【问题标题】:How to grab all frames from an avi file - how to modify MS Sample Grabber sample如何从 avi 文件中抓取所有帧 - 如何修改 MS Sample Grabber 示例
【发布时间】:2019-09-27 14:42:15
【问题描述】:

我已经根据这个 MS 链接创建了一个示例:

https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber

代码如下所示。

但代码只抓取一帧。我认为视频中的第一帧但我想抓住视频文件中可用的每一帧。我该怎么做?



    /*
    for this sample to work you have to have 
    "C:\\temp\\FlickAnimation.avi"

    and it will output the first frame to grab1.bmp

    work out how to do all frames.

    qedit.h from here:
    https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/2ab5c212-5824-419d-b5d9-7f5db82f57cd/qedith-missing-in-current-windows-sdk-v70?forum=windowsdirectshowdevelopment

    dshowutil.h from here:
    https://raw.githubusercontent.com/microsoft/Windows-classic-samples/master/Samples/Win7Samples/multimedia/directshow/common/dshowutil.h

    */


    #include <windows.h>
    #include <dshow.h>  // DirectShow main header
    #include "qedit.h"  // from Microsoft

    #include <strmif.h> // for IMediaSample
    #include <combaseapi.h>  // IID_PPV_ARGS

    #include "dshowutil.h"  // from Microsoft

    #pragma comment(lib, "strmiids.lib")
    #pragma comment(lib, "dxguid.lib")

    template <class T> void SafeRelease(T **ppT)
    {
        if (*ppT)
        {
            (*ppT)->Release();
            *ppT = NULL;
        }
    }


    HRESULT WriteBitmap(PCWSTR, BITMAPINFOHEADER*, size_t, BYTE*, size_t);

    HRESULT GrabVideoBitmap(PCWSTR pszVideoFile, PCWSTR pszBitmapFile)
    {
        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;

        BYTE *pBuffer = NULL;


        HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGraph->QueryInterface(IID_PPV_ARGS(&pEvent));
        if (FAILED(hr))
        {
            goto done;
        }

        // Create the Sample Grabber filter.
        hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
            IID_PPV_ARGS(&pGrabberF));
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGrabberF->QueryInterface(IID_PPV_ARGS(&pGrabber));
        if (FAILED(hr))
        {
            goto done;
        }

        AM_MEDIA_TYPE mt;
        ZeroMemory(&mt, sizeof(mt));
        mt.majortype = MEDIATYPE_Video;
        mt.subtype = MEDIASUBTYPE_RGB24;

        hr = pGrabber->SetMediaType(&mt);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGraph->AddSourceFilter(pszVideoFile, L"Source", &pSourceF);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pSourceF->EnumPins(&pEnum);
        if (FAILED(hr))
        {
            goto done;
        }

        while (S_OK == pEnum->Next(1, &pPin, NULL))
        {
            hr = ConnectFilters(pGraph, pPin, pGrabberF);
            SafeRelease(&pPin);
            if (SUCCEEDED(hr))
            {
                break;
            }
        }

        if (FAILED(hr))
        {
            goto done;
        }

        hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
            IID_PPV_ARGS(&pNullF));
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGraph->AddFilter(pNullF, L"Null Filter");
        if (FAILED(hr))
        {
            goto done;
        }

        hr = ConnectFilters(pGraph, pGrabberF, pNullF);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGrabber->SetOneShot(FALSE); // TRUE);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGrabber->SetBufferSamples(TRUE);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pControl->Run();
        if (FAILED(hr))
        {
            goto done;
        }

        long evCode;
        hr = pEvent->WaitForCompletion(INFINITE, &evCode);

        // Find the required buffer size.
        long cbBuffer;
        hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);
        if (FAILED(hr))
        {
            goto done;
        }

        pBuffer = (BYTE*)CoTaskMemAlloc(cbBuffer);
        if (!pBuffer)
        {
            hr = E_OUTOFMEMORY;
            goto done;
        }

        hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pGrabber->GetConnectedMediaType(&mt);
        if (FAILED(hr))
        {
            goto done;
        }

        // Examine the format block.
        if ((mt.formattype == FORMAT_VideoInfo) &&
            (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
            (mt.pbFormat != NULL))
        {
            VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)mt.pbFormat;

            hr = WriteBitmap(pszBitmapFile, &pVih->bmiHeader,
                mt.cbFormat - SIZE_PREHEADER, pBuffer, cbBuffer);
        }
        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;
    };

    // Writes a bitmap file
    //  pszFileName:  Output file name.
    //  pBMI:         Bitmap format information (including pallete).
    //  cbBMI:        Size of the BITMAPINFOHEADER, including palette, if present.
    //  pData:        Pointer to the bitmap bits.
    //  cbData        Size of the bitmap, in bytes.

    HRESULT WriteBitmap(PCWSTR pszFileName, BITMAPINFOHEADER *pBMI, size_t cbBMI,
        BYTE *pData, size_t cbData)
    {
        HANDLE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL,
            CREATE_ALWAYS, 0, NULL);
        if (hFile == NULL)
        {
            return HRESULT_FROM_WIN32(GetLastError());
        }

        BITMAPFILEHEADER bmf = {};

        bmf.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"  
        bmf.bfSize = cbBMI + cbData + sizeof(bmf);
        bmf.bfOffBits = sizeof(bmf) + cbBMI;

        DWORD cbWritten = 0;
        BOOL result = WriteFile(hFile, &bmf, sizeof(bmf), &cbWritten, NULL);
        if (result)
        {
            result = WriteFile(hFile, pBMI, cbBMI, &cbWritten, NULL);
        }
        if (result)
        {
            result = WriteFile(hFile, pData, cbData, &cbWritten, NULL);
        }

        HRESULT hr = result ? S_OK : HRESULT_FROM_WIN32(GetLastError());

        CloseHandle(hFile);

        return hr;
    }

    int main() {

        // Initialize the COM library.
        HRESULT hr = CoInitialize(NULL);
        if (FAILED(hr))
        {
            printf("ERROR - Could not initialize COM library");
            return 1;
        }

        GrabVideoBitmap(L"C:\\temp\\FlickAnimation.avi", L"grab1.bmp");

        CoUninitialize();
    }

