DirectShow实现USB相机预览和抓图例子(使用ICaptureGraphBuilder2)[通俗易懂]

DirectShow实现USB相机预览和抓图例子(使用ICaptureGraphBuilder2)[通俗易懂]关键概念:filterfiltergraphfiltergraphmanagerfilterinterface(COMinterface)filterPin(输入输出端子)PinProperty及PinMediaType系统设备枚举用于选择设备GraphEdit工具使用VideoCapture及ICaptureGraphBuilder2使用视频采集设备、VFW和WDM及KsProxy使用驱动自带的设置窗口控制设备及视频设置IAMStreamConfig:设置帧率、

大家好,欢迎来到IT知识分享网。

关键概念:

各种filter和COM对象都有很多接口,需要查官方文档才能知道如何使用,一定要学会查官方文档!!!

视频逐行扫描和隔行扫描:
逐行扫描:图像从左至右,从上到下输出一张完整的图片
隔行扫描:1. 一帧分为两个场来扫描;2. 两帧分为奇偶隔行扫描
两帧奇偶隔行扫描可以节省一半的带宽,但是可能会发生交错(interlaced),尤其是运动图像。
VIDEOINFOHEADER2VIDEOINFOHEADER提供了更多关于interlaced的信息。

在输出MJPG预览的设备中,中间需要插入MJPEG Decompressor Filter才能将视频渲染到显卡上,MJPEG Decompressor Filter输出标准的RGB图像。

有窗模式的视频预览及采图例子:

// previre_wnd.h
#include <afxwin.h>
#include <tchar.h>
#include <dshow.h>
#include <iostream>
#include <fstream>
using namespace std;
extern HWND hwnd;

extern IMediaControl *pControl;
extern IMediaEventEx *pEvent;

// window messages
#define WM_FGNOTIFY WM_USER + 1

int show();

void ShowFilterInfo(IBaseFilter *filter);
void ShowGUID(GUID *guid);
// preview_wnd.cpp
/** * 构建默认的usb设备视频预览 * * 编译 cl preview_app.cpp preview_wnd.cpp SaveGraphFile.cpp Strmiids.lib ole32.lib OleAut32.lib user32.lib */
#include "preview_wnd.h"

#include <afxwin.h>
#include <tchar.h>
#include <dshow.h>
#include <iostream>
using namespace std;

#include <dvdmedia.h>
#include "SaveGraphFile.h"

IMediaControl *pControl = NULL;
IMediaEventEx *pEvent = NULL;

EXTERN_C const CLSID CLSID_SampleGrabber;

#ifdef __cplusplus

class DECLSPEC_UUID("C1F400A0-3F08-11d3-9F0B-006008039E37")
    SampleGrabber;
#endif

EXTERN_C const IID IID_ISampleGrabberCB;

#if defined(__cplusplus) && !defined(CINTERFACE)

MIDL_INTERFACE("0579154A-2B53-4994-B0D0-E773148EFF85")
ISampleGrabberCB : public IUnknown
{ 
   
public:
    virtual HRESULT STDMETHODCALLTYPE SampleCB(
        double SampleTime,
        IMediaSample *pSample) = 0;

    virtual HRESULT STDMETHODCALLTYPE BufferCB(
        double SampleTime,
        BYTE *pBuffer,
        long BufferLen) = 0;
};

#else /* C style interface */

typedef struct ISampleGrabberCBVtbl
{ 
   
    BEGIN_INTERFACE

    HRESULT(STDMETHODCALLTYPE *QueryInterface)
    (
        ISampleGrabberCB *This,
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ void **ppvObject);

    ULONG(STDMETHODCALLTYPE *AddRef)
    (
        ISampleGrabberCB *This);

    ULONG(STDMETHODCALLTYPE *Release)
    (
        ISampleGrabberCB *This);

    HRESULT(STDMETHODCALLTYPE *SampleCB)
    (
        ISampleGrabberCB *This,
        double SampleTime,
        IMediaSample *pSample);

    HRESULT(STDMETHODCALLTYPE *BufferCB)
    (
        ISampleGrabberCB *This,
        double SampleTime,
        BYTE *pBuffer,
        long BufferLen);

    END_INTERFACE
} ISampleGrabberCBVtbl;

interface ISampleGrabberCB
{ 
   
