zoukankan      html  css  js  c++  java
  • 使用SampleGrabber过滤器扑获图像

    Sample Grabber过滤器是一个可以被插入流的过滤器,它有自己的缓冲,存放采样。

    如果你想从一个视频文件中简单的扑获一桢,那么我建议你使用Media Detector对象。Sample Grabber提供了更复杂的更灵活的控制。我们通过下面的步骤使用Sample Grabber过滤器:

    1、 指定你想要扑获的媒体类型

    在Sample Grabber 过滤器连接到别的过滤器之前你必须配置它。首先你要调用CoCreateInstance来创建Sample Grabber ,然后调用IfilterGraph::AddFilter来加载它到过滤图形中。然后查询IsampleGrabber接口。我们使用 IsampleGrabber::SetMediaType方法来设置媒体类型。这个方法指定了Sample Grabber过滤器将要连接的媒体类型。你可以仅仅指定主媒体类型;或者主类型加子类型;或者主类型,子类型和类型格式。

    例如,如果你想扑获一个未压缩的视频桢,这个视频桢要求是兼容当前显示模式的,你可以设置主类型为MEDIATYPE_Video然后设置基于当前显示位深的子类型。下面的例子也许能说明问题:

    // 创建 Sample Grabber.IBaseFilter *pF = NULL;ISampleGrabber *pGrabber = NULL;hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,    IID_IBaseFilter, reinterpret_cast<void**>(&pF));hr = pF->QueryInterface(IID_ISampleGrabber,    reinterpret_cast<void**>(&pGrabber));hr = pGraph->AddFilter(pF, LSampleGrabber);// 找到当前的色深HDC hdc = GetDC(NULL);int iBitDepth = GetDeviceCaps(hdc, BITSPIXEL);ReleaseDC(NULL, hdc);// 设置媒体类型AM_MEDIA_TYPE mt;ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));mt.majortype = MEDIATYPE_Video;switch (iBitDepth){case 8:    mt.subtype = MEDIASUBTYPE_RGB8;    break;case 16:    mt.subtype = MEDIASUBTYPE_RGB555;    break;case 24:    mt.subtype = MEDIASUBTYPE_RGB24;    break;case 32:    mt.subtype = MEDIASUBTYPE_RGB32;    break;default:    return E_FAIL;}hr = pGrabber->SetMediaType(&mt);

    2、 建立包含Sample Grabber过滤图形

    在你指定媒体类型之后,你就可以建立一个包含Sample Grabber的过滤图形了。Sample Grabber将仅连接到指定的类型,而且允许你在建立过滤图形时使用智能连接机制。

    例 如前面的代码就指定了未压缩的视频桢。准备好了以后,你就可以调用IgraphBuilder::AddSourceFilter方法从视频文件源流中加 入捕获过滤器。为了将这个过滤器插入过滤图形,我们还需要调用IgraphBuilder::Connect方法来连接源过滤器和Sample Grabber。过滤图形管理器会自动的添加需要的解码过滤器。

    下面的代码就是这样做的。它使用了两个帮助函数来枚举引脚。GetPin函数在过滤器中找到第一个引脚,输入或者输出引脚。ConnectFilters函数找到过滤器中的第一个输出引脚,然后连接这个引脚到另外一个过滤器的第一个输入引脚。

    HRESULT GetPin(IBaseFilter *, PIN_DIRECTION, IPin **);HRESULT ConnectFilters(IGraphBuilder *, IBaseFilter *, IBaseFilter *); IBaseFilter *pSrc;hr = pGraph->AddSourceFilter(wszFileName, LSource, &pSrc);hr = ConnectTwoFilters(pGraph, pSrc, pF); // Helper functions:HRESULT GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin){    IEnumPins *pEnum;    IPin       *pPin;    pFilter->EnumPins(&pEnum);    while(pEnum->Next(1, &pPin, 0) == S_OK)    {        PIN_DIRECTION PinDirThis;        pPin->QueryDirection(&PinDirThis);        if (PinDir == PinDirThis)        {            pEnum->Release();            *ppPin = pPin;            return S_OK;        }        pPin->Release();    }    pEnum->Release();    return E_FAIL; } HRESULT ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pFirst, IBaseFilter *pSecond){    IPin *pOut = NULL, *pIn = NULL;    HRESULT hr = GetPin(pFirst, PINDIR_OUTPUT, &pOut);    if (FAILED(hr)) return hr;    hr = GetPin(pSecond, PINDIR_INPUT, &pIn);    if (FAILED(hr))      {        pOut->Release();        return E_FAIL;     }    hr = pGraph->Connect(pOut, pIn);    pIn->Release();    pOut->Release();    return hr;}

    应用程序必须连接了Sample Grabber的输出引脚。如果你想丢弃采样,那么你可以连接Null Renderer过滤器。这个过滤器将会丢弃它所收到的每一桢。

             IBaseFilter *pNull = NULL;         hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,             IID_IBaseFilter, reinterpret_cast<void**>(&pNull));         hr = pGraph->AddFilter(pNull, LNullRenderer);         hr = ConnectTwoFilters(pGraph, pF, pNull);

    3、 运行过滤图形

    Sample Grabber工作包含两种模式:

    A、 在将采样向下传送之前产生每个采样的拷贝,然后放到其缓冲。

    B、 以回调方式进行处理数据,回调由应用程序定义。

    这里我们仅讨论一下缓冲模式。但是大家要注意的是回调方式会影响我们的工作效率,甚至死锁。回调函数设置我们用IsampleGrabber::SetCallback方法。

    为 了激活缓冲模式,我们调用IsampleGrabberr::SetBufferSample方法,参数填充TRUE。你也可以使用 IsampleGrabber::SetOneShot方法,这样会导致每捕获一桢后过滤图形停止。这个特性对我们如果仅想在流里面捕获一桢的需求十分有 益。我们可以搜索到想要捕获的地方运行过滤图形,进行截获。但是桢的精确度还是要靠数据源的性质决定。

    下面的例子实现的就是这些:

             // 设置快照和缓冲模式.         hr = pGrabber->SetOneShot(TRUE);         hr = pGrabber->SetBufferSamples(TRUE);          IMediaFilter *pMediaFilter = NULL;         IMediaControl *pControl = NULL;         IMediaEventEx *pEvent = NULL;                       pMediaFilter->SetSyncSource(NULL); // 关掉参考时钟         pControl->Run(); // 运行过滤图形.         pEvent->WaitForCompletion(INFINITE, &evCode); // 等待直到结束

          

    4、 从Sample Grabber中得到缓冲采样,或者实现回调函数来获得数据。

    在 缓冲模式,Sample Grabber过滤器存储了它收到的每个采样的拷贝。我们要获得缓冲数据就要调用IsampleGrabber::GetCurrentBuffer方 法。这个方法填充一个调用者分配好的矩阵。为了能获得缓冲区大小,调用方法的时候必须将缓冲的指针填NULL。

             long cbBuffer = 0;         hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL);         char *pBuffer = new char[cbBuffer];         if (!pBuffer)          {             return E_OUTOFMEMORY;         }         hr = pGrabber->GetCurrentBuffer(&cbBuffer,               reinterpret_cast<long*>(pBuffer));

    使 用IsampleGrabber::GetConnectedMediaType方法来获得缓冲格式。例如,如果缓冲是一个未压缩的视频桢,它的格式就是 VIDEOINFOHEADER结构格式。注意,Sample Grabber不支持VIDEOINFOHEADER2结构。

             AM_MEDIA_TYPE mt;         hr = pGrabber->GetConnectedMediaType(mt);         VIDEOINFOHEADER *pVih;         if (mt.formattype == FORMAT_VideoInfo)               pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);         else               return VFW_E_INVALIDMEDIATYPE; // Something went wrong         // pVih->bmiHeader 这个参数是BITMAPINFOHEADER 结构,是每一桢的图形信息.                  // 释放格式块     

  • 相关阅读:
    CSU 1333 Funny Car Racing
    FZU 2195 检查站点
    FZU 2193 So Hard
    ZOJ 1655 FZU 1125 Transport Goods
    zoj 2750 Idiomatic Phrases Game
    hdu 1874 畅通工程续
    hdu 2489 Minimal Ratio Tree
    hdu 3398 String
    洛谷 P2158 [SDOI2008]仪仗队 解题报告
    POJ 1958 Strange Towers of Hanoi 解题报告
  • 原文地址:https://www.cnblogs.com/mfryf/p/2352651.html
Copyright © 2011-2022 走看看