乐趣区

关于c++:SkeyeExPlayerWindows开发之跨语言调用

上面咱们来解说一下对于 SkeyeExPlayer 接口的调用,次要分为 C ++ 和 C# 两种语言,C++ 也能够基于 VC 和 QT 进行开发,C++ 以 VC MFC 框架为例进行解说,C# 以 Winform 框架为例进行解说。

  1. VC 开发 SkeyeExPlayer
    首先建一个基于 MFC Dialog 的工程,取名叫 SkeyeExPlayer,对于界面逻辑的处理过程就不做过多赘述了,大家有趣味的能够去看 SkeyeExPlayer 我的项目代码;上面咱们解说一下 SkeyeExPlayer 的调用流程:

    (1) 关上一个流或文件进行播放
    通过 SkeyeExPlayer_Open 关上一个流或者本地文件,关上当前即播放,不须要调用 SkeyeExPlayer_Play 办法,调用实现后,留神,比方拉网络流的时候,因为 Open 函数是非阻塞而立刻返回的,所以,播放过程可能尚未初始化实现,从而获取流的信息可能获取不到,正确的做法是在线程或者计时器外面轮询获取;Open 实现后,咱们能够对一些参数进行设置,比方设置 OSD 和图片叠加,显示模式,音量大小等:

     // player open file
     m_player = SkeyeExPlayer_Open(str, m_stcVideoWnd->GetSafeHwnd());
     if (m_player)
     {
         m_bPlayPause = FALSE;
         SetTimer(TIMER_ID_PROGRESS, 1000, NULL);
    
         m_bOpening = TRUE;
    
         // 字幕和图片叠加
         //
         //     SkeyeExPlayer_SetLogo  设置台标 /LOGO
         //         player                - 指向 SkeyeExPlayer_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            - 水印图片门路
         SkeyeExPlayer_SetLogo (m_player, 1, 2, 3, 
             0, 0, 0, 0, "C:\\Dingshuai\\Project\\Skeyelogo.png");
    
         //     SkeyeExPlayer_SetOSD  设置叠加字幕
         //         player                - 指向 SkeyeExPlayer_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 显示内容
         SkeyeExPlayer_SetOSD (m_player, 1, 1, 0, 255, 0,
             700, 100, 200, 0, -29, "隶书", "你说你爱了不该爱的人,你的心中满是创痕!");
     }

    (2) 暂停和单步播放

void CplayerDlg::OnBnClickedBtnPause()
{
    // TODO: 在此增加控件告诉解决程序代码
    if (!m_bPlayPause) SkeyeExPlayer_Pause(m_player);
    else SkeyeExPlayer_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: 在此增加控件告诉解决程序代码
    // 
    SkeyeExPlayer_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;
    
    }
    SkeyeExPlayer_Setparam(m_player, Skeye_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;

    SkeyeExPlayer_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.SkeyePlayPro_PlayOcx_Record(sRecordPath, m_sRtspUrl, nDuration);
        //m_SNPlayOcx.SkeyePlayPro_PlayOcx_Record(_T("D:\\test.mp4"), m_sRtspUrl);
        USES_CONVERSION;
        SkeyeExPlayer_Record(m_player, T2A(sRecordPath), nDuration);

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

        KillTimer(TIMER_RECORD_STATUS);

        SkeyeExPlayer_Getparam(m_player, Skeye_PARAM_RECORD_TIME, &m_lRecordTime);
        SkeyeExPlayer_Getparam(m_player, Skeye_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;
}

SkeyePlayPro_PlayOcx_Record 接口调用进行录像,SkeyeExPlayer_Stoprecord 接口调用进行录像,SkeyeExPlayer_Getparam 接口获取录像的工夫和以后录像的 PieceId, 具体参数见上一篇文章 SkeyeExPlayer 接口阐明。

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


 a. 进度显示计时 
    case TIMER_ID_PROGRESS:// 进度条计时器
        {
#if 1
            if (m_totalDuration <= 0)
            {
                LONGLONG ltotal = 0;
                SkeyeExPlayer_Getparam(m_player, Skeye_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;    
            SkeyeExPlayer_Getparam(m_player, Skeye_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)
            {SkeyeExPlayer_Seek(m_player, nPos*1000);
            }
        }
    }

c. 音量调节进度条 OnHScroll 音讯解决

    else if (m_sliderSound == pSliderTmp)// 音量调节
    {int nValue = m_sliderSound->GetPos();
        nValue -= 255;
        SkeyeExPlayer_Setparam(m_player, Skeye_PARAM_AUDIO_VOLUME, &nValue);
    }
  1. C# 开发 SkeyeExPlayer

C# 我真不善于,故此,只对 libSkeyeExPlayer 的调用做简略介绍;
首先,创立一个 Winform 程序(相似于 MFC 的 Dialog 程序),而后导入 libSkeyeExPlayer.dll,生成实体类,即可调用接口。
(1) libSkeyeExPlayer.dll 接口类化
导入 dll,生产类,申明须要用到的参数列表如下:

        public enum tagSkeye_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
        };

申明 SkeyeExPlayer 接口如下:

        // 初始化播放视频
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Open", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr SkeyeExPlayer_Open(string file, IntPtr hwnd);

        // 敞开视频
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Close", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Close(IntPtr player);

        // 播放视频
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Play", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Play(IntPtr player);

        // 单针播放视频
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_StepPlay", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_StepPlay(IntPtr player);

        // 暂停视频
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Pause", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Pause(IntPtr player);

        // 设置时长
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Seek", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Seek(IntPtr player, long ms);

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

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

        // 设置参数
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Setparam", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Setparam(IntPtr player, uint id, ref IntPtr param);

        // 失去参数
        [DllImport("libSkeyeExPlayer.dll", EntryPoint = "SkeyeExPlayer_Getparam", CallingConvention = CallingConvention.Cdecl)]
        static extern void SkeyeExPlayer_Getparam(IntPtr player, uint id, ref IntPtr param);

申明一个指针变量用于寄存播放器指针:

    private IntPtr mPlayer;

创立一个按钮,点击音讯解决:

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

其中,panel1 是创立的一个 pannel,用于显示视频的窗口;
这样,其余接口调用也相似,具体可参考 C ++ 的调用流程,这里不做过多赘述;

退出移动版