    CONST_VTBL struct ISampleGrabberCBVtbl *lpVtbl;
};

#ifdef COBJMACROS

#define ISampleGrabberCB_QueryInterface(This, riid, ppvObject) \ (This)->lpVtbl->QueryInterface(This, riid, ppvObject)

#define ISampleGrabberCB_AddRef(This) \ (This)->lpVtbl->AddRef(This)

#define ISampleGrabberCB_Release(This) \ (This)->lpVtbl->Release(This)

#define ISampleGrabberCB_SampleCB(This, SampleTime, pSample) \ (This)->lpVtbl->SampleCB(This, SampleTime, pSample)

#define ISampleGrabberCB_BufferCB(This, SampleTime, pBuffer, BufferLen) \ (This)->lpVtbl->BufferCB(This, SampleTime, pBuffer, BufferLen)

#endif /* COBJMACROS */

#endif /* C style interface */

#ifndef __ISampleGrabber_INTERFACE_DEFINED__
#define __ISampleGrabber_INTERFACE_DEFINED__

/* interface ISampleGrabber */
/* [unique][helpstring][local][uuid][object] */

EXTERN_C const IID IID_ISampleGrabber;

#if defined(__cplusplus) && !defined(CINTERFACE)

MIDL_INTERFACE("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")
ISampleGrabber : public IUnknown
{ 
   
public:
    virtual HRESULT STDMETHODCALLTYPE SetOneShot(
        BOOL OneShot) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetMediaType(
        const AM_MEDIA_TYPE *pType) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
        AM_MEDIA_TYPE * pType) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
        BOOL BufferThem) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
        /* [out][in] */ long *pBufferSize,
        /* [out] */ long *pBuffer) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
        /* [retval][out] */ IMediaSample * *ppSample) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetCallback(
        ISampleGrabberCB * pCallback,
        long WhichMethodToCallback) = 0;
};

#else /* C style interface */

typedef struct ISampleGrabberVtbl
{ 
   
    BEGIN_INTERFACE

    HRESULT(STDMETHODCALLTYPE *QueryInterface)
    (
        ISampleGrabber *This,
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ void **ppvObject);

    ULONG(STDMETHODCALLTYPE *AddRef)
    (
        ISampleGrabber *This);

    ULONG(STDMETHODCALLTYPE *Release)
    (
        ISampleGrabber *This);

    HRESULT(STDMETHODCALLTYPE *SetOneShot)
    (
        ISampleGrabber *This,
        BOOL OneShot);

    HRESULT(STDMETHODCALLTYPE *SetMediaType)
    (
        ISampleGrabber *This,
        const AM_MEDIA_TYPE *pType);

    HRESULT(STDMETHODCALLTYPE *GetConnectedMediaType)
    (
        ISampleGrabber *This,
        AM_MEDIA_TYPE *pType);

    HRESULT(STDMETHODCALLTYPE *SetBufferSamples)
    (
        ISampleGrabber *This,
        BOOL BufferThem);

    HRESULT(STDMETHODCALLTYPE *GetCurrentBuffer)
    (
        ISampleGrabber *This,
        /* [out][in] */ long *pBufferSize,
        /* [out] */ long *pBuffer);

    HRESULT(STDMETHODCALLTYPE *GetCurrentSample)
    (
        ISampleGrabber *This,
        /* [retval][out] */ IMediaSample **ppSample);

    HRESULT(STDMETHODCALLTYPE *SetCallback)
    (
        ISampleGrabber *This,
        ISampleGrabberCB *pCallback,
        long WhichMethodToCallback);

    END_INTERFACE
} ISampleGrabberVtbl;

interface ISampleGrabber
{ 
   
    CONST_VTBL struct ISampleGrabberVtbl *lpVtbl;
};

#ifdef COBJMACROS

#define ISampleGrabber_QueryInterface(This, riid, ppvObject) \ (This)->lpVtbl->QueryInterface(This, riid, ppvObject)

#define ISampleGrabber_AddRef(This) \ (This)->lpVtbl->AddRef(This)

#define ISampleGrabber_Release(This) \ (This)->lpVtbl->Release(This)

#define ISampleGrabber_SetOneShot(This, OneShot) \ (This)->lpVtbl->SetOneShot(This, OneShot)

#define ISampleGrabber_SetMediaType(This, pType) \ (This)->lpVtbl->SetMediaType(This, pType)

