C#調用libEasyPlayer動態庫,實現RTSP流播放
一、項目背景:
由于一個項目的附加部分,客戶要求實現一個關于視頻流媒體的方面內容,而且沒有經費,且做為項目的附加條款,采購現成的系統,由于經費的問題,不太現實,所以上到開源社區尋找視頻流媒體方面的開源項目,經過一番比較,選中了EasyDarwin。
二、布署服務器端
下載了服務器端的編譯版本直截在本地的Linux服務器上進行了布署。為了方便啟動服務器,寫了一個腳本。
#!/bin/bash #file name start_easydarwin_server.sh sudo ~/EasyDarwin-CentOS-x64-7.0.3-Build15.1130/easydarwin -c ~/EasyDarwin-CentOS-x64-7.0.3-Build15.1130/easydarwin.xml -d
運行后,結果如下:
[janl@svr1 sh]$ ./start_easydarwin_server.sh [sudo] password for janl: WARNING: No module folder exists. INFO: Module Loaded...QTSSFileModule [static] INFO: Module Loaded...QTSSReflectorModule [static] INFO: Module Loaded...EasyRelayModule [static] INFO: Module Loaded...EasyHLSModule [static] INFO: Module Loaded...QTSSAccessLogModule [static] INFO: Module Loaded...QTSSFlowControlModule [static] INFO: Module Loaded...QTSSPosixFileSysModule [static] INFO: Module Loaded...QTSSAdminModule [static] INFO: Module Loaded...QTSSMP3StreamingModule [static] INFO: Module Loaded...QTSSAccessModule [static] WARNING: No users file found at ./qtusers. WARNING: No groups file found at ./qtgroups. Streaming Server done starting up
到這服務器端就能運行了。
三、實現我需要的客戶端:
先看一下最后的運行結果:
從官方下載了EasyClient,這個沒有編譯好的版本,直截下載了源碼,在Win7 x64下用VS2013編譯。
值得注意的一點是,源生下截的代碼EasyClient在編譯時會報錯,提示找不libmp4creator,經過群主幫忙指點,其實
libmp4creator在下邊的EasyPlayer項目中就有,直截Copy到EasyClient項目中就可以了。
后面一切順利,編譯成功,后運行EasyClient可以用了。
四、實現自已想要的客戶端:
EasyClient客戶端雖然不錯,但是并不是我可以交付給客戶的東西,所以實現自已的客戶端就成為主要難點。
EasyClient是用C++編寫的,而我對C++并不熟,憑著多年工作經驗,只能看懂個大概,最優的方案就是調用EasyClient類庫,前端界面用C#重新實現。
廢話不多說了,本著從最容易的著手,就從EasyPlayer著手,從EasyClient目錄,Copy了libEasyPlayer.dll及其它動態庫,新建了c#項目,解決方案。
第一個要解決的是,導出函數的定義,在c#中導入libEasyPlayer.dll的API導出函數,這里不得不說,EasyPlayer的作者把EasyPlayer的導出函,封裝的很清晰:
typedef int (CALLBACK *MediaSourceCallBack)( int _channelId, int *_channelPtr, int _frameType, char *pBuf, RTSP_FRAME_INFO* _frameInfo); LIB_EASYPLAYER_API int EasyPlayer_Init(); LIB_EASYPLAYER_API void EasyPlayer_Release(); LIB_EASYPLAYER_API int EasyPlayer_OpenStream(const char *url, HWND hWnd, RENDER_FORMAT renderFormat, int rtpovertcp, const char *username, const char *password, MediaSourceCallBack callback=NULL, void *userPtr=NULL); LIB_EASYPLAYER_API void EasyPlayer_CloseStream(int channelId); LIB_EASYPLAYER_API int EasyPlayer_SetFrameCache(int channelId, int cache); LIB_EASYPLAYER_API int EasyPlayer_SetShownToScale(int channelId, int shownToScale); LIB_EASYPLAYER_API int EasyPlayer_SetDecodeType(int channelId, int decodeKeyframeOnly); LIB_EASYPLAYER_API int EasyPlayer_SetRenderRect(int channelId, LPRECT lpSrcRect); LIB_EASYPLAYER_API int EasyPlayer_ShowStatisticalInfo(int channelId, int show); LIB_EASYPLAYER_API int EasyPlayer_SetDragStartPoint(int channelId, POINT pt); LIB_EASYPLAYER_API int EasyPlayer_SetDragEndPoint(int channelId, POINT pt); LIB_EASYPLAYER_API int EasyPlayer_ResetDragPoint(int channelId); LIB_EASYPLAYER_API int EasyPlayer_StartManuRecording(int channelId); LIB_EASYPLAYER_API int EasyPlayer_StopManuRecording(int channelId); LIB_EASYPLAYER_API int EasyPlayer_PlaySound(int channelId); LIB_EASYPLAYER_API int EasyPlayer_StopSound();
導入到c#的代碼中,具體就是如這個樣子。
/// Return Type: int [System.Runtime.InteropServices.DllImportAttribute("libEasyPlayer.dll", EntryPoint = "?EasyPlayer_Init@@YAHXZ")] //[DllImport("libEasyPlayer.dll", EntryPoint = "EasyPlayer_Init", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public static extern int EasyPlayer_Init(); /// Return Type: void [System.Runtime.InteropServices.DllImportAttribute("libEasyPlayer.dll", EntryPoint = "?EasyPlayer_Release@@YAXXZ")] public static extern void EasyPlayer_Release();
這里我要提到一個工具,叫Invoke Interop Assistant 這個工具可以幫我將C++的頭件,轉換為c#的導入代碼就是上邊的代碼,這個工具我是在CSDN上下載的,不過有點遺憾的是,最復雜并且帶回調函數的EasyPlayer_OpenStream,無法自動生成,工具報了一個錯誤,具體錯誤信息是:
Error: Error processing procedure EasyPlayer_OpenStream: Expected token of type ParenClose but found ParenOpen instead.
我在Baidu上查了一下,沒有什么有效的解決辦法,而且我也沒有弄清 ParenClose 與ParenOpen是否c++的專用術語或是什么,導出函出的定義方式,總之問題沒有解決。EasyPlayer_OpenStream 和 回調函數 只好手動來碼。
如果誰知道是怎么回事,一定要告訴我一下。
完成的導入函數如下,超長了,貼不上來,我一會傳到群空吧。
程序的調試過程遇到兩個問題要提醒注意一下:
1. 找不到動態庫,明明libEasyPlayer.dll就在可執行目錄,系統提示找不到。經過嘗試后我把項目編譯配置由AnyCPU改為X86后終于不再報找不到動態庫了。
2. 提示找不動態庫的入口點,這個把我郁悶壞了,明明比較和定義一樣,就是提示找不到入口點,后來實在沒辦法了,只好上看雪下了一個Dll導出表查看器,具體的名字叫ExportList,有圖有真相啊!
看到第一行那個函數符號了嗎? 我想可能是因為編譯字符集或者是什么原因引起的吧,照這個定義就能找到入口點了。
如果你有更好的辦法,請不要忘記告訴我一聲。