EasyPlayerPro(Windows)開發之跨語言調用

下面我們來講解一下關於EasyPlayerPro接口的調用,主要分爲C++和C#兩種語言,C++也可以基於VC和QT進行開發,C++以VC MFC框架爲例進行講解,C#以Winform框架爲例進行講解。

  1. VC開發EasyPlayerPro
    首先建一個基於MFC Dialog的工程,取名叫EasyPlayerPro,關於界面邏輯的處理過程就不做過多贅述了,大家有興趣的可以去看EasyPlayerPro項目代碼;下面我們講解一下EasyPlayerPro的調用流程:

    (1) 打開一個流或文件進行播放
    通過EasyPlayerPro_Open打開一個流或者本地文件,打開以後即播放,不需要調用EasyPlayerPro_Play方法,調用完成後,注意,比如拉網絡流的時候,由於Open函數是非阻塞而立即返回的,所以,播放過程可能尚未初始化完成,從而獲取流的信息可能獲取不到,正確的做法是在線程或者計時器裏面輪詢獲取;Open完成後,我們可以對一些參數進行設置,比如設置OSD和圖片疊加,顯示模式,音量大小等:

    // player open file
    m_player = EasyPlayerPro_Open(str, m_stcVideoWnd->GetSafeHwnd());
    if (m_player)
    {
        m_bPlayPause = FALSE;
        SetTimer(TIMER_ID_PROGRESS, 1000, NULL);

        m_bOpening = TRUE;

        //字幕和圖片疊加
        //
        //  EasyPlayerPro_SetLogo  設置臺標/LOGO
        //      player              - 指向 EasyPlayerPro_Open 返回的 player 對象
        //      bIsUse              - 是否使用水印 1=啓用 0=不啓用
        //      ePos                - 臺標位置:1==leftttop 2==righttop 3==leftbottom 4==rightbottom
        //      eStyle              -  水印的風格,見WATERMARK_ENTRY_TYPE聲明
        //      x                   - 水印左上角位置x座標
        //      y                   - 水印左上角位置y座標
        //      width               - 寬
        //      height              - 高
        //      logopath            - 水印圖片路徑
        EasyPlayerPro_SetLogo (m_player, 1, 2, 3, 
            0, 0, 0, 0, "C:\\Dingshuai\\Project\\Easylogo.png");

        //  EasyPlayerPro_SetOSD  設置疊加字幕
        //      player              - 指向 EasyPlayerPro_Open 返回的 player 對象
        //      bIsUse              - 是否使用水印 1=啓用 0=不啓用 -1=刪除
        //      nMoveType           - 移動類型:0--固定位置,1--從左往右,2--從右往左,
        //      R,G,B               - 字體顏色對應三個分量紅綠藍0-255
        //      x                   - 字幕顯示左上角位置x座標
        //      y                   - 字幕顯示左上角位置y座標
        //      weight              - 字體權重,見如下聲明
        // /* Font Weights */
        // #define FW_DONTCARE         0
        // #define FW_THIN             100
        // #define FW_EXTRALIGHT       200
        // #define FW_LIGHT            300
        // #define FW_NORMAL           400
        // #define FW_MEDIUM           500
        // #define FW_SEMIBOLD         600
        // #define FW_BOLD             700
        // #define FW_EXTRABOLD        800
        // #define FW_HEAVY            900
        // #define FW_ULTRALIGHT       FW_EXTRALIGHT
        // #define FW_REGULAR          FW_NORMAL
        // #define FW_DEMIBOLD         FW_SEMIBOLD
        // #define FW_ULTRABOLD        FW_EXTRABOLD
        // #define FW_BLACK            FW_HEA
        //      width               - 寬
        //      height              - 高
        //      fontname            - 字體名稱,如“宋體”“楷體”“隸書”“華文行楷”......
        //      tittleContent       - OSD顯示內容
        EasyPlayerPro_SetOSD (m_player, 1, 1, 0, 255, 0,
            700, 100, 200, 0, -29, "隸書", "你說你愛了不該愛的人,你的心中滿是傷痕!");
    }

(2) 暫停和單步播放

void CplayerDlg::OnBnClickedBtnPause()
{
    // TODO: 在此添加控件通知處理程序代碼
    if (!m_bPlayPause) EasyPlayerPro_Pause(m_player);
    else EasyPlayerPro_Play(m_player);
    m_bPlayPause = !m_bPlayPause;
    CSkinButton* pBtn = (CSkinButton*)GetItemByName(_T("Pause"));
    if(pBtn)
    {
        if (m_bPlayPause)
        {
            pBtn->SetBtnText(_T("播放"));
        }   
        else
        {
            pBtn->SetBtnText(_T("暫停"));
        }
    }
}