#define ISampleGrabber_GetConnectedMediaType(This, pType) \ (This)->lpVtbl->GetConnectedMediaType(This, pType)

#define ISampleGrabber_SetBufferSamples(This, BufferThem) \ (This)->lpVtbl->SetBufferSamples(This, BufferThem)

#define ISampleGrabber_GetCurrentBuffer(This, pBufferSize, pBuffer) \ (This)->lpVtbl->GetCurrentBuffer(This, pBufferSize, pBuffer)

#define ISampleGrabber_GetCurrentSample(This, ppSample) \ (This)->lpVtbl->GetCurrentSample(This, ppSample)

#define ISampleGrabber_SetCallback(This, pCallback, WhichMethodToCallback) \ (This)->lpVtbl->SetCallback(This, pCallback, WhichMethodToCallback)

#endif /* COBJMACROS */

#endif /* C style interface */

HRESULT STDMETHODCALLTYPE ISampleGrabber_SetOneShot_Proxy(
    ISampleGrabber *This,
    BOOL OneShot);

void __RPC_STUB ISampleGrabber_SetOneShot_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_SetMediaType_Proxy(
    ISampleGrabber *This,
    const AM_MEDIA_TYPE *pType);

void __RPC_STUB ISampleGrabber_SetMediaType_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_GetConnectedMediaType_Proxy(
    ISampleGrabber *This,
    AM_MEDIA_TYPE *pType);

void __RPC_STUB ISampleGrabber_GetConnectedMediaType_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_SetBufferSamples_Proxy(
    ISampleGrabber *This,
    BOOL BufferThem);

void __RPC_STUB ISampleGrabber_SetBufferSamples_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_GetCurrentBuffer_Proxy(
    ISampleGrabber *This,
    /* [out][in] */ long *pBufferSize,
    /* [out] */ long *pBuffer);

void __RPC_STUB ISampleGrabber_GetCurrentBuffer_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_GetCurrentSample_Proxy(
    ISampleGrabber *This,
    /* [retval][out] */ IMediaSample **ppSample);

void __RPC_STUB ISampleGrabber_GetCurrentSample_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

HRESULT STDMETHODCALLTYPE ISampleGrabber_SetCallback_Proxy(
    ISampleGrabber *This,
    ISampleGrabberCB *pCallback,
    long WhichMethodToCallback);

void __RPC_STUB ISampleGrabber_SetCallback_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);

#endif /* __ISampleGrabber_INTERFACE_DEFINED__ */

EXTERN_C const CLSID CLSID_NullRenderer;

#ifdef __cplusplus

class DECLSPEC_UUID("C1F400A4-3F08-11d3-9F0B-006008039E37")
    NullRenderer;
#endif

// class CDeviceController : public CFrameWnd
// { 
   

// };

class CSampleGrabberCB : public ISampleGrabberCB
{ 
   
public:
    STDMETHODIMP_(ULONG)
    AddRef() { 
    return 2; }
    STDMETHODIMP_(ULONG)
    Release() { 
    return 1; }
    STDMETHODIMP QueryInterface(REFIID iid, void **ppv)
    { 
   
        if (NULL == ppv)
            return E_POINTER;
        *ppv = NULL;
        if (IID_IUnknown == iid)
        { 
   
            *ppv = (IUnknown *)this;
            AddRef();
            return S_OK;
        }
        else if (IID_ISampleGrabberCB == iid)
        { 
   
            *ppv = (ISampleGrabberCB *)this;
            AddRef();
            return S_OK;
        }
        return E_NOINTERFACE;
    }

    STDMETHODIMP BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize)
    { 
   
        cout << "BufferCB SampleTime " << dec << dblSampleTime << ", BufferSize " << lBufferSize << endl;

        static char path[100];
        static int index = 0;
        static int m_index = 0;

        sprintf(path, "pic/%d_%d.jpg", m_index, index++);
        FILE *file = fopen((const char *)path, "wb");
        fwrite(pBuffer, lBufferSize, 1, file);
        fclose(file);

        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE SampleCB(double SampleTime, IMediaSample *pSample)
    { 
   
        cout << "SampleCB SampleTime " << dec << SampleTime << endl;

        return S_OK;
    }
};

