在c#中用directshow做的媒體播放機(jī)
概述:
我的這個(gè)程序僅僅只是告訴大家如何用directshow 在c#中做一個(gè)播放機(jī),世上并不能
有太多的功能.也許你只要花上五分種就可以解決問(wèn)題.是的如果你用的是ide,我感保證
一切都只是用你的鼠標(biāo)在你的設(shè)計(jì)器中點(diǎn)點(diǎn)屬性設(shè)置一些東西就可以簡(jiǎn)單的完成了.當(dāng)然
了還是要那么一點(diǎn)點(diǎn)編碼的.至少是關(guān)于directshow 接口的.例如,視屏和聲音.
程序中的小問(wèn)題:
1.如何從你的磁盤上打開媒體文件
2.如何讓工具條上的按鈕起用和禁用
3.如何設(shè)置狀態(tài)欄的顯示文字
4.如何控制時(shí)間
5.如何使用時(shí)間控件的事件
6.如何用directshow來(lái)播放媒體文件
7.如何確定播放狀態(tài)等等...
...
用戶界面如下圖:
很簡(jiǎn)單是嗎?是的,我說(shuō)了是個(gè)簡(jiǎn)單的程序,我只是讓它具備了基本功能而已.工具欄上
的三個(gè)button控制播放,停止和暫停.一個(gè)文件菜單用來(lái)打開媒體文件和關(guān)閉程序.當(dāng)然
還有一個(gè)介紹程序的info毫無(wú)疑問(wèn)這是最基本的界面配置.
下面介紹directshow 接口
播放視屏和聲音文件我們要用到diectx為我們提供的directshow組件.使用這個(gè)接口
可以讓你方便的播放那些共用的影像和聲音文件.你要做的僅僅只是安裝directshow接口
和使用它的功能函數(shù)和配置正確的接口參數(shù)而已.
不幸的是.net并不正式支持directx.是的也許你聽說(shuō)directx9支持是嗎?是的,不過(guò)在
最終版敲定的那一天還沒來(lái),我們都得不到最好的效果.但無(wú)論如何我們還是要用的不是嗎?
要不這篇文章得作廢了.是的,也許你用過(guò)vb,對(duì)了,就是它,我們正是要用到那個(gè).
好了,在此之前我們還必須要做件事情.我想你已經(jīng)猜到了,引用對(duì)嗎?還記得xcopy嗎?是的
.net的優(yōu)勢(shì).來(lái)吧,快點(diǎn)把這個(gè)"interop.quartztypelib.dll"dll引用進(jìn)來(lái),就象這樣
看見下面的圖示了嗎?很簡(jiǎn)單.
最后別忘了看看你的代碼中是否有那么一句
using quartztypelib;
有是嗎?編譯器為你加的,如果沒有自己加上好了.
準(zhǔn)備工作結(jié)束了,該是代碼部分了,這可是程序員無(wú)法推卸的責(zé)任.否則我們都得下崗了.
程序?qū)崿F(xiàn)部分:
如何打開你想要媒體文件?
還記得嗎?"file -> open..." 是的幾乎每個(gè)使用windows的人都會(huì)這樣操作.如何實(shí)現(xiàn)?
很簡(jiǎn)單看看下面的代碼:
openfiledialog openfiledialog = new openfiledialog();
openfiledialog.filter = "media files|*.mpg;*.avi;*.wma;*.mov;*.wav;*.mp2;*.mp3|all files|*.*";
if (dialogresult.ok == openfiledialog.showdialog())
{
.
.
.
看吧很簡(jiǎn)單是嗎?記得寫一個(gè)函數(shù)把它放進(jìn)去.當(dāng)你點(diǎn)擊ok按鈕的時(shí)候.directshow接口就會(huì)
得到你想要播放的文件.
看下面的圖你就知道它是如何工作的.
directshow為多媒體流回放提供最基本的服務(wù),這些多媒體流可以是本地文件,還可以是服務(wù)器傳輸過(guò)來(lái)的。特別的,directshow可以支持視頻回放,支持以不同的文件和流格式壓縮視頻內(nèi)容,包括windows media、mpeg、avi和wav。
在directshow的核心處,服務(wù)是組件的模塊化集合,稱為過(guò)濾器,可以根據(jù)媒體類型排列成過(guò)濾器圖。過(guò)濾器可以操作數(shù)據(jù)流,如讀入、分析、解碼、格式化或渲染。
過(guò)濾器以樹型進(jìn)行排列,這棵樹稱為過(guò)濾器樹,通過(guò)過(guò)濾器樹管理器(filter graph manager,簡(jiǎn)稱fgm)進(jìn)行管理。使用fgm應(yīng)用程序可以通過(guò)使用microsoft windows media player控件間接控制過(guò)濾器樹,還可以通過(guò)調(diào)用com接口方法直接控制。directshow過(guò)濾器樹(參閱圖1)由從源到目標(biāo)渲染器的有向過(guò)濾器序列組成,所有這些通過(guò)輸入和輸出過(guò)濾器引腳連接。過(guò)濾器引腳協(xié)商它們將支持哪些媒體類型。fgm控制樹過(guò)濾器之間的多媒體數(shù)據(jù)流。因?yàn)閐irectshow有一個(gè)靈活的、可重配置的過(guò)濾器樹體系結(jié)構(gòu),因此directshow可以使用同樣的軟件成分支持多種媒體類型的回放和分流。開發(fā)人員還可以通過(guò)編寫自己的過(guò)濾器擴(kuò)展directshow多媒體支持。
圖1. directshow過(guò)濾器樹
過(guò)濾器
過(guò)濾器是注冊(cè)的directshow類,它執(zhí)行許多媒體信息處理任務(wù)。這些任務(wù)包括:
獲得源信息(例如,獲得媒體流)
分析(例如,在流上執(zhí)行包讀入、分離和格式化)
轉(zhuǎn)換(例如,解碼wma和mpeg-4音頻和視頻流)
渲染(例如,在適當(dāng)?shù)臅r(shí)候產(chǎn)生音頻pcm或者視頻rgb/yuv輸出,將數(shù)據(jù)傳給directsound和directdraw)
過(guò)濾器使用幾種類型的接口,例如引腳、計(jì)數(shù)器、傳送器和時(shí)鐘接口,來(lái)執(zhí)行它們的任務(wù)。過(guò)濾器實(shí)現(xiàn)和開放了許多接口。fgm可以使用這些接口創(chuàng)建、連接和控制樹。過(guò)濾器經(jīng)常實(shí)現(xiàn)包含下列方法的ibasefilter接口:
運(yùn)行、停止和暫停過(guò)濾器狀態(tài)。
恢復(fù)過(guò)濾器和廠商信息。
得到和設(shè)置參考時(shí)鐘。
恢復(fù)過(guò)濾器狀態(tài)信息。
枚舉過(guò)濾器引線。
重建過(guò)濾器樹時(shí)定位引腳
好了介紹了這么多,你的手也許已經(jīng)閑不住了.看看下面的代碼是如何實(shí)現(xiàn)的
cleanup();
m_objfiltergraph = new filgraphmanager();
m_objfiltergraph.renderfile(openfiledialog.filename);
m_objbasicaudio = m_objfiltergraph as ibasicaudio;
try
{
m_objvideowindow = m_objfiltergraph as ivideowindow;
m_objvideowindow.owner = (int) panel1.handle;
m_objvideowindow.windowstyle = ws_child | ws_clipchildren;
m_objvideowindow.setwindowposition(panel1.clientrectangle.left,
panel1.clientrectangle.top,
panel1.clientrectangle.width,
panel1.clientrectangle.height);
}
catch (exception ex)
{
m_objvideowindow = null;
}
m_objmediaevent = m_objfiltergraph as imediaevent;
m_objmediaeventex = m_objfiltergraph as imediaeventex;
m_objmediaeventex.setnotifywindow((int) this.handle, wm_graphnotify, 0);
m_objmediaposition = m_objfiltergraph as imediaposition;
m_objmediacontrol = m_objfiltergraph as imediacontrol;
//
如何來(lái)播放,暫停,停止?
簡(jiǎn)單這些函數(shù)看字面也知道.
m_objmediacontrol.run();//播放
m_objmediacontrol.pause();//暫停
m_objmediacontrol.stop();//停止
ok,在來(lái)看我們是如何控制時(shí)間進(jìn)度的?
//
private void timer1_tick(object sender, system.eventargs e)
{
if (m_currentstatus == mediastatus.running)
{
updatestatusbar();
}
}
看見上面那個(gè) updatestatusbar();這里是讓它沒100ms更新一次狀態(tài)欄.
代碼如下:
private void updatestatusbar()
{
switch (m_currentstatus)
{
case mediastatus.none : statusbarpanel1.text = "stopped"; break;
case mediastatus.paused : statusbarpanel1.text = "paused "; break;
case mediastatus.running: statusbarpanel1.text = "running"; break;
case mediastatus.stopped: statusbarpanel1.text = "stopped"; break;
}
if (m_objmediaposition != null)
{
int s = (int) m_objmediaposition.duration;
int h = s / 3600;
int m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);
statusbarpanel2.text = string.format("{0:d2}:{1:d2}:{2:d2}", h, m, s);
s = (int) m_objmediaposition.currentposition;
h = s / 3600;
m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);
statusbarpanel3.text = string.format("{0:d2}:{1:d2}:{2:d2}", h, m, s);
}
else
{
statusbarpanel2.text = "00:00:00";
statusbarpanel3.text = "00:00:00";
}
}
還有一個(gè)問(wèn)題程序怎么能夠知道它播放完了????
這會(huì)有點(diǎn)麻煩了.好了,想想看有什么辦法呢?對(duì)了,windows是消息驅(qū)動(dòng)的.那找找看有什么消息
好了.有的就ec_complete 這個(gè).還記得"wndproc" 它嗎??是的,我的老朋友.這次我們必須
要改寫它來(lái)捕獲ec_complete消息.這個(gè)消息是directshow通知父窗體,播放結(jié)束了.
protected override void wndproc(ref message m)
{
if (m.msg == wm_graphnotify)
{
int leventcode;
int lparam1, lparam2;
while (true)
{
try
{
m_objmediaeventex.getevent(out leventcode,
out lparam1,
out lparam2,
0);
m_objmediaeventex.freeeventparams(leventcode, lparam1, lparam2);
if (leventcode == ec_complete)
{
m_objmediacontrol.stop();
m_objmediaposition.currentposition = 0;
m_currentstatus = mediastatus.stopped;
updatestatusbar();
updatetoolbar();
}
}
catch (exception)
{
break;
}
}
}
base.wndproc(ref m);
}
好了,一切都結(jié)束了,現(xiàn)在要做的事就是做些來(lái)找一部影片來(lái)享受一下自己的成果了.
新聞熱點(diǎn)
疑難解答
圖片精選