void CplayerDlg::OnBnClickedBtnPlayByFrame()
{
    // TODO: 在此添加控件通知處理程序代碼
    // 
    EasyPlayerPro_StepPlay(m_player);
    m_bPlayPause = TRUE;
    CSkinButton* pBtn = (CSkinButton*)GetItemByName(_T("Pause"));
    if(pBtn)
    {
        if (m_bPlayPause)
        {
            pBtn->SetBtnText(_T("播放"));
        }   
        else
        {
            pBtn->SetBtnText(_T("暫停"));
        }
    }
}

這裏直接調用即可,不做過多贅述。

(3) 快放和慢放

void CplayerDlg::OnBnClickedBtnRatePlay()
{

    int nRate = 0;
    switch(m_speedRate)
    {
    case    SPEED_SLOW_X4:
        nRate = 25;
        break;
    case    SPEED_SLOW_X2:
        nRate = 50;
        break;
    case    SPEED_NORMAL:   
        nRate = 100;
        break;
    case    SPEED_FAST_X2:
        nRate = 200;
        break;
    case    SPEED_FAST_X4:
        nRate = 300;
        break;
    case    SPEED_FAST_X8:
        nRate = 400;
        break;
    case    SPEED_FAST_X16:
        nRate = 500;
        break;
    case    SPEED_FAST_X64:
        nRate = 600;
        break;

    }
    EasyPlayerPro_Setparam(m_player, EASY_PARAM_PLAY_SPEED, &nRate);
}

目前定義慢放範圍爲2倍和4倍,快放範圍爲2,4,8,16,64倍,超過這個範圍則無明顯反應或者意義。

(4) 抓圖接口調用

void CplayerDlg::OnBnClickedBtnSnapshot()
{
    // TODO: 在此添加控件通知處理程序代碼
    // 
    TCHAR sPath[512];
    memset(sPath, 0x00, sizeof(TCHAR) * 512);
    GetWorkDirectory(sPath, 512);

    int nPathLen = _tcslen(sPath);

    if ((sPath[nPathLen - 1] != '/' && sPath[nPathLen - 1] != '\\'))
    {
        sPath[nPathLen] = '\\';
    }

    unsigned int timestamp = (unsigned int)time(NULL);
    time_t tt = timestamp;
    struct tm _time;
    ::localtime_s(&_time, &tt);
    char szTime[64] = { 0, };
    strftime(szTime, 32, "\\pic_%Y%m%d%H%M%S.jpg", &_time);

    CString strTime = (CString)szTime;

    CString sScreenPath = _T("");
    sScreenPath.Format(_T("%s%s"), sPath, _T("ScreenShot"));
    bool bSec = EnsureDirExist(sScreenPath);
    sScreenPath += strTime;

    USES_CONVERSION;

    EasyPlayerPro_Snapshot(m_player, T2A(sScreenPath), 0, 0, 1000);

}

抓圖接口直接調用即可,注意保存的路徑需要存在,否則,抓圖保存將會失敗。

(5) 錄像接口調用

void CplayerDlg::OnBnClickedBtnRecord()
{
    // TODO: 在此添加控件通知處理程序代碼
    if(!m_player)
        return ;
    CSkinButton* pBtn = (CSkinButton*)GetItemByName(_T("Record"));
    if (!pBtn)
    {
        return;
    }

    if (!m_bRecording)
    {
        pBtn->SetBtnText(_T("停止錄像"));


        TCHAR sPath[512];
        memset(sPath, 0x00, sizeof(TCHAR)*512);
        GetWorkDirectory(sPath, 512);

        int nRecordPathLen = _tcslen(sPath);

        if ((sPath[nRecordPathLen - 1] != '/' && sPath[nRecordPathLen - 1] != '\\'))
        {
            sPath[nRecordPathLen] = '\\';
        }

        unsigned int timestamp = (unsigned int)time(NULL);
        time_t tt = timestamp;
        struct tm _time;
        ::localtime_s(&_time, &tt);
        char szTime[64] = { 0, };
        strftime(szTime, 32, "\\record_%Y%m%d%H%M%S.mp4", &_time);

        CString strTime = (CString)szTime;

        CString sRecordPath = _T("");
        sRecordPath.Format(_T("%s%s"), sPath, _T("Record"));
        bool bSec = EnsureDirExist(sRecordPath);
        sRecordPath += strTime;

        UpdateData(TRUE);
        CString sRecDuration = _T("");
        if(m_editRecPieceTime)
            m_editRecPieceTime->GetWindowText(sRecDuration);
        int nDuration =  _ttoi( sRecDuration.GetBuffer());

        //m_SNPlayOcx.EasyPlayPro_PlayOcx_Record(sRecordPath, m_sRtspUrl, nDuration);
        //m_SNPlayOcx.EasyPlayPro_PlayOcx_Record(_T("D:\\test.mp4"), m_sRtspUrl);
        USES_CONVERSION;
        EasyPlayerPro_Record(m_player, T2A(sRecordPath), nDuration);

        m_lRecordTime = 0;//IDC_STATIC_RECORD_STATUS
        SetTimer(TIMER_RECORD_STATUS, 300, NULL);
    } 
    else
    {
        pBtn->SetBtnText(_T("錄像"));
        EasyPlayerPro_Stoprecord(m_player);

        KillTimer(TIMER_RECORD_STATUS);

        EasyPlayerPro_Getparam(m_player, EASY_PARAM_RECORD_TIME, &m_lRecordTime);
        EasyPlayerPro_Getparam(m_player, EASY_PARAM_RECORD_PIECE_ID, &m_lRecordSliceUp);
        int thh, tmm, tss = 0;
        thh = m_lRecordTime / 3600;
        tmm = (m_lRecordTime % 3600) / 60;
        tss = (m_lRecordTime % 60);

        CString sShowRec = _T("");
        if (m_lRecordSliceUp > -1)
            sShowRec.Format(_T("錄像已停止 錄製時間:%02d:%02d:%02d  切片ID:%d"), thh, tmm, tss, m_lRecordSliceUp);
        else
            sShowRec.Format(_T("錄像已停止 錄製時間:%02d:%02d:%02d"), thh, tmm, tss);

        SetString(4, sShowRec);

        m_lRecordTime = 0;//IDC_STATIC_RECORD_STATUS
    }
    m_bRecording = !m_bRecording;
}