void ShowGUID(GUID *guid)
{ 
   
    cout << hex << guid->Data1 << "-" << guid->Data2 << "-" << guid->Data3 << "-";
    for (int i = 0; i < 8; i++)
    { 
   
        cout << hex << guid->Data4[i];
    }
    cout << endl;
}

void ShowFilterInfo(IBaseFilter *filter)
{ 
   
    FILTER_INFO finfo;
    HRESULT hr = filter->QueryFilterInfo(&finfo);
    if (S_OK == hr)
    // cout << finfo.achName << endl;
    { 
   
        CLSID clsid;
        filter->GetClassID(&clsid);

        cout << "filter class id " << hex << clsid.Data1 << "-" << clsid.Data2 << "-" << clsid.Data3 << endl;

        _tprintf(_T("filter name %ws\r\n"), finfo.achName);

        if (finfo.pGraph != NULL)
        { 
   
            finfo.pGraph->Release();
        }
    }
    else
    { 
   
        cout << "Show Filter Info Failed " << hr << endl;
    }
}

void ShowPinInfo(IPin *pin)
{ 
   
    PIN_INFO info;
    HRESULT hr = pin->QueryPinInfo(&info);
    if (S_OK == hr)
    { 
   
        _tprintf(_T("pin name %ws,direction %d\r\n"), info.achName, info.dir);
        if (NULL != info.pFilter)
        { 
   
            ShowFilterInfo(info.pFilter);
            info.pFilter->Release();
        }
    }
    else
    { 
   
        cout << "get pin info failed" << endl;
    }
}

BOOL ChooseDevice(TCHAR *szDeviceName, IBaseFilter **pFilter)
{ 
   
    HRESULT hr;
    ICreateDevEnum *pSysDevEnum = NULL;
    // 创建并默认初始化一个指定CLSID关联的类的对象
    // 创建SystemDeviceEnum对象
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
    IEnumMoniker *pEnumCat = NULL;
    // 创建关联的设备类型枚举对象,枚举视频输入设备
    hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);

    IMoniker *pMoniker = NULL;
    ULONG cFected;
    // 循环获取设备
    while (pEnumCat->Next(1, &pMoniker, &cFected) == S_OK)
    { 
   
        IPropertyBag *pPropBag = NULL;
        // 获取设备信息
        hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);

        if (SUCCEEDED(hr))
        { 
   
            // To retrieve the filter's friendly name, do the following:
            VARIANT varName;
            VariantInit(&varName);
            hr = pPropBag->Read(L"FriendlyName", &varName, 0);
            if (SUCCEEDED(hr))
            { 
   
                // Display the name in your UI somehow.
                printf("%S\n", varName.bstrVal);
            }
            VariantClear(&varName);

            // 获取封装设备的Filter
            hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void **)pFilter);

            pPropBag->Release();

            break;
        }
    }

    pEnumCat->Release();
    pSysDevEnum->Release();

    return TRUE;
}

