利用Visual C#開發一個媒體播放器
2024-07-21 02:24:47
供稿:網友
摘要:了解如何在 microsoft visual c# .net 中使用 directshow 控件,如何開發一個媒體播放器。按照本文介紹的操作步驟,您可以創建一個簡單 visual c# 應用程序,用來播放數字音頻和視頻。
簡介
microsoft visual c# 是世界上最流行的編程語言,利用 visual c# 的最新版本 visual c# .net,您能夠快速、有效地開發基于 windows 窗體的應用程序,還可以為嵌入了 microsoft windows media? player 9 series activex 控件的應用程序添加新鮮、有趣而又非常實用的功能。
directshow 控件是一個標準的 activex 控件,提供了大量的功能。directshow控件提供的功能包括:
· 數字媒體文件和流媒體的高級播放功能。
· 使用播放列表的功能。
· 播放 dvd 和 cd 的功能。
· 訪問 windows media player 中的 media library(媒體庫)。
· 處理元數據的功能。
· 支持字幕。
· 支持多種語言的音頻。
· 控制網絡連通性和訪問相關統計信息的功能。
下面我們來看看構造這個媒體播放器要達到什么樣的目標,確定了目標也就確定了代碼量和程序的復雜程度。本文的媒體播放器要達到如下目標:
· 是一個菜單驅動的簡單awt應用。
· 包含一個“文件”菜單,文件菜單包含三個菜單項:
· “打開”,用來打開媒體文件。
· “循環”,是播放一次(默認),還是重復播放。
· “退出”,退出程序。
· 可以在多種平臺上運行。
· 核心功能通過jmf(java media framework)api實現。
按照本文介紹的步驟,您將創建一個基于 windows 窗體的基本應用程序,并在其中嵌入 player 控件。您創建的示例應用程序具有如下特點:
· 創建 directshow 控件的一個實例。
· 利用 windows media player 主互操作程序集提供組件對象模型 (com) 互操作性。
· 允許用戶打開并播放 windows media 文件,尤其是文件擴展名為 .wma 或 .wmv 的文件。
· 創建供用戶播放、暫停和停止數字媒體內容的傳輸控制按鈕。
· 顯示當前數字媒體文件的標題。
· 演示如何使用 player 對象模型,包括使用屬性、方法和事件的示例。
我的這個程序僅僅只是告訴大家如何用directshow 在c#中做一個播放機,
在這個程序中我們經要解決的一些小問題:
1.如何從你的磁盤上打開媒體文件
2.如何讓工具條上的按鈕起用和禁用
3.如何設置狀態欄的顯示文字
4.如何控制時間
5.如何使用時間控件的事件
6.如何用directshow來播放媒體文件
7.如何確定播放狀態等等...
下圖顯示了您將要創建的應用程序,其中正在播放名為“melow”的數字音頻文件,同時呈現了可視化效果。
圖 1
· 本文假設您已經具備一定的 visual c# 和 visual studio.net 集成開發環境知識。
準備工作
在開始創建應用程序之前,您需要安裝必要的軟件并注冊主互操作程序集 (quartztypelib)。
這里簡單介紹directshow 接口:
播放視屏和聲音文件我們要用到diectx為我們提供的directshow組件.使用這個接口可以讓你方便的播放那些共用的影像和聲音文件.你要做的僅僅只是安裝directshow接口和使用它的功能函數和配置正確的接口參數而已.
不幸的是.net并不正式支持directx.是的也許你聽說directx9支持是嗎?是的,不過在最終版敲定的那一天還沒來,我們都得不到最好的效果.但無論如何我們還是要用的不是嗎?要不這篇文章得作廢了.是的,也許你用過vb,對了,就是它,我們正是要用到那個.
開始項目
在安裝必要軟件并注冊 quartztypelib之后,您就可以啟動 visual c#,開始為示例應用程序創建項目。下面我將給大家介紹這一過程的操作步驟。
創建項目
按以下步驟創建一個空的項目:
1. 啟動 visual studio .net,然后單擊 new project(新建項目)。
2. 在 visual c# projects(visual c# 項目)文件夾中單擊 windows application(windows 應用程序),鍵入新項目的名稱(最好為 directshow),然后單擊 ok(確定)。
visual c# 使用默認的 windows 窗體“form1”創建一個新的項目。
3. 這個名稱并沒有特別的意義或用處,所以請在 properties(屬性)窗口中將窗體名稱更改為 frmplaymedia,將窗體文本更改為“媒體播放器”。
在項目中添加對 directshow的引用
按照以下步驟在項目中添加一個對 directshow的引用:
1. 打開 visual studio 工具箱,然后單擊 components(組件)顯示該面板。
2. 右擊面板,然后單擊 customize toolbox(自定義工具箱),顯示對話框。
3. 在 com components(com 組件)選項卡上,選中 interop.quartztypelib.dll。(如果 interop.quartztypelib.dll 由于某種原因未列出,則單擊 browse [瀏覽] 并查找名為 quartztypelib.dll的文件。)
4. 單擊 ok(確定)關閉對話框。
圖 2
要在代碼中使用 directshow,您需要添加一行代碼,以引用 directshow命名空間。在窗體代碼窗口的頂部,將以下代碼添加到所有聲明語句之前:
using quartztypelib;
using語句必須在所有 options 語句(本項目中并未使用)之后,并且在所有其他代碼之前。添加該語句后。
開發應用程序
創建通過 pia 與 framework 連接的 player 控件實例之后,您可以向窗體中添加所需的其他元素,并編寫完成實際操作的代碼。
添加 windows 窗體控件
1. 在 view(視圖)菜單中,單擊 designer(設計器),或者單擊 solution explorer(解決方案資源管理器)中的 view designer(視圖設計器)按鈕,切換到窗體設計器。
2. 在窗體上增加文件、播放、信息等菜單。
3. 在工具箱的 windows forms(windows 窗體)面板中,為您的窗體添加一個工具欄、一個狀態欄和圖片imagelist。
4. 在 properties(屬性)窗口中,將工具欄的名稱更改為 toolbar1,將在buttons上增加4個按鈕。狀態欄的名稱更改為 statusbar1,并分別增加三個panel。
5. 在工具箱的面板中,為您的窗體添加一個面版panel1。
6. 增加一個定時器timer1。
7. 調整控件在窗體中的排列方式,使之符合您的需要而且方便用戶使用。下圖為 visual studio designer(設計器)中完成后的窗體布局。
圖 3
編寫代碼
如何打開你想要媒體文件?
第一步是編寫在 frmplaymedia中打開 windows media 文件的代碼。要自動切換到 code(代碼)視圖并編輯打開菜單的 click 事件處理程序 (menuitem2_click) 的代碼,請雙擊窗體上的“工具欄”按鈕。將以下代碼添加到事件處理程序中:
還記得嗎"文件 -> 打開..." 是的幾乎每個使用windows的人都會這樣操作.如何實現?
很簡單看看下面的代碼:
openfiledialog openfiledialog = new openfiledialog();
openfiledialog.filter = "media files|*.mpg;*.avi;*.wma;*.mov;*.wav;*.mp2;*.mp3|all files|*.*";
if (dialogresult.ok == openfiledialog.showdialog())
{
….
}
看吧很簡單是嗎?記得寫一個函數把它放進去。當你點擊ok按鈕的時候,directshow接口就會得到你想要播放的文件。下圖解釋了它是如何工作的。
directshow為多媒體流回放提供最基本的服務,這些多媒體流可以是本地文件,還可以是服務器傳輸過來的。特別的,directshow可以支持視頻回放,支持以不同的文件和流格式壓縮視頻內容,包括windows media、mpeg、avi和wav。
在directshow的核心處,服務是組件的模塊化集合,稱為過濾器,可以根據媒體類型排列成過濾器圖。過濾器可以操作數據流,如讀入、分析、解碼、格式化或渲染。
過濾器以樹型進行排列,這棵樹稱為過濾器樹,通過過濾器樹管理器(filter graph manager,簡稱fgm)進行管理。使用fgm應用程序可以通過使用microsoft windows media player控件間接控制過濾器樹,還可以通過調用com接口方法直接控制。directshow過濾器樹(參閱圖1)由從源到目標渲染器的有向過濾器序列組成,所有這些通過輸入和輸出過濾器引腳連接。過濾器引腳協商它們將支持哪些媒體類型。fgm控制樹過濾器之間的多媒體數據流。因為directshow有一個靈活的、可重配置的過濾器樹體系結構,因此directshow可以使用同樣的軟件成分支持多種媒體類型的回放和分流。開發人員還可以通過編寫自己的過濾器擴展directshow多媒體支持。
過濾器
過濾器是注冊的directshow類,它執行許多媒體信息處理任務。這些任務包括:
獲得源信息(例如,獲得媒體流)
分析(例如,在流上執行包讀入、分離和格式化)
轉換(例如,解碼wma和mpeg-4音頻和視頻流)
渲染(例如,在適當的時候產生音頻pcm或者視頻rgb/yuv輸出,將數據傳給directsound和directdraw)
過濾器使用幾種類型的接口,例如引腳、計數器、傳送器和時鐘接口,來執行它們的任務。過濾器實現和開放了許多接口。fgm可以使用這些接口創建、連接和控制樹。過濾器經常實現包含下列方法的ibasefilter接口:
運行、停止和暫停過濾器狀態。
恢復過濾器和廠商信息。
得到和設置參考時鐘。
恢復過濾器狀態信息。
枚舉過濾器引線。
重建過濾器樹時定位引腳
用戶單擊“打開”時,這段代碼將顯示一個對話框,供用戶在計算機上瀏覽并選擇要播放的 .wma 或 .wmv 文件。用戶選擇文件(并單擊“確定”)時,代碼將 player 的 url 屬性設置為用戶選擇的文件。由于 player 的 autostart 屬性在默認情況下設置為 true,所以 player 立即打開并播放用戶選擇的數字媒體文件。
接下來,添加播放/暫停按鈕的代碼。在代碼窗口中,在停止、暫停菜單中單擊,然后,在方法名稱列表中單擊 click。將以下代碼添加到 visual c# 為您創建的click 事件處理程序中:
看看下面的代碼是如何實現的:
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;
//
如何來播放,暫停,停止?
簡單這些函數看字面也知道.
//
m_objmediacontrol.run();//播放
m_objmediacontrol.pause();//暫停
m_objmediacontrol.stop();//停止
// 這段代碼非常簡單。當用戶單擊播放/暫停按鈕時,代碼將檢查 player 的 playstate 屬性。如果 player 正在播放數字媒體文件,代碼就會暫停文件的播放; 如果 player 已經暫停或停止,代碼就再次啟動 player 播放文件。
ok,在來看我們是如何控制時間進度的?
//
private void timer1_tick(object sender, system.eventargs e)
{
if (m_currentstatus == mediastatus.running)
{
updatestatusbar();
}
}
看見上面那個 updatestatusbar();這里是讓它沒100ms更新一次狀態欄.
代碼如下:
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";
}
}
還有一個問題程序怎么能夠知道它播放完了?
這會有點麻煩了,想想看有什么辦法呢?對了,windows是消息驅動的。那找找看有什么消息。有的就ec_complete。還記得"wndproc" 它嗎?是的,我的老朋友,這次我們必須要改寫它來捕獲ec_complete消息。這個消息是directshow通知父窗體,播放結束了。
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);
}
只要播放狀態改變,上述代碼就會運行。如果 player 正在播放(用戶打開文件時就處于播放狀態,因為 autostart 設置為 true),代碼將啟用播放/暫停按鈕和停止按鈕,以便用戶執行操作。之后,代碼將播放/暫停按鈕的文字更改為“暫停”,這樣用戶就可以使用該按鈕暫停播放過程。最后,代碼檢索當前數字媒體文件的標題,并更新標題標簽的文字以顯示標題。
如果 player 被暫停(用戶單擊了播放/暫停按鈕),代碼會將播放/暫停按鈕的文字更改為“播放”,以提示用戶使用該按鈕可以恢復播放。
如果 player 被停止(用戶單擊了停止按鈕),代碼將禁用停止按鈕(因 player 已經停止工作)并將播放/暫停按鈕的文字恢復為默認值“播放”。
一切都結束了,現在要做的事就是做些來找一部影片來享受一下自己的成果了.
編寫完示例項目的代碼之后,您可以生成并運行解決方案。
生成解決方案
在 build(生成)菜單中單擊 build solution(生成解決方案)。visual studio 開始編譯并生成項目。如果鍵入內容全部正確,生成過程將順利完成,不會出現任何錯誤。如果生成報告錯誤,則請檢查您的代碼并糾正錯誤。
使用示例應用程序
要在調試器中運行項目,請按鍵盤上的 f5 鍵。如果出現“查看生成的代碼”主題中介紹的未處理的異常,則應該停止調試會話,刪除或注釋掉生成代碼中的相應行,然后再按 f5 鍵。
您可以單擊“打開”查找 .wma 或 .wmv 文件(究竟選擇何種文件,取決于您在“打開”對話框中選擇的文件類型)。選擇某個文件并單擊“確定”之后,“打開”對話框關閉,開始播放數字媒體文件,傳輸控制按鈕的狀態也隨之改變。這時您就可以利用傳輸控制按鈕來暫停、重新開始或完全停止播放。