c++ - ISampleGrabber::GetCurrentBuffer() 返回 E_OUTOFMEMORY

标签 c++ windows directshow samplegrabber

我是 directshow 的新手,正在使用 DirectShow 示例“FrameGrabberDemo”,但在获取图像时遇到了问题。我尝试使用 .avi 和 .mpg,两者都给出了同样的问题。

第一个问题可能是 IMediaControl::Run() 的 S_FALSE 返回值。但是,这不是错误,它指出:

The graph is preparing to run, but some filters have not completed the transition to a running state.

第二个观察是 ISampleGrabber::GetCurrentBuffer() 返回 E_OUTOFMEMORY 代码,它指出“指定的缓冲区不够大”。但是,BitmapInfo 的 biImageSize = 1244160 并且 MediaType 的 ISampleSize = 1244160。

HRESULT CFrameGrabberDemoDlg::DoExtractFrame()
{
WCHAR wFile[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, m_FilePath, -1, wFile, MAX_PATH );

// Create the graph builder
CComPtr<IGraphBuilder> pGraphBuilder;
HRESULT hr = ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                                IID_IGraphBuilder, (void**)&pGraphBuilder);
if (FAILED(hr))
    return hr;
ASSERT(pGraphBuilder != NULL);

// Create the "Grabber filter"
CComPtr<IBaseFilter>    pGrabberBaseFilter;
CComPtr<ISampleGrabber> pSampleGrabber;
AM_MEDIA_TYPE   mt;
hr = ::CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, 
                        IID_IBaseFilter, (LPVOID *)&pGrabberBaseFilter);
if (FAILED(hr))
    return hr;
pGrabberBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
if (pSampleGrabber == NULL)
    return E_NOINTERFACE;
hr = pGraphBuilder->AddFilter(pGrabberBaseFilter,L"Grabber");
if (FAILED(hr))
    return hr;

ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
mt.formattype = FORMAT_VideoInfo; 
hr = pSampleGrabber->SetMediaType(&mt);        
if (FAILED(hr))
    return hr;
hr = pGraphBuilder->RenderFile(wFile,NULL);
if (FAILED(hr))
    return hr;

CComPtr<IMediaControl> pMediaControl;
CComPtr<IMediaEvent> pMediaEventEx;
// QueryInterface for some basic interfaces
pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&pMediaEventEx);

if (pMediaControl == NULL || pMediaEventEx == NULL)
    return E_NOINTERFACE;

// Set up one-shot mode.
hr = pSampleGrabber->SetBufferSamples(TRUE);
if (FAILED(hr))
    return hr;

hr = pSampleGrabber->SetOneShot(TRUE);
if (FAILED(hr))
    return hr;

CComQIPtr<IMediaSeeking> pSeek = pMediaControl;
if (pSeek == NULL)
    return E_NOINTERFACE;
LONGLONG Duration;
hr = pSeek->GetDuration(&Duration);
if (FAILED(hr))
    return hr;
int NumSecs = int(Duration/10000000);

REFERENCE_TIME rtStart = 1 * 10000000;
if (NumSecs < 1)
    rtStart = 0;
REFERENCE_TIME rtStop = rtStart; 

hr = pSeek->SetPositions(&rtStart, AM_SEEKING_AbsolutePositioning, 
                         &rtStop, AM_SEEKING_AbsolutePositioning);
if (FAILED(hr))
    return hr;

CComQIPtr<IVideoWindow> pVideoWindow = pGraphBuilder;

hr = pVideoWindow->put_AutoShow(OAFALSE);
if (FAILED(hr))
    return hr;

// Run the graph and wait for completion.
hr = pMediaControl->Run();
if (FAILED(hr))
    return hr;

long evCode;
hr = pMediaEventEx->WaitForCompletion(INFINITE, &evCode);
if (FAILED(hr))
    return hr;

AM_MEDIA_TYPE MediaType;
ZeroMemory(&MediaType,sizeof(MediaType));
hr = pSampleGrabber->GetConnectedMediaType(&MediaType); 
if (FAILED(hr))
    return hr;

// Get a pointer to the video header.
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)MediaType.pbFormat;
if (pVideoHeader == NULL)
    return E_FAIL;

// The video header contains the bitmap information. 
// Copy it into a BITMAPINFO structure.
BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BitmapInfo));
CopyMemory(&BitmapInfo.bmiHeader, &(pVideoHeader->bmiHeader), sizeof(BITMAPINFOHEADER));

// Create a DIB from the bitmap header, and get a pointer to the buffer.
void *buffer = NULL;
HBITMAP hBitmap = ::CreateDIBSection(0, &BitmapInfo, DIB_RGB_COLORS, &buffer, NULL, 0);
GdiFlush(); 

// Copy the image into the buffer.
long size = 0;
hr = pSampleGrabber->GetCurrentBuffer(&size, (long *)buffer);
if (FAILED(hr))
    return hr;

long Width = pVideoHeader->bmiHeader.biWidth;
long Height = pVideoHeader->bmiHeader.biHeight;

HBITMAP hOldBitmap = m_Image.SetBitmap(hBitmap);
if (hOldBitmap != NULL)
    ::DeleteObject(hOldBitmap);

return S_OK;
}

::CreateDIBSection 也没有返回 NULL,缓冲区也被初始化。

如何解决?

最佳答案

您正在请求将数据放入零长度缓冲区:

long size = 0;
hr = pSampleGrabber->GetCurrentBuffer(&size, (long *)buffer);

错误代码看起来很相关:

If pBuffer is not NULL, set this parameter equal to the size of the buffer, in bytes.

E_OUTOFMEMORY The specified buffer is not large enough.

您只需要在相关调用中使用适当的参数(适当的缓冲区长度)。

关于c++ - ISampleGrabber::GetCurrentBuffer() 返回 E_OUTOFMEMORY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26092185/

相关文章:

c++ - 从 .c 文件中定义的 .cpp 文件调用的函数

c# - 如何将 ISampleGrabber::BufferCB 的缓冲区转换为位图

c++ - 如何传递参数并将标准输入从文件重定向到在 gdb 中运行的程序?

c++ - 函数后的 const 如何优化程序?

c++ - 如何与 PlaySound 同时执行其他功能?

c# - 目录存在在桌面与服务器上产生不一致的结果

linux - "type"命令在 Git Bash 上未按预期工作

c++ - Filtergraph 在第一次数据通过后停止

c++ - 获取视频文件的原始视频分辨率

c++ - QRegexp 未识别 "\n"