EasyPlayPro_PlayOcx_Record接口調用進行錄像,EasyPlayerPro_Stoprecord接口調用停止錄像,EasyPlayerPro_Getparam接口獲取錄像的時間和當前錄像的PieceId, 具體參數見上一篇文章EasyPlayerPro接口說明

(6) 本地文件和點播拖拽

 a. 進度顯示計時
    case TIMER_ID_PROGRESS://進度條計時器
        {
#if 1
            if (m_totalDuration <= 0)
            {
                LONGLONG ltotal = 0;
                EasyPlayerPro_Getparam(m_player, EASY_PARAM_MEDIA_DURATION, &ltotal);
                if (ltotal>1)
                {
                    m_totalDuration = ltotal/1000;
                    int totalSeconds = (int)m_totalDuration;
                    int gTotalSeconds = totalSeconds;
                    int gTotalMinute = (int)(totalSeconds / 60);
                    int nTotalHour = (int)(gTotalMinute / 60);  //時
                    int nTotalMinute = (int)(gTotalMinute % 60);//分
                    int totalSecond = (int)(totalSeconds % 60); //秒

                    m_strPlayFileTime.Format(_T("%02d:%02d:%02d"), nTotalHour, nTotalMinute, totalSecond);
                    if (m_sliderPlay)
                    {
                        m_sliderPlay->SetRange(0, m_totalDuration);
                        m_sliderPlay->SetPos(0);                    
                    }                       
                    m_sliderPlay->EnableWindow(TRUE);
                }
            }

            LONGLONG llCurPos   = 0;    
            LONGLONG llPos  = 0;    
            EasyPlayerPro_Getparam(m_player, EASY_PARAM_MEDIA_POSITION, &llPos);
            llCurPos = llPos/1000;
            TRACE("Position == %d\r\n",llCurPos);
            int totalSeconds = (int)llCurPos;
            int gTotalSeconds = totalSeconds;
            int gTotalMinute = (int)(totalSeconds / 60);
            int nTotalHour = (int)(gTotalMinute / 60);  //時
            int nTotalMinute = (int)(gTotalMinute % 60);//分
            int totalSecond = (int)(totalSeconds % 60); //秒
            CString strTemp = _T("");

            if (m_totalDuration>0  )
            {
                if (llCurPos<m_totalDuration)
                {
                    strTemp.Format(_T("%02d:%02d:%02d/%s"), nTotalHour, nTotalMinute, totalSecond, m_strPlayFileTime);
                    if (m_sliderPlay)
                    {
                        m_sliderPlay->SetPos(llCurPos);
                    }
                } 
                else
                {
#if 0
                    KillTimer(TIMER_ID_PROGRESS);
                    PlayerCloseFile();
                    SetString(2,_T(""));
                    m_totalDuration = -1;
                    m_sliderPlay->SetRange(0, 2000);
                    m_sliderPlay->SetPos(0);    
                    m_speedRate = 0;
#endif
                    OnBnClickedBtnClose();
                    strTemp = _T("");
                }
            }
            else
                strTemp.Format(_T("%02d:%02d:%02d/../../.."), nTotalHour, nTotalMinute, totalSecond);
            SetString(2,strTemp);
#endif
        }
        break;

