Как получить все кадры из файла avi - как изменить образец MS Sample Grabber - PullRequest
0 голосов
/ 27 сентября 2019

Я создал образец на основе этой ссылки 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();
    }

1 Ответ

0 голосов
/ 27 сентября 2019

Идея, лежащая в основе решения:

Попробуйте открыть видео с помощью OpenCV , затем используйте его вспомогательные функции, чтобы читать его покадрово, сохраняя кадр к изображениям.

Пример кода:

#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;
}

Надеюсь, это поможет!;)

...