最簡單的基於DirectShow的樣本:視頻播放器自訂版,directshow樣本

來源:互聯網
上載者:User

最簡單的基於DirectShow的樣本:視頻播放器自訂版,directshow樣本
本文記錄一個簡單的基於DirectShow的自訂的視頻播放器。這裡所說的“自訂播放器”,實際上指的是自己在Filter Graph中手動逐個添加Filter,並且串連這些Filter的後啟動並執行播放器。這麼做相對於使用RenderFile()這種“智能”建立Filter Graph的方法來說要複雜不少,但是可以讓我們更加瞭解DirectShow的體系。

流程圖

最簡單的基於DirectShow的自訂的視頻播放器的流程如所示。


該流程圖中包含如下變數:
IGraphBuilder *pGraph:繼承自IFilterGraph,用於構建Filter Graph。
IMediaControl *pControl:提供和播放控制有關的一些介面。
IMediaEvent   *pEvent:用來處理Filter Graph發出的事件。
IBaseFilter *pF_source:源Filter。
IFileSourceFilter* pFileSource:源Filter的暴露的介面,用於設定輸入檔案的路徑。
IBaseFilter *pF_demuxer:解複用Filter。
IBaseFilter *pF_decoder:解碼Filter。
IBaseFilter *pF_render:渲染Filter。
IPin *pOut:輸出Pin。
IPin *pIn:輸入Pin。
IPin **pPin:內部變數Pin。
該流程圖大體上可以分成以下步驟:
(1)       初始化DirectShow
包括以下幾個步驟:
a)       CoInitialize():初始化COM運行環境。
b)       CoCreateInstance(…,pGraph):用指定的類別識別項建立一個Com對象。在這裡建立IGraphBuilder。
c)       pGraph->QueryInterface(…,pControl):通過QueryInterface()查詢某個組件是否支援某個特定的介面。在這裡查詢IMediaControl介面。
d)       pGraph->QueryInterface(…,pEvent):同上。在這裡查詢IMediaEvent介面。
(2)       添加Source Filter
包括以下幾個步驟:
a)       CoCreateInstance(…,pF_source):建立Source Filter。
b)       pGraph->AddFilter(pF_source,…):將Source Filter加入Filter Graph。
c)       pF_source->QueryInterface(…,pFileSource):尋找Source Filter的IFileSourceFilter介面。
d)       pFileSource->Load(L"xxx.mpg",pF_source):調用IFileSourceFilter的Load()方法載入視頻檔案。
(3)       添加Demuxer Filter
包括以下幾個步驟:
a)       CoCreateInstance(…,pF_demuxer):建立Demuxer Filter。
b)       pGraph->AddFilter(pF_demuxer,…):將Demuxer Filter加入Filter Graph。
(4)       添加Decoder Filter
包括以下幾個步驟:
a)       CoCreateInstance(…,pF_decoder):建立Decoder Filter。
b)       pGraph->AddFilter(pF_decoder,…):將Decoder Filter加入Filter Graph。
(5)       添加Render Filter
包括以下幾個步驟:
a)       CoCreateInstance(…,pF_render):建立Render Filter。
b)       pGraph->AddFilter(pF_render,…):將Render Filter加入Filter Graph。
(6)       串連Source Filter和Demuxer Filter
調用了一個函數connect_filters()用於串連2個Filter。
connect_filters()的執行步驟如下:
a)       調用get_unconnected_pin()從源Filter中選擇一個沒有連結的輸出Pin。
b)       調用get_unconnected_pin()從目的Filter中選擇一個沒有連結的輸入Pin。
c)       串連這兩個Pin
get_unconnected_pin()的執行步驟如下:
a)       枚舉Filter上的Pin。
b)       遍曆這些Pin,尋找符合輸出方向(通過IPin的QueryDirection()方法),而且沒有在使用的Pin(通過IPin的ConnectedTo()方法)。
(7)       串連Demuxer Filter和Decoder Filter
過程同上。
(8)       串連Decoder Filter和Render Filter
過程同上。
(9)       開始播放
包括以下步驟:
pControl->Run():開始運行Filter Graph中的所有Filter。
pEvent->WaitForCompletion():等待Filter Graph處理完所有資料。
 

