zoukankan      html  css  js  c++  java
  • [转]DirectShow:图片的抓取

    本文转自:http://blog.chinaunix.net/u2/63021/showart_492136.html

    原文如下:

    在播放媒体文件的过程中,有一个很有用的功能,就是在当前播放的位置抓取图,实现这种图片抓取功能的方法很多,我们这里只介绍常用的两种。 


    第1种方法最简单,它使用1BasicVideo::GetCurrentImage接口方法,代码如下。 
       heel SnapshotBitmap(IBasicVideo*pBa8icVideo,  const char*OutFile)
        if  (pBasicVldeo)
        {
            long bitmapSize=0;
            //首先获得图像大小
            if(SUCCEEDED(pEasicVidee->GetcurrentImage(&bitmapSize,0)))
            {
                bool pass=false;
                //分配图像帧内存
                unsigned char*buffer=new unsigned char[bitmapSize];
               //获取图像帧数据
               if(SUCCEEDED(pBasicVideo->GetCurrentImage(&bitmapSize,(long*)buffer)))
         {
                   BITMAPFILEHEADER hdr;
                   LPBITMAPINFOHEADER  ipbi;
                   ipbi=(LPBITMAPINFOHEADER)buffer;
                   int nColors=1<<ipbi->biBitCount;
                   if(nColors>256)
                   //always is”BM”
                    hdr.bfType    =((WORD)(‘M’<<8)|’B’);
                    hdr.bfSize    =bitmapSize+sizeof(hdr);
                    hdr.bfReservedl    =0;
                    hdr.bfReserved2    =0;
                    hdr.bfOffBits    =(DWORD)
                   (sizeof(BITMAPFILEHEADER)+lpbi->biSize+nColors*sizeof(RGBQUAD));
                   CFile bitmapFile(outFile,CFile::modeReadWrite |
                                   CFile::modeCreate | CFile::typeBinary);
                   //写入位图文件头
                   bitmapFile.Write{&hdr,sizeof【BITMApFILEHEADER));
                   //写入图像帧数据(包括BITMAPINFOHEADER信息)
                   bitmapFile.Write(buffer,bitmapSize);
                   bitmapFile.Close();
                   pas8=true;
       }
                   delete[]burfer;
                   return Pass;
               }
                return false ;

      值得注意的是,IBasieVideo接口应该从Filter Graph Manager上获得,但真正实现在
    Renderer Filter上。如果我们使用的是传统的Video Renderer,那么使用GetCurrentlmage 抓图将是不可靠的。因为如果Video Renderer使用了DirectDraw加速,这个函数调用会失 败;而且调用这个函数,Video Renderer必须处于暂停状态。但如果我们使用的是VMR, 则没有上述这些限制。


      第2种方法比较复杂.它使用Sample Grabber Filter。它其实是一个Trans-In-Place
    Filter,在SDK安装目录下的Samples\C++\DirectShow’Filters\Grabber提供了源代码。实际 上,Sample Grabber可以抓取任何类型的Sample。但在这里,我们只介绍使用它抓取视频 帧的方法。步骤如下:

    (1)创建Sample Grabber,并将之加入到Filter Graph中。
    //Create the Sample Grabber
    IBaseFilter*pGrabberF=NULL;
    hr=CoCreateInstanee(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,
        IID IBaseFilter,  (void**)&pGrabberF);
    if(FAILED(hr))

        //Return an error

    hr=pGraph->AddFilter(pGrabberF,L"Sample Grabber");
    if(FAILED(hr)
    {
        //Return an error
    }
    ISampleGrabber*pGrabber=NULL;
    pGrabberF->QueryInterface(IID_ISampleGrabber,(void**)&pGrabber);

    (2)给SampleGrabber设置Pin上连接用的媒体类型。
       如果我们想抓取24位的RGB图片,如下设置媒体类型:
    AM_MEDIA_TYPE mt;
    ZeroMemorY(&mt,sizeof(AM_MEDIA_TYPE));
    mt.malOrtype=MEDIATYPE Video;
    mt.subtype=ME:DIASUBTYPE RGB24;
    hr=pGrabber->SetMediaType(&mt);
    也可以根据当前显示器的配置来设置Sample Grabber接受的RGB类型,代码如下: 
      //Find the current bit depth
      HDC hdc=GetDC(NULL);
      int iBitDepth=GetDeviceCaps(hdc,  BITSPIXEL);
      ReleaseDC(NULL,hdc);
      //Set the media type
      mt.maJortype=MEDIATYPE Video;
      switch(iBitDepth)
      {
      Case 8:
        mt.subtype=MEDIASUBTYPE RGB8 ;
        break;
        case 1 6:
        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); 

    (3)完成FilterGraph的构建。
        因为Sample Grabber上已经设置了一个媒体类型,则其他Filter必须以这种媒
    才能与Sample Grabber相连。我们可以使用DimctShow的“智能连接”机制,来
    个Fitler Graph的创建过程,代码如下。
    IBaseFiiter*pSrc;
    hr=pGraph->AddSourceFilter(wszFileName,  L"Source",  &pSrc}; 
      if(FAILED(hr))
      {
        //Return an error code
      }
      hr=ConnectFiiters(pGraph,pSrc,pGrabberF);
      其中,ConnectFilters是我们在5.3节中介绍的自定义函数。
      如果我们只是想抓图(不需要对视频预览),则Sample Grabber后面可以连接一个Null Renderer Filter(它的CLSID为CLSID NullRenderer)。如果要Filter Graph中的数据流以最快的速度传送,则Filter Graph不要使用参考时钟(调用IMediaFitter::SetSyncSource,参数为NULL)。

    (4)运行FilterGraph。
      Sample Grabber可以有如下两种工作模式:
      缓冲模式将输入的Sample进行缓存后,再往下传送。
      回调模式当有输入的Sample时,调用应用程序设置进来的回调函数。
      因为回调模式会影响整个Filter Graph的效率,并且容易引起死锁,所以我们推荐使用缓冲模式。另外,我们可以设置ISampleGrabber::SetOneShot,使得Sample Grabber获取一个Sample以后,就让FilterGraph停止,代码如下: 
      //Set one-shot mode and buffering.
      hr=pGrabber->SetOneShot(TRUE);
      hr=pGrabber->SetBufferSamples(TRUE);
      pControl->Run();//Run the graph.
      pEvent->WaitForCompletion(INFINITE,&evCode),//Wait till it’s done. 
       
    (5)获取抓到的Sample数据
      
    缓冲模式下,我们可以调用ISampleGrabber::GetCurrentBuffer来获取Sample数据,代码如下:
      //Find the required buffer size
      long cbBuffer=0;
      hr=pGrabber->GetCurrentBuffer(&cbBuffer,NULL);
      char*pBuffer=new char[cbBuffer];
      if(!pBuffer)
        //Out of memory.Return an error code
        }
    hr=pGrabber->GetCurrentBuffer(&cbBuffer,(long*)pBuffer);
    我们也可以将获取的数据使用GDI函数显示出来,代码如下:
    AM_MEDIA_TYPE mt;
    hr=pGrabber->GetConnectedMediaType(&rot);
    if(FAILED(hr))
    {
       //Return err05 code
      }
      //Examine the format block
      VIDEOINFOHEADER*pVih;
      if((mt.formattype==FORMAT_VideoInfo)&&
        (mt.cbFormat>=sizeof(VIDEOINFOHEADER))&&
        (mt.pbFormat!=NULL))
        pVih={vIDEOINFOHEADER*)mt·pbFormat;
      }
      else    
      {
        //Wrong format.Free the format block and return an error‘
        FreeMedlaType(mt);
        return VFW_E_INVALIDMEDIATYPE;
    //youcan use the media type to access the BITMAPINFOHEAFRE information,
    //For example,the following code draws the bitmap using GDI
      SetDIBitsToDevice(
        hdc,0,0,
        pVih->bmiHeader.biWidth,
        pVih->bmiHeader.biHeight,
        O,  O,
        0,
        pVih->bmiHeader.biHeight,
        pBuffer,
        (BITMAPINFO*)&pVih->bmiHeader,
        DIB RGB COLORS
      ),
     //Free the format block when you are done:
      FreeMediaType(mt); 

  • 相关阅读:
    混合现实开发教程unity2017
    Intro to Airplane Physics in Unity 3D – 2017 and 2018
    Unity Awards 2018最佳资源
    ambiguous
    Unity2018.3全新Prefab预制件系统深入介绍视频教程+PPT+Demo源码
    Android Studio 集成开发工具教学视频 + 项目实战安卓多SDK接入与集成
    Unity下一轮最大的变革-Entity Component System & C# Jobs System
    使用unity开发游戏时如觉得游戏声音太吵,点Mute Audio
    SQL Delta实用案例介绍
    经典批处理实现自动关机(BAT)
  • 原文地址:https://www.cnblogs.com/freeliver54/p/1376785.html
Copyright © 2011-2022 走看看