int show()
{ 
   
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    { 
   
        // init COM failed
        cout << "init COM failed" << endl;
        return 0;
    }

    // 创建Filter Graph Manager对象
    IGraphBuilder *pGraph;
    // 查找类标识为CLSID_FilterGraph的COM组件,使用改组件创建接口标识符为IID_IGraphBuilder的进程内组件对象pGraph
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    { 
   
        // 创建 Filter Graph
        return 0;
    }

    /** * 获取Filter Graph Manager的两个接口 * 1. IMediaControl 控制filter graph的启动和停止 * 2. IMediaEvent 从Filter Graph Manager获取事件,例如视频文件播放完毕事件 * */

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    ICaptureGraphBuilder2 *pBuild = NULL;
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pBuild);
    if (FAILED(hr))
        return 0;

    pBuild->SetFiltergraph(pGraph);

    // build graph
    IBaseFilter *pDeviceFilter = NULL;

    ChooseDevice(_T("SEMIC Camera"), &pDeviceFilter);

    cout << "Create Device Filter " << hex << pDeviceFilter << endl;
    pGraph->AddFilter(pDeviceFilter, L"SEMIC Camera");

    ShowFilterInfo(pDeviceFilter);

    IEnumPins *pDeviceEnumPins = NULL;
    // 设置输出视频格式及参数
    hr = pDeviceFilter->EnumPins(&pDeviceEnumPins);
    IPin *pDeviceOutPin = NULL;
    while (pDeviceEnumPins->Next(1, &pDeviceOutPin, NULL) == S_OK)
    { 
   
        PIN_DIRECTION pdir;
        pDeviceOutPin->QueryDirection(&pdir);
        if (PIN_DIRECTION::PINDIR_OUTPUT == pdir)
        { 
   
            break;
        }
        pDeviceOutPin->Release();
    }

    //
    GUID pSelectFormat = FORMAT_VideoInfo;
    GUID pSelectVideoType = MEDIASUBTYPE_MJPG;
    LONG pSelectWidth = 1920L;
    LONG pSelectHeight = 1080L;
    int pSelectFrameRate = 10;

    AM_MEDIA_TYPE *pSelectMediaType = NULL;

    AM_MEDIA_TYPE *pMediaType = NULL;

    IAMStreamConfig *pStreamConfig = NULL;
    hr = pDeviceOutPin->QueryInterface(IID_IAMStreamConfig, (void **)&pStreamConfig);
    if (hr == S_OK)
    { 
   

        int piCount, piSize;
        hr = pStreamConfig->GetNumberOfCapabilities(&piCount, &piSize);
        cout << "show media type : " << endl;
        for (int i = 0; i < piCount; i++)
        { 
   
            VIDEO_STREAM_CONFIG_CAPS scc;
            pStreamConfig->GetStreamCaps(i, &pMediaType, reinterpret_cast<BYTE *>(&scc)); // 获取所有设备支持的多媒体格式

            // hr = pStreamConfig->GetFormat(&pMediaType);
            // pMediaType->formattype;

            // ShowGUID(&pMediaType->formattype);
            // ShowGUID(&pMediaType->majortype);
            // ShowGUID(&pMediaType->subtype);
            // ShowGUID(&pMediaType->subtype);
            // pStreamConfig->SetFormat()
            if (FORMAT_VideoInfo == pMediaType->formattype)
            { 
   
                VIDEOINFOHEADER *pvideoInfo = (VIDEOINFOHEADER *)pMediaType->pbFormat;
                cout << "format videoinfo frame type ";
                if (MEDIASUBTYPE_YUY2 == pMediaType->subtype)
                { 
   
                    cout << "YUY2 , ";
                }
                else if (MEDIASUBTYPE_MJPG == pMediaType->subtype)
                { 
   
                    cout << "MJPG , ";
                }
                else
                { 
   
                    ShowGUID(&pMediaType->subtype);
                }

                cout << " height " << dec << pvideoInfo->bmiHeader.biHeight << " width " << pvideoInfo->bmiHeader.biWidth; // << endl;

                cout << ", frame rate " << dec << 10000000 / pvideoInfo->AvgTimePerFrame << endl;

                if (pSelectFormat == pMediaType->formattype && pSelectVideoType == pMediaType->subtype &&
                    pSelectHeight == pvideoInfo->bmiHeader.biHeight && pSelectWidth == pvideoInfo->bmiHeader.biWidth)
                { 
   
                    pSelectMediaType = pMediaType;
                }
                // cout << " frame size " << dec << pvideoInfo->bmiHeader.biSizeImage << endl;

                // 修改帧率
                // int _frame_rate = 5;
                // pvideoInfo->AvgTimePerFrame = 10000000 / _frame_rate;
                // pvideoInfo->dwBitRate = pvideoInfo->bmiHeader.biSizeImage * 8 * _frame_rate;
                // pStreamConfig->SetFormat(pMediaType);
            }
            else if (FORMAT_VideoInfo2 == pMediaType->formattype)
            { 
   
                VIDEOINFOHEADER2 *pvideoInfo = (VIDEOINFOHEADER2 *)pMediaType->pbFormat;
                cout << "format videoinfo2 frame type ";
                if (MEDIASUBTYPE_YUY2 == pMediaType->subtype)
                { 
   
                    cout << "YUY2 , ";
                }
                else if (MEDIASUBTYPE_MJPG == pMediaType->subtype)
                { 
   
                    cout << "MJPG , ";
                }
                else
                { 
   
                    ShowGUID(&pMediaType->subtype);
                }

                cout << " height " << dec << pvideoInfo->bmiHeader.biHeight << " width " << pvideoInfo->bmiHeader.biWidth; // << endl;
                cout << ", frame rate " << dec << 10000000 / pvideoInfo->AvgTimePerFrame << endl;

                if (pSelectFormat == pMediaType->formattype && pSelectVideoType == pMediaType->subtype &&
                    pSelectHeight == pvideoInfo->bmiHeader.biHeight && pSelectWidth == pvideoInfo->bmiHeader.biWidth)
                { 
   
                    pSelectMediaType = pMediaType;
                }
            }
            else
            { 
   
                cout << " other video format type ";
                ShowGUID(&pMediaType->formattype);
            }
        }
    }

    hr = pStreamConfig->SetFormat(pSelectMediaType);
    cout << " Set StreamConfig Media Format " << dec << hr << endl;
    pStreamConfig->Release();

    // 添加smart tee , 分成两路,一路预览,一路抓图
    IBaseFilter *pSmartTee = NULL;
    // hr = CoCreateInstance(CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pSmartTee);
    // cout << " Create Smart Tee " << hex << hr << endl;
    // pGraph->AddFilter(pDeviceFilter, L"Smart Tee");

    IBaseFilter *pNullFilter = NULL;
    hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (LPVOID *)&pNullFilter);

    pGraph->AddFilter(pNullFilter, L"NULL Filter");

    // RenderStream 若filter没有preview out pin,只有capture out pin则会插入一个smart tee filter;若没有指定要连接的目标则默认为video/video render filter
    hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pDeviceFilter, NULL, NULL);
    // hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pDeviceFilter, NULL, pSmartTee);
    cout << " RenderStream 1 " << hex << hr << endl;

    // hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pSmartTee, NULL, NULL);
    // cout << " RenderStream 2 " << hex << hr << endl;
    // hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSmartTee, NULL, pNullFilter);
    // cout << " RenderStream 3 " << hex << hr << endl;

    // 查找插入的smart tee filter
    hr = pBuild->FindInterface(&LOOK_DOWNSTREAM_ONLY, &MEDIATYPE_Video, pDeviceFilter, IID_IBaseFilter, (void **)&pSmartTee);
    cout << " FindInterface 1 " << hex << hr << " Smart Tee : " << pSmartTee << endl;

    ShowFilterInfo(pSmartTee);

    // hr = pBuild->FindInterface(NULL, &MEDIATYPE_Video, pDeviceFilter, IID_IBaseFilter, (void **)&pSmartTee);
    // cout << " FindInterface 1 " << hex << hr << " Smart Tee : " << pSmartTee << endl;

    // CLSID_MjpegDec;

    // IBaseFilter *pRender = NULL;
    // hr = pBuild->FindInterface(NULL, &MEDIATYPE_Video, pSmartTee, IID_IBaseFilter, (void **)&pRender);
    CLSID slcid;
    hr = pSmartTee->GetClassID(&slcid);
    if (hr == S_OK)
        cout << hex << slcid.Data1 << "-" << slcid.Data2 << "-" << slcid.Data3 << endl;
    else
    { 
   
        cout << "get class id failed" << endl;
    }

    IPin *pPrev = NULL;
    IEnumPins *pEnumPins = NULL;
    hr = pSmartTee->EnumPins(&pEnumPins);
    while (pEnumPins->Next(1, &pPrev, NULL) == S_OK)
    { 
   
        PIN_DIRECTION pDir;
        pPrev->QueryDirection(&pDir);

        if (pDir == PINDIR_OUTPUT)
        { 
   
            LPWSTR pId;
            pPrev->QueryId(&pId);
            // cout << pId << endl;

            _tprintf(_T("pin id : %ws , direction %d\r\n"), pId, pDir);

            // PIN_INFO pPinInfo;
            // pPrev->QueryPinInfo(&pPinInfo);

            pPrev->Release();
            // ShowPinInfo(pPrev);
        }

        /* code */
    }

    pEnumPins->Release();

    // IPin * pNextPin = NULL;
    // IBaseFilter * pNextFilter = NULL;
    // ULONG pins=1;
    // pPrev->QueryInternalConnections(&pNextPin,&pins);
    // cout <<"start show next pin "<<endl;
    // ShowPinInfo(pPrev);
    // ShowPinInfo(pNextPin);

    // pPrev->Release();

    // pBuild->

    // FILTER_INFO finfo;
    // pSmartTee->QueryFilterInfo(&finfo);
    // cout << finfo.achName << endl;

    // grabber sample
    IBaseFilter *pGrabberF = NULL;
    ISampleGrabber *pGrabber = NULL;
    hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pGrabberF);

    cout << " Create Sample Grabber " << hex << hr << endl;

    hr = pGraph->AddFilter(pGrabberF, L"Sample Grabber");

    cout << " add grabber filter " << hex << hr << endl;

    hr = pGrabberF->QueryInterface(IID_ISampleGrabber, (void **)&pGrabber);

    cout << "grabber filter query interface " << hex << hr << endl;

    // 设置允许的视频格式
    // AM_MEDIA_TYPE mt;
    // ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
    // mt.majortype = MEDIATYPE_Video;
    // mt.subtype = MEDIASUBTYPE_MJPG;
    // mt.formattype = FORMAT_VideoInfo;
    // hr = pGrabber->SetMediaType(&mt); // 在使用前必须设置多媒体类型
    hr = pGrabber->SetMediaType(pSelectMediaType);
    cout << " Set Media Type " << dec << hr << endl;

    // RenderStream 会查找符合条件的未连接的PIN进行连接
    hr = pBuild->RenderStream(NULL, &MEDIATYPE_Video, pSmartTee, pGrabberF, pNullFilter);
    cout << " RenderStream 4 " << hex << hr << endl;
    // hr = pBuild->RenderStream(NULL, &MEDIATYPE_Video, pGrabberF, NULL, pNullFilter);
    // cout << " RenderStream 3 " << hex << hr << endl;

    // 保存filer graph文件,用graphedit打开
    SaveGraphFile(pGraph, L"MyGraph.grf");

    CSampleGrabberCB *scb = new CSampleGrabberCB;
    pGrabber->SetCallback(scb, 1);

    // hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pDeviceFilter, NULL, NULL);
    // if (hr != S_OK && hr != VFW_S_NOPREVIEWPIN)
    // { 
   
    // cout << "render MEDIATYPE_Video stream failed : " << hex << hr << endl;
    // hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Interleaved, pDeviceFilter, NULL, NULL);

    // if (hr == VFW_S_NOPREVIEWPIN)
    // { 
   
    // cout << "use capture pin" << endl;
    // }
    // else if (hr != S_OK)
    // { 
   
    // cout << "render MEDIATYPE_Interleaved stream failed : " << hex << hr << endl;
    // }
    // }

    // 设置视频播放窗口
    IVideoWindow *pVidWin = NULL;
    pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
    pVidWin->put_Owner((OAHWND)hwnd);
    pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
    RECT rc;
    GetClientRect(hwnd, &rc);
    pVidWin->SetWindowPosition(0, 0, rc.right, rc.bottom);

    // 设置filter graph event
    pEvent->SetNotifyWindow((OAHWND)hwnd, WM_FGNOTIFY, 0);

    hr = pControl->Run();

    cout << "start run : " << hr << endl;

    // // if (hr == S_OK)
    // Sleep(1000 * 100);

    // cout << "complete" << endl;

    // pControl->Stop();

    // pControl->Release();
    // pEvent->Release();
    // pGraph->Release();
    // CoUninitialize();

    return 0;
}
// main.cpp
// #include <windows.h>
#include "preview_wnd.h"