上述步驟可以理解為在GraphEdit軟體中分別按照步驟添加以下控制項。其中(1)、(2)、(3)、(4)為先添加的4個Filter,(5)、(6)、(7)為Filter之間的連接線。



原始碼
/** * 最簡單的基於DirectShow的視頻播放器(Custom) * Simplest DirectShow Player (Custom) * * 雷霄驊 Lei Xiaohua * leixiaohua1020@126.com * 中國傳媒大學/數字電視技術 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程式是一個簡單的基於DirectShow的視頻播放器。該播放器通過逐個添加 * 濾鏡並串連這些濾鏡實現了視頻的播放。適合初學者學習DirectShow。 *  * This software is a simple video player based on DirectShow. * It Add DirectShow Filter Manually and Link the Pins of these filters * to play videos.Suitable for the beginner of DirectShow. */#include "stdafx.h"#include <dshow.h>//'1':Add filters manually//'0':Add filters automatically#define ADD_MANUAL 1//Find unconnect pinsHRESULT get_unconnected_pin(IBaseFilter *pFilter, // Pointer to the filter.PIN_DIRECTION PinDir, // Direction of the pin to find.IPin **ppPin) // Receives a pointer to the pin.{*ppPin = 0;IEnumPins *pEnum = 0;IPin *pPin = 0;HRESULT hr = pFilter->EnumPins(&pEnum);if (FAILED(hr)){return hr;}while (pEnum->Next(1, &pPin, NULL) == S_OK){PIN_DIRECTION ThisPinDir;pPin->QueryDirection(&ThisPinDir);if (ThisPinDir == PinDir){IPin *pTmp = 0;hr = pPin->ConnectedTo(&pTmp);if (SUCCEEDED(hr)) // Already connected, not the pin we want.{pTmp->Release();}else // Unconnected, the pin we want.{pEnum->Release();*ppPin = pPin;return S_OK;}}pPin->Release();}pEnum->Release();// Did not find a matching pin.return E_FAIL;}//Connect 2 filtersHRESULT connect_filters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest){if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL)){return E_POINTER;}//Find Output pin in source filterIPin *pOut = 0;HRESULT hr = NULL;hr=get_unconnected_pin(pSrc, PINDIR_OUTPUT, &pOut);if (FAILED(hr)){return hr;}//Find Input pin in destination filterIPin *pIn = 0;hr = get_unconnected_pin(pDest, PINDIR_INPUT, &pIn);if (FAILED(hr)){return hr;}//Connnect themhr = pGraph->Connect(pOut, pIn);pIn->Release();pOut->Release();return hr;}int _tmain(int argc, _TCHAR* argv[]){IGraphBuilder *pGraph = NULL;    IMediaControl *pControl = NULL;    IMediaEvent   *pEvent = NULL;     // Init COM    HRESULT hr = CoInitialize(NULL);    if (FAILED(hr)){        printf("Error - Can't init COM.");        return -1;    }// Create FilterGraph   hr=CoCreateInstance(CLSID_FilterGraph, NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&pGraph);    if (FAILED(hr)){        printf("Error - Can't create Filter Graph.");        return -1;    }   // Query Interface    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);//1. Add Filters=======================//SourceIBaseFilter *pF_source = 0;hr = CoCreateInstance(CLSID_AsyncReader, 0, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)(&pF_source));if (FAILED(hr)){printf("Failed to create File Source.\n");return -1;}hr = pGraph->AddFilter(pF_source, L"Lei's Source");if (FAILED(hr)){printf("Failed to add File Source to Filter Graph.\n");return -1;}IFileSourceFilter* pFileSource;pF_source->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSource);pFileSource->Load(L"cuc_ieschool.mpg", NULL);pFileSource->Release();#if ADD_MANUAL//DemuxerIBaseFilter *pF_demuxer = 0;hr = CoCreateInstance(CLSID_MPEG1Splitter, 0, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)(&pF_demuxer));if (FAILED(hr)){printf("Failed to create Demuxer.\n");return -1;}hr = pGraph->AddFilter(pF_demuxer, L"Lei's Demuxer");if (FAILED(hr)){printf("Failed to add Demuxer to Filter Graph.\n");return -1;}//DecoderIBaseFilter *pF_decoder = 0;hr = CoCreateInstance(CLSID_CMpegVideoCodec, 0, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)(&pF_decoder));if (FAILED(hr)){printf("Failed to create Decoder.\n");return -1;}hr = pGraph->AddFilter(pF_decoder, L"Lei's Decoder");if (FAILED(hr)){printf("Failed to add Decoder to Filter Graph.\n");return -1;}//RenderIBaseFilter *pF_render = 0;hr = CoCreateInstance(CLSID_VideoRenderer, 0, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)(&pF_render));if (FAILED(hr)){printf("Failed to create Video Render.\n");return -1;}hr = pGraph->AddFilter(pF_render, L"Lei's Render");if (FAILED(hr)){printf("Failed to add Video Render to Filter Graph.\n");return -1;}//2. Connect Filters=======================hr = connect_filters(pGraph, pF_source, pF_demuxer);if (FAILED(hr)){printf("Failed to link Source and Demuxer.\n");return -1;}hr = connect_filters(pGraph, pF_demuxer, pF_decoder);if (FAILED(hr)){printf("Failed to link Demuxer and Decoder.\n");return -1;}hr = connect_filters(pGraph, pF_decoder, pF_render);if (FAILED(hr)){printf("Failed to link Decoder and Render.\n");return -1;}pF_source->Release();pF_demuxer->Release();pF_decoder->Release();pF_render->Release();#elseIPin* Pin;ULONG fetched;//get output pinIEnumPins* pEnumPins;hr = pF_source->EnumPins(&pEnumPins);hr = pEnumPins->Reset();hr = pEnumPins->Next(1, &Pin, &fetched);pEnumPins->Release();//render pin, graph builder automatically complete rest workshr = pGraph->Render(Pin);#endif    if (SUCCEEDED(hr)){        // Run        hr = pControl->Run();        if (SUCCEEDED(hr)){long evCode=0;pEvent->WaitForCompletion(INFINITE, &evCode);        }    }//Release    pControl->Release();    pEvent->Release();    pGraph->Release();    CoUninitialize();return 0;}

