• 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
    ",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
    ", 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++的调用流程,这里不做过多赘述;

    关于EasyPlayerPro

    EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP、RTMP、HTTP、HLS、UDP、RTP等多种流媒体协议播放、支持本地文件播放,支持本地抓拍、本地录像、播放旋转、多屏播放等多种功能特性,稳定、高效、可靠,支持Windows、Android、iOS三个平台,目前在多家教育、安防、行业型公司,都得到的应用,广受好评!

    EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro

    点击链接加入群【EasyPlayer & EasyPlayerPro】:544917793

    获取更多信息

    邮件:support@easydarwin.org

    WEB:www.EasyDarwin.org

    Copyright © EasyDarwin.org 2012-2017

    EasyDarwin

  • 相关阅读:
    docker基础:docker网络模式
    WEB架构师成长之路之一-走正确的路(转载)
    DDD(领域驱动设计)
    C#泛型和泛型约束(转载)
    MES系统介绍
    vue中 computed和watch的一些简单理解(区别)(转载)
    sqlserver常用表值函数
    SQLServerAgent 当前未运行,因此无法将此操作通知它。
    浅谈敏捷开发(转载)
    认证、授权、鉴权和权限控制(转载)
  • 原文地址:https://www.cnblogs.com/babosa/p/9217771.html
Copyright © 2020-2023  润新知