HWND hwnd;

/*----------------------------------------------------------------------------*\ | AppWndProc( hwnd, uiMessage, wParam, lParam ) | | | | Description: | | The window proc for the app's main (tiled) window. This processes all | | of the parent window's messages. | | | | Arguments: | | hwnd window handle for the window | | msg message number | | wParam message-dependent | | lParam message-dependent | | | | Returns: | | 0 if processed, nonzero if ignored | | | \*----------------------------------------------------------------------------*/
LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ 
   
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    int cxBorder, cyBorder, cy;

    switch (msg)
    { 
   
    case WM_CREATE:
        break;

    case WM_COMMAND:
        break;

    case WM_INITMENU:
        break;

    case WM_INITMENUPOPUP:
        break;

    //
    // We're out of here!
    //
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_CLOSE:
        break;

    case WM_ENDSESSION:

        break;

    case WM_ERASEBKGND:
        break;

    // ESC will stop capture
    case WM_KEYDOWN:

        break;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);

        // nothing to do
        EndPaint(hwnd, &ps);
        break;

    case WM_TIMER:

        break;

    case WM_SIZE:

        break;

    case WM_FGNOTIFY:
        cout << "recv a filter graph event " << endl;
        // // uh-oh, something went wrong while capturing - the filtergraph
        // // will send us events like EC_COMPLETE, EC_USERABORT and the one
        // // we care about, EC_ERRORABORT.
        // // 获取filter graph manager发出的事件
        if (pEvent)
        { 
   
            LONG event;
            LONG_PTR l1, l2;
            HRESULT hrAbort = S_OK;
            BOOL bAbort = FALSE;
            while (pEvent->GetEvent(&event, &l1, &l2, 0) == S_OK) // 循环读取filter graph manager事件队列
            { 
   
                pEvent->FreeEventParams(event, l1, l2);
                if (event == EC_ERRORABORT) // filter graph退出/中断
                { 
   
                    cout << "filter graph abort" << endl;
                    // StopCapture();
                    bAbort = TRUE;
                    hrAbort = static_cast<HRESULT>(l1);
                    continue;
                }
                else if (event == EC_DEVICE_LOST) // graph中的设备热插拔事件
                { 
   
                    cout << "device lost event " << endl;

                    // Check if we have lost a capture filter being used.
                    // lParam2 of EC_DEVICE_LOST event == 1 indicates device added (1 设备插入)
                    // == 0 indicates device removed (0 设备移除)
                    if (l2 == 0)
                    { 
   
                        IBaseFilter *pf;
                        IUnknown *punk = (IUnknown *)l1;
                        if (S_OK == punk->QueryInterface(IID_IBaseFilter, (void **)&pf))
                        { 
   
                            cout << "device lost " << endl;
                            ShowFilterInfo(pf);
                            pf->Release();
                        }
                    }
                }
                else
                { 
   
                    cout << "other event " << dec << event << endl;
                }
            } // end while
        }
        break;

    case WM_DEVICECHANGE:
        // // We are interested in only device arrival & removal events
        // // 注册的感兴趣的设备热插拔事件
        // if (DBT_DEVICEARRIVAL != wParam && DBT_DEVICEREMOVECOMPLETE != wParam)
        // break;

        // PDEV_BROADCAST_HDR pdbh = (PDEV_BROADCAST_HDR)lParam;
        // if (pdbh->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
        // { 
   
        // break;
        // }

        // PDEV_BROADCAST_DEVICEINTERFACE pdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
        // // Check for capture devices.
        // if (pdbi->dbcc_classguid != AM_KSCATEGORY_CAPTURE)
        // { 
   
        // break;
        // }

        // // Check for device arrival/removal.
        // if (DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam)
        // { 
   
        // gcap.fDeviceMenuPopulated = false;
        // }
        break;
    }

    return (LONG)DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{ 
   
    static TCHAR szAppName[] = TEXT("HelloWin");
    WNDCLASS wndclass;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;

    RegisterClass(&wndclass);

    hwnd = CreateWindow(szAppName,                 // window class name
                        TEXT("The Hello Program"), // window caption
                        WS_OVERLAPPEDWINDOW,       // window style
                        CW_USEDEFAULT,             // initial x position
                        CW_USEDEFAULT,             // initial y position
                        CW_USEDEFAULT,             // initial x size
                        CW_USEDEFAULT,             // initial y size
                        NULL,                      // parent window handle
                        NULL,                      // window menu handle
                        hInstance,                 // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

    auto cbuf = cout.rdbuf();

	// cout重定位输出到文件
    ofstream of1("log.txt");
    auto fileBuf = of1.rdbuf();
    cout.rdbuf(fileBuf);

    cout << "start show " << endl;
    // const char *path = "log.txt";
    // // sprintf(path, "log.txt", m_index, index++);
    // FILE *file = fopen((const char *)path, "w");
    // const char *log = "start show";
    // fwrite(log, strlen(log), 1, file);
    // fclose(file);

    // show video
    show();

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    { 
   
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    of1.flush();
    of1.close();
    cout.rdbuf(cbuf);

    return msg.wParam;
}

使用cl.exe编译:

cl preview_app.cpp preview_wnd.cpp SaveGraphFile.cpp Strmiids.lib ole32.lib OleAut32.lib user32.lib

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/24902.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信