directshow的中文資料之播放影片

 

DirectShow編程指南

我們終於開始了我們的真正旅程!Let's Go!

由於DirectXVC++的緊密聯繫,所有的代碼都用C++寫的。

 

.播放影片

通過一個簡單的C++程序示範如何播放影片。本節包括:

1.播放一個媒體文件--回放媒體文件的基本代碼。

2.添加媒體seek功能--提供在媒體文件中如何seek一個特定的的位置的代碼。(seek就是...你用過CFile::Seek麼?嗯...就是他了)。

 

因爲只是個演示很多都是定了的。例如:

TCHAR *szFilename = "c://dxmedia//movie//movie.avi";

當然你可以用各種方法得到你使用的文件信息。

另外就是定義了自己的響應消息和一個釋放宏:

 #define WM_GRAPHNOTIFY  WM_USER+13

 #define HELPER_RELEASE(x) { if (x) x->Release(); x = NULL; }

 

需要的頭文件:

#include <windows.h>

#include <mmsystem.h>

#include <streams.h>

 

申明變量:

HWND      ghApp;

HINSTANCE ghInst;

HRESULT   hr;

LONG      evCode;

LONG      evParam1;

LONG      evParam2;

其中ghApp是一個graph產生的事件的響應窗口句柄。ghInst是窗口的HINSTANCEevCode將保存事件代碼,evParam1evParam2保存事件的參數。

 

申明和初始化必須的接口。由於接口的索引值是自動的加1,所以你不要調用IUnknown::AddRef方法(如果你覺得陌生,你可以參考綜述篇的"一、DirectX和部件對象模型COM")。

IGraphBuilder *pigb  = NULL;

IMediaControl *pimc  = NULL;

IMediaEventEx *pimex = NULL;

IVideoWindow  *pivw  = NULL;

 

定義一個函數:szFile參數是播放的媒體文件名

void PlayFile(LPSTR szFile)

     HRESULT  hr;

 

建立一個Unicode(wide character)字符串。

     WCHAR wFile[MAX_PATH];

     MultiByteToWideChar( CP_ACP, 0, szFile, -1, wFile, MAX_PATH );

 

實例化一個filter graph manager

     hr = CoCreateInstance(CLSID_FilterGraph,

        NULL,

        CLSCTX_INPROC_SERVER,

        IID_IGraphBuilder,

        (void **)&pigb);

 

查詢IMediaControl接口(提供run,pause and stop methods),IMediaEventEx接口(你可以接收事件響應),IVideoWindow接口。

    pigb->QueryInterface(IID_IMediaControl, (void **)&pimc);

      pigb->QueryInterface(IID_IMediaEventEx, (void **)&pimex);

      pigb->QueryInterface(IID_IVideoWindow, (void **)&pivw);

 

filter graph manager建立filter graph去渲染輸入文件。現在還沒播放文件(當你用run函數播放時,filter graph會自動渲染輸入文件的媒體類型,你不必指定渲染過濾器)。

    hr = pigb->RenderFile(wFile, NULL);

 

用一個窗口捕捉graph的通知事件。可以改善性能,但是允許你的應用程序運行在另一個線程。

    pimex->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);

ghApp處理消息去響應從graph傳來的所有事件。如果事件發生了,DirectShowpost一個WM_GRAPHNOTIFY消息給ghApp

 

開始播放文件。

     hr = pimc->Run();

 

同樣的,你也可以有

   hr = pimc->Pause();

    hr = pimc->Stop();

當然了,你可以用一個對話框的按鈕來響應Pause Stop。這樣就實現了簡單的回放。

記住了,在你的代碼裏,要釋放你用的接口,可以用HELPER_RELEASE 宏。

例:HELPER_RELEASE(pigb);

 

現在加入seek功能。

在你的媒體文件中,你可以用IMediaPosition or IMediaSeeking 接口seek到一個特定的位置播放。IMediaPostion::put_CurrentPosition方法可以指定開始時間,例如你可以用下面的代碼實現重放:

   IMediaPosition *pimp;

    hr = pigb->QueryInterface(&IID_IMediaPosition, (void **)&pimp);

    hr = pimp->put_CurrentPosition(0);

 

時間的單位是100吶秒,下面的代碼seek到文件的一秒處:

    hr = pimp->put_CurrentPosition(10000000);

 

你也可以用IMediaPosition::put_StopTime 方法去設置文件的回放停止時間。

 

然而,用IMediaPosition只能用seek時間,如果你用 IMediaSeeking接口,你能用多種格式seek,用100吶秒單位,frame(),字節,media samples,或者是interlaced video fields。你可以用IMediaSeeking::SetTimeFormat 設置你需要的格式。注意,確信你不在播放媒體文件,當你設置格式的時候。

格式如下:

TIME_FORMAT_MEDIA_TIME  單位是100吶秒

TIME_FORMAT_BYTE  單位是字節 

TIME_FORMAT_FIELD  單位是interlaced video field(我不太清楚這格式,所有隻好用英文) 

TIME_FORMAT_FRAME  單位是幀 

TIME_FORMAT_SAMPLE  單位是sample (我不太清楚這格式,所有隻好用英文) 

 

舉個例子吧,下面的代碼設置格式爲幀。

    IMediaSeeking *pims;

     hr = pigb->QueryInterface(IID_IMediaSeeking, (void **)&pims);

     hr = pims->SetTimeFormat(&TIME_FORMAT_SAMPLE);

 

應用程序可以用多樣的seek模式,而不需要考慮 時間/速率的轉換。有時候這是很有用的。

 

下面示例如何用幀的格式開始和結束播放。如在15幀開是播放影片。你可以把代碼插入到PlayFile函數的任何地方,注意的是,一定要在RenderFile函數的後面(還記得hr = pigb->RenderFile(wFile, NULL);這段代碼麼?)。

    IMediaSeeking *pims;

     hr = pigb->QueryInterface(IID_IMediaSeeking, (void **)&pims);

 

設置時間格式。

    hr = pims->SetTimeFormat(&TIME_FORMAT_FRAME);

 

申明並初始化開始和結束變量:

   LONGLONG start = 5L;

    LONGLONG stop = 15L;

 

通過IMediaSeeking::SetPositions方法設置開始和結束時間, AM_SEEKING_AbsolutePositioning標誌意味着這是一個絕對的位置(不是相對於媒體文件現在的位置)。在這個例子中,媒體文件就在第5幀開始,在15幀結束,持續時間是10幀。具體的時間長度要看視頻幀的播放速率了。

   pims->SetPositions(&start, AM_SEEKING_AbsolutePositioning, &stop,

               AM_SEEKING_AbsolutePositioning);

 

最後釋放接口。

   pims->Release();

 

當然你也可以設置別的格式,和別的開始結束的信息。例如5秒到7秒。

   hr = pims->SetTimeFormat(&TIME_FORMAT_FRAME);

   LONGLONG start = 50000000L;

    LONGLONG stop = 70000000L;

其他就看你自己喜歡了......(我沒有任何權利干涉)

發佈了34 篇原創文章 · 獲贊 1 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章