運行結果

程式的運行結果如所示。運行後會播放“cuc_ieschool.mpg”檔案。需要注意的是,本程式並沒有加入音頻解碼和播放的Filter,所以播放視頻的時候是沒有聲音的。


除了手動一個一個添加Filter之外,也可以在獲得“源”Filter的Pin之後,直接調用IFilterGraph的Render()方法“智能”自動構建Filter Graph。注意Render()方法和RenderFile()方法是不一樣的。RenderFile()是指定一個檔案路徑後,自動構建整個Filter Graph,相對來說更加簡單些;而Render()方法則是首先要建立一個Source Filter之後,才可以自動構建整個Filter Graph。
可以通過修改源檔案首部的宏定義ADD_MANUAL來設定是否手動添加Filter,如下所示。
//'1':Add filters manually//'0':Add filters automatically#define ADD_MANUAL 1
 
下載
Simplest DirectShow Example
 
SourceForge項目首頁:https://sourceforge.net/projects/simplestdirectshowexample/
CDSN:http://download.csdn.net/detail/leixiaohua1020/8348163
 
本程式包含了DirectShow開發的樣本程式。適合DirectShow初學者進行學習。
它包含了以下幾個子程式:
simplest_directshow_player: 最簡單的基於DirectShow的視頻播放器。
simplest_directshow_player_custom: 最簡單的基於DirectShow的視頻播放器(Custom)。
playerGUI: 最簡單的基於DirectShow的播放器-圖形介面版。
simplest_directshow_info: 最簡單的Directshow資訊顯樣本子。
simplest_directshow_filter: 目前還未完成。
 

相關關鍵詞:
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.