【问题讨论】:

    标签: c++ windows video directshow


    【解决方案1】:

    解决方案背后的想法:

    尝试opening the video 和OpenCV,然后使用它的辅助函数逐帧读取,保存frame to images.

    代码示例:

    #include "opencv2/opencv.hpp"
    #include <iostream>
    
    using namespace std;
    using namespace cv;
    
    int main(){
    
      // Create a VideoCapture object and open the input file
      // If the input is the web camera, pass 0 instead of the video file name
      VideoCapture cap("chaplin.mp4"); 
    
      // Check if camera opened successfully
      if(!cap.isOpened()){
        cout << "Error opening video stream or file" << endl;
        return -1;
      }
    
      int counter = 0;
    
      while(1){
    
        Mat frame;
        // Capture frame-by-frame
        cap >> frame;
    
        // If the frame is empty, break immediately
        if (frame.empty())
          break;
    
        // Display the resulting frame
        //imshow( "Frame", frame );
    
        //Save the resulting frame
        imwrite( "FilePathAndName" + std::to_string( counter ), frame );
        counter++;
    
        // Press  ESC on keyboard to exit
        char c=(char)waitKey(25);
        if(c==27)
          break;
      }
    
      // When everything done, release the video capture object
      cap.release();
    
      // Closes all the frames
      destroyAllWindows();
    
      return 0;
    }
    

    希望这会有所帮助! ;)

    【讨论】:

    • 我确实看过 opencv,但不想要庞大库的开销。我希望直接使用 Windows api 来实现这个目标。
    猜你喜欢
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2016-08-16
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多