1. 概述
這本篇文章給出創建DirectShow程序的一個簡單的示例。DirectShow中使用了大量的COM,確切講DirectShow就是構建在COM基礎上的,但關於COM的基礎知識不在這裡敷述。這個程序是一個簡單的可以播放聲音或者是視頻的控制台程序。這個示例程序只有簡單的幾行,但是卻演示了一個強大的DirectShow的程序。
一個DirectShow應用程序包括以下幾個步驟:
1. 創建一個Filter Graph Manager 的實例;
2. 使用Filter Graph Manager創建一個Filter Graph
3. 運行這個 graph,這樣就會使數據通過這些過濾器(filter)
2. 詳細敘述
首先,調用CoInitialize初始化COM庫:
//初始化COM庫.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - 不能初始化COM庫");
return 1;
}
為了使這個示例程序簡單一些,程序中忽略了返回值,但是你可以從任何方法調用中檢查HRESULT的值。
其次,調用CoCreateInstance創建Filter Graph Manager:
//創建過濾器圖像管理器,查詢接口
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - 不能夠創建 Filter Graph Manager.");
return 0;
}
如上面的代碼所示,這個類標識符(CLSID)是CLSID_FilterGraph。這個Filter Graph Manager由進程中的Dll提供,所以創建時的執行空間上下文是CLSCTX_INPROC_SERVER。DirectShow支持自由線程模式,所以你也可以用CoInitializeEx調用COINIT_MULTITHREADED標識符。
調用CoCreateInstance返回IGraphBuilder這個接口,這個接口包含了創建filter graph的大多數方法。另外示例中還需要其余的兩個接口:
l IMediaControl接口控制數據流。這個接口裡面包含了開始和結束播放畫面的方法。
l IMediaEvent接口包含從Filter Graph Manager中取得的事件。在這個示例裡面,這個接口用來等待視頻播放完成。
這兩個接口都是通過Filter Graph Manager暴露出來的。使用IGraphBuilder指針可以查詢這兩個接口:
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
現在,你可以創建Filter Graph。這個可以用一個簡單的命令調用。
// 創建graph,此處為要打開的影片
hr = pGraph->RenderFile((LPCWSTR)wText, NULL);
IGraphBuilder::RenderFile 這個方法用來創建一個Filter Graph 用來播放一個特定的文件。第一個參數是一個文件名,這個文件名為一個Unicode字符串,第二個參數是一個保留字符,一般為NULL。
如果打開的文件不存在,或者是文件格式識別這個返回值HRESULT為FAIL。假設這個方法成功了,filter就可以播放了。調用IMediaControl::Run就可以播放視頻了。
//運行graph.
hr = pControl->Run();
當這個過濾器開始運行後,數據通過filter過濾器後分解成視頻和音頻。系統播放視頻時會創建一個獨立的進程,你可以通過調用IMediaEvent::WaitForCompletion事件方法來監視播放事件當前的狀態。
// 等待影片播放完成
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
這個事件阻塞到文件完成播放時,或者是到這個線程分配到的時間片丟失掉的時候。INFINITE這個值意味著應用程序阻塞到整個影片播放完成。
當應用程序完成了整個影片的播放,釋放這些接口的指針,然後關閉這些COM組件庫。
pControl->Release();
pEvent->Release();
pGraph->Release();
//卸載COM組件
CoUninitialize();
3. 源程序
3.1. 說明
程序中用到了DirectShow示例文件中的基本類庫,在編譯之前先編譯DX安裝目錄\Samples\C++\DirectShow \BaseClasses 下面的工程,進行以下設置菜單Project->Setting
添加strmbase.lib
3.2. 源碼
1. /********************************************************************
2. created: 2008/05/15
3. created: 15:5:2008 13:39
4. file base: FirstDX
5. file ext: cpp
6. author: ZJY
7.
8. purpose: 這個小程序主要是為了演示DirectShow的最基本的一個步驟
9. *********************************************************************/
10. #include "stdafx.h"
11. #include <dshow.h>
12. #include <iostream>
13.
14. int main(int argc,char *argv[])
15. {
16. char strAviName[256];
17. if (argc == 1)
18. {
19. std::cout << "沒有輸出影片,請添加要播放的影片..." <<std::endl;
20. return 1;
21. }
22. else if (argc == 2)
23. {
24. strcpy(strAviName,argv[1]);
25. }
26. else
27. {
28. std::cout <<"參數傳遞錯誤..." <<std::endl;
29. return 1;
30. }
31.
32. IGraphBuilder *pGraph = NULL;
33. IMediaControl *pControl = NULL;
34. IMediaEvent *pEvent = NULL;
35.
36. //初始化COM庫.
37. HRESULT hr = CoInitialize(NULL);
38. if (FAILED(hr))
39. {
40. printf("ERROR - 不能初始化COM庫");
41. return 1;
42. }
43.
44. //創建過濾器圖像管理器,查詢接口
45. hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
46. IID_IGraphBuilder, (void **)&pGraph);
47. if (FAILED(hr))
48. {
49. printf("ERROR - 不能夠創建 Filter Graph Manager.");
50. return 0;
51. }
52.
53. hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
54. hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
55.
56. //由於DirectShow主要是Unicode格式,我們使用Windows自帶函數
57. //轉換文件名char數組為Unicode格式
58. int len = strlen(strAviName)+1;
59. wchar_t *wText = new wchar_t[len];
60. if ( wText == NULL)
61. {
62. std::cout <<"ERROR - 文件打開錯誤..."<<std::endl;
63. return 1;
64. }
65. memset(wText,0,len);
66. ::MultiByteToWideChar( CP_ACP, NULL,strAviName, -1, wText,len );
67.
68. // 創建graph,此處為要打開的影片
69. hr = pGraph->RenderFile((LPCWSTR)wText, NULL);
70.
71. if (SUCCEEDED(hr))
72. {
73. //運行graph.
74. hr = pControl->Run();
75. if (SUCCEEDED(hr))
76. {
77. // 等待影片播放完成
78. long evCode;
79. pEvent->WaitForCompletion(INFINITE, &evCode);
80. //注意:不要在真實的程序中使用INFINITE,因為這樣會永久阻塞應用程序
81. }
82. }
83. else
84. std::cout << "ERROR - 影片不存在或格式不支持..." <<std::endl;
85. pControl->Release();
86. pEvent->Release();
87. pGraph->Release();
88. //卸載COM組件
89. CoUninitialize();
90. return 0;
91. }本文出自 “持之以恆,刨根問底” 博客,請務必保留此出處http://zjyzjy.blog.51cto.com/329429/77136