在c++中使用directshow过滤器从视频中捕获一帧
Capture a frame from video using directshow filters in C++
我从网上获取了一段代码,从视频文件中捕获一帧,并修改为捕获所有帧并将其存储为bmp图像。
HRESULT GrabVideoBitmap(PCWSTR pszVideoFile)
{
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEventEx *pEvent = NULL;
IBaseFilter *pGrabberF = NULL;
ISampleGrabber *pGrabber = NULL;
IBaseFilter *pSourceF = NULL;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
IBaseFilter *pNullF = NULL;
long evCode;
wchar_t temp[10];
wchar_t framename[50] = IMAGE_FILE_PATH; // L"D:\sampleframe";
BYTE *pBuffer = NULL;
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
return 0;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pGraph));
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
// Create the Sample Grabber filter.
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pGrabberF));
hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
// Displays the metadata of the file
DisplayFileInfo((wchar_t*)pszVideoFile); // to display video information
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(mt));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pGrabber->SetMediaType(&mt);
hr = pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF);
hr = pSourceF->EnumPins(&pEnum);
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
hr = ConnectFilters(pGraph, pPin, pGrabberF);
SafeRelease(&pPin);
if (SUCCEEDED(hr))
{
break;
}
}
hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pNullF));
hr = pGraph->AddFilter(pNullF, L"Null Filter");
hr = ConnectFilters(pGraph, pGrabberF, pNullF);
hr = pGrabber->SetOneShot(TRUE);
hr = pGrabber->SetBufferSamples(TRUE);
hr = pControl->Run();
hr = pEvent->WaitForCompletion(INFINITE, &evCode);
for (int i = 0; i < 10; i++)
{
// Find the required buffer size.
long cbBuffer;
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
hr = pGrabber->GetConnectedMediaType(&mt);
// Examine the format block.
if ((mt.formattype == FORMAT_VideoInfo) &&
(mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
(mt.pbFormat != NULL))
{
swprintf(temp, 5, L"%d", i);
wcscat_s(framename, temp);
wcscat_s(framename, L".bmp");
VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;
hr = WriteBitmap((PCWSTR)framename, &pVih->bmiHeader,
mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
wcscpy_s(framename, IMAGE_FILE_PATH);
}
else
{
// Invalid format.
hr = VFW_E_INVALIDMEDIATYPE;
}
FreeMediaType(mt);
}
done:
CoTaskMemFree(pBuffer);
SafeRelease(&pPin);
SafeRelease(&pEnum);
SafeRelease(&pNullF);
SafeRelease(&pSourceF);
SafeRelease(&pGrabber);
SafeRelease(&pGrabberF);
SafeRelease(&pControl);
SafeRelease(&pEvent);
SafeRelease(&pGraph);
return hr;
}
输入的视频文件有132帧。但是只生成了68张图像。最后38张图像的最后一帧视频也被捕获。
我认为directshow图形正在连续运行,而WriteBitmap()缺少帧。
如何在directX中获得控件捕获一帧并将其写入bmp文件并捕获下一帧,从而捕获所有帧为bmp图像
谢谢阿伦
你的方法不对。目前,您将样本采集器设置为一次拍摄,然后等待图形完成。这种方式只适用于捕获单个帧。您需要在pGrabber的ISampleGrabberCB回调中捕获帧。你需要实现ISampleGrabberCB接口,并在你的pGrabber过滤器上使用ISampleGrabber::SetCallback将其指向你的实现。之后,您可以在SampleCB或BufferCB方法中捕获帧。http://www.infognition.com/blog/2013/accessing_raw_video_in_directshow.html
相关文章:
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 如何检测是否在缓冲绘画动画中绘制最后一帧?
- C++ 尝试优化每一帧将数据打印到二进制文件
- 当我在每一帧中多次使用正则表达式时,FPS 下降了
- 为什么除了最后一帧之外,每一帧都没有调用命令
- WinApi 在每一帧中绘制
- Opencv 视频帧.我只能看到最后一帧
- 访问视频的每一帧并对其进行处理
- Qt:显示实时视频,一次一帧
- Haar检测-保存图像的Mat,以便获得并显示前一帧
- OpenCV - 如何在局域网中的单独主机中处理视频的每一帧
- 在Qt/QML中的每一帧更新图像时运行时崩溃
- 设置GL_TEXTURE_MAX_ANISOTROPY_EXT会导致下一帧崩溃
- 在计算了一帧的SIFT或ORB之后,如何实时跟踪视频中的对象
- gstreamermm:如何提取 Gst::P layBin 的最后一帧视频
- 如何在 C++ 中保留 OpenCV 中的最后一帧
- 如何找到一帧中物体质心与相邻帧之间的欧氏距离
- Opencv VideoWriter只保存一帧
- 在c++中使用directshow过滤器从视频中捕获一帧
- 我如何使用点云库捕获一帧