C#調用libEasyPlayer動態庫,實現RTSP流播放

jopen 8年前發布 | 58K 次閱讀 .NET開發

一、項目背景:

        由于一個項目的附加部分,客戶要求實現一個關于視頻流媒體的方面內容,而且沒有經費,且做為項目的附加條款,采購現成的系統,由于經費的問題,不太現實,所以上到開源社區尋找視頻流媒體方面的開源項目,經過一番比較,選中了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,有圖有真相啊!

 看到第一行那個函數符號了嗎? 我想可能是因為編譯字符集或者是什么原因引起的吧,照這個定義就能找到入口點了。

如果你有更好的辦法,請不要忘記告訴我一聲。

來自: http://my.oschina.net/janl/blog/599852

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!