SkeyeExPlayer(Windows)开发之跨语言调用

2023-04-17 10:53:24 浏览数 (1)

下面我们来讲解一下关于SkeyeExPlayer接口的调用,主要分为C 和C#两种语言,C 也可以基于VC和QT进行开发,C 以VC MFC框架为例进行讲解,C#以Winform框架为例进行讲解。

  1. VC开发SkeyeExPlayer 首先建一个基于MFC Dialog的工程,取名叫SkeyeExPlayer,关于界面逻辑的处理过程就不做过多赘述了,大家有兴趣的可以去看SkeyeExPlayer项目代码;下面我们讲解一下SkeyeExPlayer的调用流程:
代码语言:txt复制
(1) 打开一个流或文件进行播放
代码语言:txt复制
通过SkeyeExPlayer_Open打开一个流或者本地文件,打开以后即播放,不需要调用SkeyeExPlayer_Play方法,调用完成后,注意,比如拉网络流的时候,由于Open函数是非阻塞而立即返回的,所以,播放过程可能尚未初始化完成,从而获取流的信息可能获取不到,正确的做法是在线程或者计时器里面轮询获取;Open完成后,我们可以对一些参数进行设置,比如设置OSD和图片叠加,显示模式,音量大小等:
代码语言:txt复制
    // 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) 暂停和单步播放

代码语言:txt复制
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) 快放和慢放

代码语言:txt复制
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) 抓图接口调用

代码语言:txt复制
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) 录像接口调用

代码语言:txt复制
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("录像已停止 录制时间:d:d:d  切片ID:%d"), thh, tmm, tss, m_lRecordSliceUp);
		else
			sShowRec.Format(_T("录像已停止 录制时间:d:d:d"), 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) 本地文件和点播拖拽

代码语言:txt复制
 a. 进度显示计时
代码语言:txt复制
    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("d:d:d"), 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 == %drn",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("d:d:d/%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("d:d:d/../../.."), nTotalHour, nTotalMinute, totalSecond);
			SetString(2,strTemp);
#endif
		}
        break;

b. 拖拽进度条OnHScroll消息处理

代码语言:txt复制
	if (m_sliderPlay==pSliderTmp)
	{
		if (nSBCode == 5)
		{
			int nPos = m_sliderPlay->GetPos();
			TRACE("nPos==%drn", 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消息处理

代码语言:txt复制
	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,生产类,声明需要用到的参数列表如下:

代码语言:txt复制
        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接口如下:

代码语言:txt复制
        //初始化播放视频
        [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);

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

代码语言:txt复制
    private IntPtr mPlayer;

创建一个按钮,点击消息处理:

代码语言:txt复制
	private void button1_Click(object sender, EventArgs e)
	    {							                          SkeyeExPlayer_Open("rtmp://live.hkstv.hk.lxdns.com/live/hks", panel1.Handle);
        }

其中,panel1是创建的一个pannel,用于显示视频的窗口;

这样,其他接口调用也类似,具体可参考C 的调用流程,这里不做过多赘述;

0 人点赞