<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      在VC中調用DirectShow全屏播放視頻

      [摘要]有些正在嘗試自己編制游戲的朋友可能會碰到這樣一個問題:游戲要播放片頭動畫,可是如何全 屏播放動畫呢?用媒體播放機控件?這是最簡單的方法,可是好多功能都用不上,不免覺得有些 浪費。而用vfw之類的多媒...
      有些正在嘗試自己編制游戲的朋友可能會碰到這樣一個問題:游戲要播放片頭動畫,可是如何全
      屏播放動畫呢?用媒體播放機控件?這是最簡單的方法,可是好多功能都用不上,不免覺得有些
      浪費。而用vfw之類的多媒體庫又太麻煩。怎么辦呢?

      其實微軟不但提供了DirectX這樣的便于游戲開發的SDK,還提供了基于其上的DirectX Media  
      SDK。這套SDK可以幫助你簡化多媒體開發,而又充分利用DirectX的高性能。使用起來很簡單,功
      能也很強大,它可以自己識別流的格式,連mpeg2都不放過!

      下面我以實例來說明如何調用DirectShow來全屏播放視頻:

      首先,需要在工程中包含如下頭文件:
      #include "ddraw.h"
      #include "mmstream.h"
      #include "amstream.h"
      #include "ddstream.h"

      這些頭文件提供了必要的數據結構和方法聲明。

      其次,我們可以將程序的整個流程分為3個步驟:
      1、建立DirectDraw表面(Surface)。
      2、從文件中提取視頻流(可能還有音頻)。
      3、在DirectDraw上表面播放視頻流。

      必要的變量:
      DDSURFACEDESC ddsd;
      IDirectDraw *pDD;     
      IDirectDrawSurface *pPrimarySurface;
      IMultiMediaStream *pMMStream;

      IMultiMediaStream接口是DirectShow中最高等級的接口對象,可以包含一個或多個多媒體對象。
      這些多媒體對象可以是不同類型的,比如音頻,視頻等等。下面大家將會看到。

      在初始化方法中加入如下代碼:
      HRESULT Init()
      {
      ......
      pDD=NULL;
      pPrimarySurface=NULL;
      pMMStream=NULL;
      ZeroMemmory(ddsd,sizeof(ddsd));

      HRESULT r;
      //初始化COM
      CoInitialize(NULL);
      //初始化DirectDraw
      r=InitDDraw();

      return r;
      }
      由于DirectShow是基于COM的所以要用CoInitialize初始化COM,該方法很簡單,只有一個參數且必
      須是NULL。
      InitDDraw()的實現將在后面給出。

      析構方法中加入如下代碼:
      void Uninit()
      {
      ......
      if(pMMStream!=NULL)
      pMMStream->Release();
      if(pPrimarySurface!=NULL)
      pPrimarySurface->Release();     
      if(pDD!=NULL)
      pDD->Release();  

      CoUninitialize();
      }

      初始化DirectDraw并建立DirectDraw表面:(由于DirectDraw不是本文的重點,原理請參考相關
      文獻,現只給出代碼)
      不妨建立一個方法將這些工作統統包括:
      HRESULT InitDDraw()
      {
      HRESULT r;
      if(FAILED(r=DirectDrawCreate(NULL, &pDD, NULL)))
      return r;
        if(FAILED(r=pDD->SetCooperativeLevel(hWnd,  
      DDSCL_EXCLUSIVE DDSCL_FULLSCREEN)))
      return r;
      if(FAILED(r=pDD->SetDisplayMode(640,480,16))) //分辨率設置
      return r;
        
      ddsd.dwSize = sizeof(ddsd);
      ddsd.dwFlags = DDSD_CAPS;
        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
        if(FAILED(pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL)))
      return r;
      return S_OK;

      }

      接下來的一步將從文件中提取視頻流。
      不妨也建立一個方法將工作封裝。
      HRESULT LoadFromFile(const char * szFileName, IMultiMediaStream **ppMMStream,  
      IDirectDraw *pDD)
      {
      HRESULT r;
      IAMMultiMediaStream *pAMStream;

        if(FAILED(r=CoCreateInstance(CLSID_AMMultiMediaStream, NULL,  
      CLSCTX_INPROC_SERVER,
                            IID_IAMMultiMediaStream, (void **)&pAMStream)))
      return r;
      WCHAR wPath[MAX_PATH];
      MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wPath,
      sizeof(wPath)/sizeof(wPath[0]));     

        if(FAILED(r=pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD,  
      NULL)))
      return r;
        if(FAILED(r=pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL)))
      return r;
        if(FAILED(r=pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio,  
      AMMSF_ADDDEFAULTRENDERER, NULL)))
      return r;
        if(FAILED(r=pAMStream->OpenFile(wPath, 0)))
      return r;
      *ppMMStream = pAMStream;
      return S_OK;
      }
      方法代碼如上。

      LoadFromFile()方法有3個參數:
      const char * szFileName, IMultiMediaStream **ppMMStream和IDirectDraw *pDD

      第一個參數是要提取的文件名。字符串常量。第二個參數是多媒體流接口的指針的指針,是用來
      操縱多媒體流的。第三個參數是DirectDraw接口,將來播放時就是通過它的表面。

      首先聲明一個IAMMultiMediaStream接口的指針,該接口的功能十分強大,這里只用了它的一部
      分:
      建立視頻和音頻流,再從文件中提取。

      然后調用CoCreateInstance方法來創建IAMMultiMediaStream的實例。該方法的第一個參數指定了
      全局標志(guid,下同),第四個參數指明要創建的接口的標志,第五個參數是創建好的實例返
      回付給pAMStream變量。

      接下來的兩行代碼是將char字符串轉換成unicode,不必多言。

      然后初始化IAMMultiMediaStream,建立視頻音頻流。

      最后,也是最重要的一步:調用OpenFile()方法從文件中提取流。第一個參數是文件名,第二
      個參數是打開方式(具體請參考msdn)。

      這樣就完成了流的提取工作。

      下面開始播放。
      這也是最復雜的工作(相對)。

      同樣,建個方法封裝代碼。
      HRESULT Play(IDirectDrawSurface *pSurface, IMultiMediaStream *pMMStream)
      {     
      IMediaStream *pPrimaryVidStream;     
      IDirectDrawMediaStream *pDDStream;
        IDirectDrawStreamSample *pSample;
      RECT rect;
        DDSURFACEDESC ddsd;

        pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pPrimaryVidStream);
        pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)
      &pDDStream);
        ddsd.dwSize = sizeof(ddsd);
        pDDStream->GetFormat(&ddsd, NULL, NULL, NULL);
        
      rect.top =100;
      rect.left =150;
        rect.bottom = ddsd.dwHeight+100;
        rect.right = ddsd.dwWidth+150;
        
      pDDStream->CreateSample(pSurface, &rect, 0, &pSample);
      pMMStream->SetState(STREAMSTATE_RUN);

      while (pSample->Update(0, NULL, NULL, NULL) == S_OK)
      ;

      pMMStream->SetState(STREAMSTATE_STOP);
      pSample->Release();     
      pDDStream->Release();
        pPrimaryVidStream->Release();
      }
      Play()方法有兩個參數,一個是用來播放視頻的DirectDraw表面,一個是含有數據流的
      MultiMediaStream對象。

      變量聲明如下:
      IMediaStream *pPrimaryVidStream;     
      IDirectDrawMediaStream *pDDStream;
        IDirectDrawStreamSample *pSample;
      RECT rect;
        DDSURFACEDESC ddsd;
      他們分別是IMediaStream接口,用來查詢IDirectDrawMediaStream接口;DirectDrawMediaStream
      接口,用來得到流數據的細節,如長、寬等等;IDirectDrawStreamSample接口,這是一個數據樣
      本,用來刷新DirectDraw表面,也就是播放了。
      接下來的兩個分別是:一個rect數據結構,用來指定播放區域;一個表面描述,這里用來得到樣
      本數據的格式。

      然后是實現部分:

      首先調用IMultiMediaStream的GetMediaStream()方法來得到一個IMediaStream的視頻對象流,
      類型由參數MSPID_PrimaryVideo指定。
      接著通過IMediaStream來查詢得到IDirectDrawMediaStream接口(具體機理請參考COM文獻,這里
      不再累述)。
      然后由IDirectDrawMediaStream接口獲取數據格式,建立樣本并關聯到DirectDraw表
      面。IMediaStream接口通過
      SetState(STREAMSTATE_RUN)方法來播放媒體流,播放的數據由IDirectDrawStreamSample樣本刷
      新到DirectDraw表面上。
      如果刷新成功,IDirectDrawStreamSample::Update()方法返回S_OK。放完了以后再調用
      IMediaStream::SetState(STREAMSTATE_STOP)停止媒體流。

      就這樣,DirectShow通過這些接口互相協作著完成了視頻流的播放。

      由于篇幅所限只列出了核心代碼,如果大家有興趣可以到我的網站下載一個demo(付源碼)。
      網址如下:http://www.sunistudio.com

      本人才疏學淺,如有錯誤之處還望高手指點!^o^
      我的email:Lythm@citiz.net(別炸我)。
      ...... 


      日韩精品一区二区三区高清