b. 拖拽進度條OnHScroll消息處理

    if (m_sliderPlay==pSliderTmp)
    {
        if (nSBCode == 5)
        {
            int nPos = m_sliderPlay->GetPos();
            TRACE("nPos==%d\r\n", nPos);
            //如果處於斷點循環
#if 0   
            if (m_bLoopAB)
            {
                if(nPos<m_dbBreakPtA || nPos>m_dbBreakPtB)
                {   
                    nPos = m_dbBreakPtA;
                }
            }
#endif
            if (m_totalDuration>0)
            {                       
                EasyPlayerPro_Seek(m_player, nPos*1000);
            }
        }
    }

c. 音量調節進度條OnHScroll消息處理

    else if (m_sliderSound == pSliderTmp)//音量調節
    {
        int nValue = m_sliderSound->GetPos();
        nValue -= 255;
        EasyPlayerPro_Setparam(m_player, EASY_PARAM_AUDIO_VOLUME, &nValue);
    }
  1. C#開發EasyPlayerPro

C#我真不擅長,故此,只對libEasyPlayerPro的調用做簡單介紹;
首先,創建一個Winform程序(類似於MFC的Dialog程序),然後導入 libeasyplayerpro.dll,生成實體類,即可調用接口。
(1) libeasyplayerpro.dll接口類化
導入dll,生產類,聲明需要用到的參數列表如下:

        public enum tagEASY_PARAM_ID
        {
            //++ public
            // duration & position
            PARAM_MEDIA_DURATION = 0x1000,
            PARAM_MEDIA_POSITION,

            // media detail info
            PARAM_VIDEO_WIDTH,
            PARAM_VIDEO_HEIGHT,

            // video display mode
            PARAM_VIDEO_MODE,

            // audio volume control
            PARAM_AUDIO_VOLUME,

            // playback speed control
            PARAM_PLAY_SPEED,

            // video decode thread count
            PARAM_DECODE_THREAD_COUNT,

            // visual effect mode
            PARAM_VISUAL_EFFECT,

            // audio/video sync diff
            PARAM_AVSYNC_TIME_DIFF,

            // player event callback
            PARAM_PLAYER_CALLBACK,

            // audio/video stream
            PARAM_AUDIO_STREAM_TOTAL,
            PARAM_VIDEO_STREAM_TOTAL,
            PARAM_SUBTITLE_STREAM_TOTAL,
            PARAM_AUDIO_STREAM_CUR,
            PARAM_VIDEO_STREAM_CUR,
            PARAM_SUBTITLE_STREAM_CUR,
            //-- public

            //++ for adev
            PARAM_ADEV_RENDER_TYPE = 0x2000,
            //-- for adev

            //++ for vdev
            PARAM_VDEV_RENDER_TYPE = 0x3000,
            PARAM_VDEV_FRAME_RATE,
            //-- for vdev

            //++ for render
            PARAM_RENDER_UPDATE = 0x4000,
            PARAM_RENDER_START_PTS,
            //-- for render
        };

聲明Easyplayerpro接口如下:

        //初始化播放視頻
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Open", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr EasyPlayerPro_Open(string file, IntPtr hwnd);

        //關閉視頻
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Close", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Close(IntPtr player);

        //播放視頻
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Play", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Play(IntPtr player);

        //單針播放視頻
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_StepPlay", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_StepPlay(IntPtr player);

        //暫停視頻
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Pause", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Pause(IntPtr player);

        //設置時長
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Seek", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Seek(IntPtr player, long ms);

        //設置窗口
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Resize", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Resize(IntPtr player, int type, int x, int y, int w, int h);

        //截圖
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Snapshot", CallingConvention = CallingConvention.Cdecl)]
        static extern int EasyPlayerPro_Snapshot(IntPtr player, string file, int w, int h, int wait);

        //設置參數
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Setparam", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Setparam(IntPtr player, uint id, ref IntPtr param);

        //得到參數
        [DllImport("libEasyplayerpro.dll", EntryPoint = "EasyPlayerPro_Getparam", CallingConvention = CallingConvention.Cdecl)]
        static extern void EasyPlayerPro_Getparam(IntPtr player, uint id, ref IntPtr param);

聲明一個指針變量用於存放播放器指針:
private IntPtr mPlayer;
創建一個按鈕,點擊消息處理:

    private void button1_Click(object sender, EventArgs e)
        {                                                     EasyPlayerPro_Open("rtmp://live.hkstv.hk.lxdns.com/live/hks", panel1.Handle);
        }

其中,panel1是創建的一個pannel,用於顯示視頻的窗口;
這樣,其他接口調用也類似,具體可參考C++的調用流程,這裏不做過多贅述;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章