使用 YUV2 或 MPEG 格式在 directshow 上不起作用

问题描述 投票:0回答:1

我正在使用下面的程序使用样本采集器从视频流中捕获帧。当我使用 MEDIASUBTYPE_RGB32 时,图像会显示并且我可以打开它们。但是,当我使用 MEDIASUBTYPE_YUV2 或 MEDIASUBTYPE_MJPG 时,保存的图像无法打开(照片应用程序说不支持此格式)。

我尝试使用 SetFormat 和 pSampleGrabber->SetMediaType(&mt) 设置所需的格式类型。我期待样本采集器保存图像,然后我可以查看这些图像。

有人可以解释一下如何让它与其他格式一起使用吗?我也不明白为什么 RGB32 可以工作,而相机甚至没有报告支持它。它仅报告支持 MJPG 和 YUV2。


    #include <dshow.h>
    #include <iostream>
    #include <time.h>
    
    EXTERN_C const CLSID CLSID_NullRenderer;
    EXTERN_C const CLSID CLSID_SampleGrabber;
    
    static
    const
    IID IID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce, { 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } };
    
    class __declspec(uuid("{C1F400A0-3F08-11D3-9F0B-006008039E37}")) SampleGrabber;
    
    #pragma region SampleGrabber
    
    struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
    ISampleGrabberCB : IUnknown
    {
        //
        // Raw methods provided by interface
        //
    
          virtual HRESULT __stdcall SampleCB (
            double SampleTime,
            struct IMediaSample * pSample ) = 0;
          virtual HRESULT __stdcall BufferCB (
            double SampleTime,
            unsigned char * pBuffer,
            long BufferLen ) = 0;
    };
    
    struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
    ISampleGrabber : IUnknown
    {
        //
        // Raw methods provided by interface
        //
    
          virtual HRESULT __stdcall SetOneShot (
            long OneShot ) = 0;
          virtual HRESULT __stdcall SetMediaType (
            struct _AMMediaType * pType ) = 0;
          virtual HRESULT __stdcall GetConnectedMediaType (
            struct _AMMediaType * pType ) = 0;
          virtual HRESULT __stdcall SetBufferSamples (
            long BufferThem ) = 0;
          virtual HRESULT __stdcall GetCurrentBuffer (
            /*[in,out]*/ long * pBufferSize,
            /*[out]*/ long * pBuffer ) = 0;
          virtual HRESULT __stdcall GetCurrentSample (
            /*[out,retval]*/ struct IMediaSample * * ppSample ) = 0;
          virtual HRESULT __stdcall SetCallback (
            struct ISampleGrabberCB * pCallback,
            long WhichMethodToCallback ) = 0;
    };
    
    struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37"))
    SampleGrabber;
        // [ default ] interface ISampleGrabber
    
    #pragma endregion
    
    // DirectShow objects
    HRESULT hr;
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    IMoniker *pMoniker = NULL;
    IPropertyBag *pPropBag = NULL;
    IGraphBuilder *pGraph = NULL;
    ICaptureGraphBuilder2 *pBuilder = NULL;
    IBaseFilter *pCap = NULL;
    IBaseFilter *pSampleGrabberFilter = NULL;
    IBaseFilter *pSampleGrabberStillFilter = NULL;
    
    ISampleGrabber *pSampleGrabber = NULL;
    ISampleGrabber *pSampleGrabberStill = NULL;
    IBaseFilter *pNullRenderer = NULL;
    IBaseFilter *pNullRendererStill = NULL;
    IMediaControl *pMediaControl = NULL;
    IAMVideoControl *pAMVidControl = NULL;
    IAMCameraControl *pAMVCamControl = NULL;
    
    int img_index_curr = 0;
    int img_index_prev = 0;
    
    AM_MEDIA_TYPE g_VideoMediaType;
    AM_MEDIA_TYPE *pmtConfig;
    // Find the still pin.
    IPin *pPin = NULL;
    char *pBuffer = NULL;
    
    void exit_message(const char* error_message, int error)
    {
        // Print an error message
        fprintf(stderr, error_message);
        fprintf(stderr, "\n");
        
        // Clean up DirectShow / COM stuff
        if (pBuffer != NULL) delete[] pBuffer;
        if (pMediaControl != NULL) pMediaControl->Release();    
        if (pNullRenderer != NULL) pNullRenderer->Release();
        if (pNullRendererStill != NULL) pNullRendererStill->Release();
        if (pSampleGrabber != NULL) pSampleGrabber->Release();
        if (pSampleGrabberStill != NULL) pSampleGrabberStill->Release();
        if (pSampleGrabberFilter != NULL) pSampleGrabberFilter->Release();
        if (pSampleGrabberStillFilter != NULL) pSampleGrabberStillFilter->Release();
        if (pCap != NULL) pCap->Release();
        if (pBuilder != NULL) pBuilder->Release();
        if (pGraph != NULL) pGraph->Release();
        if (pPropBag != NULL) pPropBag->Release();
        if (pMoniker != NULL) pMoniker->Release();
        if (pEnum != NULL) pEnum->Release();
        if (pDevEnum != NULL) pDevEnum->Release();
        if (pPin != NULL) pPin->Release();
        if (pAMVidControl != NULL) pAMVidControl->Release();
        if (pAMVCamControl != NULL) pAMVCamControl->Release();
    
        CoUninitialize();
        
        // Exit the program
        exit(error);
    }
    
    
    class SampleGrabberCallback : public ISampleGrabberCB
    {
    public:
        // Fake referance counting.
        STDMETHODIMP_(ULONG) AddRef() { return 1; }
        STDMETHODIMP_(ULONG) Release() { return 2; }
        char filename[100];
    
        STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
        {
            if (NULL == ppvObject) return E_POINTER;
            if (riid == __uuidof(IUnknown))
            {
                *ppvObject = static_cast<IUnknown*>(this);
                 return S_OK;
            }
            if (riid == __uuidof(ISampleGrabberCB))
            {
                *ppvObject = static_cast<ISampleGrabberCB*>(this);
                 return S_OK;
            }
            return E_NOTIMPL;
        }
    
        STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
        {
            fprintf(stderr, "Callback triggered SampleCB\n");
            return E_NOTIMPL;
        }
    
        STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)
        {
            if ((g_VideoMediaType.majortype != MEDIATYPE_Video) ||
                (g_VideoMediaType.formattype != FORMAT_VideoInfo) ||
                (g_VideoMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) ||
                (g_VideoMediaType.pbFormat == NULL) ||
                (g_VideoMediaType.subtype != MEDIASUBTYPE_MJPG)
                )
            {
                fprintf(stderr, "Invalid Format\n");
                return VFW_E_INVALIDMEDIATYPE;
            }
            //fprintf(stderr, "Save file\n");
            sprintf(filename, "video/Image_Video_%d.bmp", img_index_curr);
            img_index_curr++;
            HANDLE hf = CreateFile(filename, GENERIC_WRITE, 
            FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
            if (hf == INVALID_HANDLE_VALUE)
            {
                return E_FAIL;
            }
            long cbBitmapInfoSize = g_VideoMediaType.cbFormat - SIZE_PREHEADER;
            VIDEOINFOHEADER *pVideoHeader =
               (VIDEOINFOHEADER*)g_VideoMediaType.pbFormat;
    
            BITMAPFILEHEADER bfh;
            ZeroMemory(&bfh, sizeof(bfh));
            bfh.bfType = 'MB';  // Little-endian for "BM".
            bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
            bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
            
            // Write the file header.
            DWORD dwWritten = 0;
            WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
            WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);        
            WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
            CloseHandle( hf );
            return S_OK;
    
        }
    };
    
    // Global instance of the class.
    SampleGrabberCallback g_VideoCapCB;
    
    int main(int argc, char **argv)
    {
        // Capture settings
        int show_preview_window = 0;
        int device_number = 2;
        char device_name[100];
        
        // Other variables
        char char_buffer[100];
    
        // Parse command line arguments. Available options:
        //      /preview
    
        int n = 1;
        while (n < argc)
        {
            // Process next command line argument
            if (strcmp(argv[n], "/preview") == 0)
            {
                // Enable preview window
                show_preview_window = 1;
            }
            else
            {
                // Unknown command line argument
                fprintf(stderr, "Unrecognised option: %s\n", argv[n]);
                exit_message("", 1);            
            }
            
            // Increment command line argument counter
            n++;
        }
        
        // Intialise COM
        hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if (hr != S_OK)
            exit_message("Could not initialise COM", 1);
    
        // Create filter graph
        hr = CoCreateInstance(CLSID_FilterGraph, NULL,
                CLSCTX_INPROC_SERVER, IID_IGraphBuilder,
                (void**)&pGraph);
        if (hr != S_OK)
            exit_message("Could not create filter graph", 1);
        
        // Create capture graph builder.
        hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
                CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
                (void **)&pBuilder);
        if (hr != S_OK)
            exit_message("Could not create capture graph builder", 1);
    
        // Attach capture graph builder to graph
        hr = pBuilder->SetFiltergraph(pGraph);
        if (hr != S_OK)
            exit_message("Could not attach capture graph builder to graph", 1);
    
        // Create system device enumerator
        hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
                CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));
        if (hr != S_OK)
            exit_message("Could not crerate system device enumerator", 1);
    
        // Video input device enumerator
        hr = pDevEnum->CreateClassEnumerator(
                        CLSID_VideoInputDeviceCategory, &pEnum, 0);
        if (hr != S_OK)
            exit_message("No video devices found", 1);
        
        
        // Get moniker for specified video input device,
        // or for the first device if no device number
        // was specified.
        VARIANT var;
        n = 0;
        while(1)
        {
            // Access next device
            hr = pEnum->Next(1, &pMoniker, NULL);
            if (hr == S_OK)
            {
                n++; // increment device count
            }
            else
            {
                if (device_number == 0)
                {
                    fprintf(stderr,
                        "Video capture device %s not found\n",
                        device_name);
                }
                else
                {
                    fprintf(stderr,
                        "Video capture device %d not found\n",
                        device_number);
                }
                exit_message("", 1);
            }
    
            if (n >= device_number)
            {
                break;
            }
        }
        
        // Get video input device name
        hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
        VariantInit(&var);
        hr = pPropBag->Read(L"FriendlyName", &var, 0);
        fprintf(stderr, "Capture device: %ls\n", var.bstrVal);
        VariantClear(&var);
        
        // Create capture filter and add to graph
        hr = pMoniker->BindToObject(0, 0,
                        IID_IBaseFilter, (void**)&pCap);
        if (hr != S_OK) exit_message("Could not create capture filter", 1);
        
        // Add capture filter to graph
        hr = pGraph->AddFilter(pCap, L"Capture Filter");
        if (hr != S_OK) exit_message("Could not add capture filter to graph", 1);
    
    
        // Create sample grabber filter
        hr = CoCreateInstance(CLSID_SampleGrabber, NULL,
            CLSCTX_INPROC_SERVER, IID_IBaseFilter,
            (void**)&pSampleGrabberFilter);
        if (hr != S_OK)
            exit_message("Could not create Sample Grabber filter", 1);
        
        // Query the ISampleGrabber interface of the sample grabber filter
        hr = pSampleGrabberFilter->QueryInterface(
                IID_ISampleGrabber, (void**)&pSampleGrabber);
        if (hr != S_OK)
            exit_message("Could not get ISampleGrabber interface to sample grabber filter", 1);
        
        // Enable sample buffering in the sample grabber filter
        hr = pSampleGrabber->SetBufferSamples(TRUE);
        if (hr != S_OK)
            exit_message("Could not enable sample buffering in the sample grabber", 1);
    
        
        hr = pSampleGrabber->SetCallback(&g_VideoCapCB, 1); 
        if (hr != S_OK)
        exit_message("Could not set sample grabber callback", 1);
    
        fprintf(stderr, "Here");
    
        AM_MEDIA_TYPE mt;
        ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
        mt.majortype = MEDIATYPE_Video;
        mt.subtype = MEDIASUBTYPE_MJPG;
    
        // Set media type in sample grabber filter
        hr = pSampleGrabber->SetMediaType(&mt);
        if (hr != S_OK)
            exit_message("Could not set media type in sample grabber", 1);
        
        
        // Add sample grabber filter to filter graph
        hr = pGraph->AddFilter(pSampleGrabberFilter, L"SampleGrab");
        if (hr != S_OK)
            exit_message("Could not add Sample Grabber to filter graph", 1);
    
        // Create Null Renderer filter
        hr = CoCreateInstance(CLSID_NullRenderer, NULL,
            CLSCTX_INPROC_SERVER, IID_IBaseFilter,
            (void**)&pNullRenderer);
        if (hr != S_OK)
            exit_message("Could not create Null Renderer filter", 1);
        
        // Add Null Renderer filter to filter graph
        hr = pGraph->AddFilter(pNullRenderer, L"NullRender");
        if (hr != S_OK)
            exit_message("Could not add Null Renderer to filter graph", 1);
    
            // Get pointer to IAMStreamConfig
        IAMStreamConfig *pConfig = NULL;
        hr = pBuilder->FindInterface(
        &PIN_CATEGORY_CAPTURE, // Preview pin.
        0,    // Any media type.
        pCap, // Pointer to the capture filter.
        IID_IAMStreamConfig, (void**)&pConfig);
    
        if (hr != S_OK)
            exit_message("Could not find IAMStreamConfig", 1);
    
        int iCount = 0,iSize = 0;
        hr = pConfig->GetNumberOfCapabilities(&iCount,&iSize);
        if(iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
        {
            for(int iFormat = 0;iFormat < iCount;iFormat++)
            {
                fprintf(stderr, "iFormat: %d\n", iFormat);
                VIDEO_STREAM_CONFIG_CAPS scc;
                
                hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
                if(hr == S_OK)
                {
                    fprintf(stderr, "Looking for Format\n");
                    VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
                    fprintf(stderr, "Width = %d , Height = %d \n", pVih->bmiHeader.biWidth, pVih->bmiHeader.biHeight);
    
                    OLECHAR* guidString;
                    StringFromCLSID(pmtConfig->subtype, &guidString);
                    fprintf(stderr, "Media Type = %ls\n", guidString);
    
                    // Without breaking the below statement MJPG is selected otherwise YUV2 is
                    // I am not explicity looking as I cannot find RGB32 in this list which is the only one this works with.
                    if(pVih->bmiHeader.biWidth == 1920 && pVih->bmiHeader.biHeight == 1080)
                    {
                        fprintf(stderr, "Set Format -----------------------\n");
                        hr = pConfig->SetFormat(pmtConfig);
                        if (hr != S_OK)
                        exit_message("Could not set format Directly", 1);
                        
                    }
                }
                else
                {
                    fprintf(stderr, "Could not get streams cap\n");
    
                }
            }
        }
    
        fprintf(stderr, "------------------------\n\n");
        
        // Connect up the filter graph's capture stream
        hr = pBuilder->RenderStream(
            &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
            pCap,  pSampleGrabberFilter, pNullRenderer);
        if (hr != S_OK)
            exit_message("Could not render capture video stream", 1);
    
            
        // Connect up the filter graph's preview stream
        if (show_preview_window > 0)
        {
            hr = pBuilder->RenderStream(
                    &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
                    pCap, NULL, NULL);
            if (hr != S_OK && hr != VFW_S_NOPREVIEWPIN)
                exit_message("Could not render preview video stream", 1);
        }
        
    
        // Get media control interfaces to graph builder object
        hr = pGraph->QueryInterface(IID_IMediaControl,
                        (void**)&pMediaControl);
        if (hr != S_OK) exit_message("Could not get media control interface", 1);
    
        // Run graph
        while(1)
        {
            hr = pMediaControl->Run();
            
            // Hopefully, the return value was S_OK or S_FALSE
            if (hr == S_OK) break; // graph is now running
            if (hr == S_FALSE) continue; // graph still preparing to run
            
            // If the Run function returned something else,
            // there must be a problem
            fprintf(stderr, "Error: %u\n", hr);
            exit_message("Could not run filter graph", 1);
        }
    
        // Query the capture filter for IAMVideoControl
        hr = pCap->QueryInterface(IID_IAMVideoControl, (void**)&pAMVidControl);
        if (hr != S_OK) exit_message("Could not get IAMVideoControl", 1);
    
        // Query the capture filter for IAMCameraControl
        hr = pCap->QueryInterface(IID_IAMCameraControl, (void**)&pAMVCamControl);
        if (hr != S_OK) exit_message("Could not get IAMCameraControl", 1);
    
        long Min, Max, Step, Default, Flags, Val;
    
        // Get the range and default value. 
        hr = pAMVCamControl->GetRange(CameraControl_Exposure, &Min, &Max, &Step,
            &Default, &Flags);
    
            
        // Set Default exposure
        hr = pAMVCamControl->Set(CameraControl_Exposure, 1, CameraControl_Flags_Manual);
        if (hr != S_OK) exit_message("Could not set exposure", 1);
    
        hr = pAMVCamControl->Get(CameraControl_Exposure, &Val, &Flags);
        if (hr != S_OK) exit_message("Could not get current camera exposure", 1);
    
        // Get the media type from the video grabber filter
        hr = pSampleGrabber->GetConnectedMediaType(
                &g_VideoMediaType);
        if (hr != S_OK) exit_message("Could not get media type", 1);
    
        int count = 0;
    
        clock_t begin = clock();
    
        // Loop to change exposure and capture still image
        while(true)
        {  
            if(img_index_curr > img_index_prev)
            {
                clock_t end = clock();
                double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
                fprintf(stderr, "Image = %d, Time = %f, \n", img_index_curr, time_spent);
                
                if(img_index_curr == 20)
                {
                    break;
                }
    
                if(img_index_curr == 10)
                {
                    fprintf(stderr, "Set New expo\n");
                    Val = -10;
                    Flags = CameraControl_Flags_Manual;
                    hr = pAMVCamControl->Set(CameraControl_Exposure, Val, Flags);
                    
                    clock_t set_exposure_time = clock();
                    double time_spent_expo = (double)(set_exposure_time - begin) / CLOCKS_PER_SEC;
                    fprintf(stderr, "Expo set Time = %f, \n", time_spent_expo);
    
    
    
                    if (hr != S_OK) exit_message("Could not set exposure", 1);
                }
                count++;
    
                hr = pAMVCamControl->Get(CameraControl_Exposure, &Val, &Flags);
                if (hr != S_OK) exit_message("Could not get exposure", 1);
    
                fprintf(stderr, "Expo Val: %ld\n", Val);
                fprintf(stderr, "Expo Flags: %ld\n", Flags);
                img_index_prev = img_index_curr;
    
                fprintf(stderr, "\n");
            }
            //Sleep(500);
        }
    
        pPin->Release();
        // Stop the graph
        pMediaControl->Stop();
    
        // Clean up and exit
        exit_message("", 0);    
    }

c++ winapi directshow samplegrabber
1个回答
0
投票

您保存到 Windows 位图

.bmp
文件,这种图像格式通常不假定 YUY 或 MJPG 内容。好吧,从技术上来说,将此类数据推送到那里可能是有意义的,但您将很难找到能够识别该格式的应用程序。

您应该能够将 MJPG 内容按原样保存到

.jpg
文件(即不添加位图标题)。

据我所知,没有众所周知的格式来保存 YUY2 数据以便立即查看。您需要转换或制作自己的查看器等。

© www.soinside.com 2019 - 2024. All rights reserved.