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

1、項目背景:前端

        因爲一個項目的附加部分,客戶要求實現一個關於視頻流媒體的方面內容,並且沒有經費,且作爲項目的附加條款,採購現成的系統,因爲經費的問題,不太現實,因此上到開源社區尋找視頻流媒體方面的開源項目,通過一番比較,選中了EasyDarwin。c++

2、佈署服務器端git

       下載了服務器端的編譯版本直截在本地的Linux服務器上進行了佈署。爲了方便啓動服務器,寫了一個腳本。github

#!/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

       運行後,結果以下:c#

[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

    到這服務器端就能運行了。bash

3、實現我須要的客戶端:服務器

    先看一下最後的運行結果:tcp

     從官方下載了EasyClient,這個沒有編譯好的版本,直截下載了源碼,在Win7 x64下用VS2013編譯。函數

     值得注意的一點是,源生下截的代碼EasyClient在編譯時會報錯,提示找不libmp4creator,通過羣主幫忙指點,其實工具

libmp4creator在下邊的EasyPlayer項目中就有,直截Copy到EasyClient項目中就能夠了。

    後面一切順利,編譯成功,後運行EasyClient能夠用了。

4、實現自已想要的客戶端:

      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,有圖有真相啊!

 看到第一行那個函數符號了嗎? 我想多是由於編譯字符集或者是什麼緣由引發的吧,照這個定義就能找到入口點了。

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

看到你們找不到這個源碼給個人留言,我首先感謝你們,讓我知道這個東西仍是有一點點用。

爲了方便你們,我把源碼整理了一下,放到了github上,以方便你們下載。

對於給我留言,須要發源碼的朋友,我由於時間有限就不給你們一一回郵件了,請你們到github上去下載吧,在此報歉了。下載地址:

https://github.com/janl99/EasyClient.Net.git

相關文章
相關標籤/搜索