C# 视频监控系列(13):H264播放器——控制播放和截图
前言
本该把这部分和上一篇合成一篇的,无奈挣扎半天,还是想对称起来,客户端3篇、服务器端3篇——所有播放器也勉强凑3篇吧(封装API的文章不算) : )
注意
本系列文章限于学习交流,注重过程,由于涉及公司,所以不提供源代码下载,非常抱歉!!但是请大家放心,核心、实现以及其他能够贴出来的代码我都会贴出来,并且争取尽所能的回答留言里的每一个问题,感谢大家关注,欢迎交流 :)
系列
5. C# 视频监控系列(5):客户端——给服务器端发送字符串和录像(数据捕获)
6. C# 视频监控系列(6):服务器端——封装API(上) [HikServer.dll]
7. C# 视频监控系列(7):服务器端——封装API(下) [DS40xxSDK.dll]
8. C# 视频监控系列(8):服务器端——预览和可被客户端连接
9. C# 视频监控系列(9):服务器端——数据捕获(抓图 + 录像)
10. C# 视频监控系列(10):服务器端——验证、设置画面质量、字幕叠加、板卡序列号
11. C# 视频监控系列(11):H264播放器——封装API[HikPlayM4.dll]
12. C# 视频监控系列(12):H264播放器——播放录像文件
13. C# 视频监控系列(13):H264播放器——控制播放和截图
正文
一、控制播放
1.1 暂停/播放/停止
VC++ Code:
// Funtion:Play or change the play speed to normal;
////////////////////////////////////////////////////////////////////////////// /
void CPlayerDlg::OnPlay()
{
// TODO: Add your control notification handler code here
Play();
}
void CPlayerDlg::Play()
{
m_nSpeed= 0 ;
OnThrow0();
// #ifdef _TEST_CALLBACK
if (m_bConvert)
Hik_PlayM4_SetDecCallBack(PORT,DecCBFun);
else
m_pMainMenu -> EnableMenuItem(ID_FILE_CLOSE, FALSE);
// #endif
if (m_bPlaying)
{
Hik_PlayM4_Play(PORT,GetDlgItem(IDC_SHOW) -> m_hWnd);
}
else
{
if (m_bStreamType)
{
::SetFilePointer(m_hStreamFile,m_nHeadSize, 0 ,FILE_BEGIN);
Hik_PlayM4_ResetSourceBuffer(PORT);
SetEvent(m_hEventInput);
}
m_bPlaying = Hik_PlayM4_Play(PORT,GetDlgItem(IDC_SHOW) -> m_hWnd);
m_bSound=Hik_PlayM4_PlaySound(PORT);
if (m_bPlaying)
SetTimer(PLAY_TIMER, 500 ,NULL);
}
if (m_bPlaying)
SetPlayState();
else
{
CString csError;
csError.Format( " Play the file faild.(%d) " ,Hik_PlayM4_GetLastError(PORT));
AfxMessageBox(csError);
}
}
//////////////////////////////////////////////////////////////////////////////
// Funtion:pause.
//////////////////////////////////////////////////////////////////////////////
void CPlayerDlg::OnPause()
{
// TODO: Add your control notification handler code here
if (m_bPlaying)
{
m_bPause=!m_bPause;
Pause(m_bPause);
}
}
void CPlayerDlg::Pause(BOOL bPause)
{
if (m_bPaused == bPause)
return;
m_bPaused=bPause;
Hik_PlayM4_Pause(PORT,bPause);
TRACE( " PAUSE %d\n " ,m_bPaused);
}
/////////////////////////////////////////////////////////////////////////// //
// Function: Stop
/////////////////////////////////////////////////////////////////////////// //
void CPlayerDlg::OnStop()
{
// TODO: Add your control notification handler code here
if (m_bPlaying)
{
Stop();
}
if (m_bConvert)
{
if (outFile!=NULL)
closeWriffFiles();
if (yuvBuf!=NULL)
{
free(yuvBuf);
yuvBuf=NULL;
}
m_bConvert= 0 ;
//
}
}
void CPlayerDlg::Stop()
{
CButton *pButton;
if (!m_bPlaying)
return;
KillTimer(PLAY_TIMER);
if (Hik_PlayM4_StopSound())
{
m_bSound=FALSE;
pButton = (CButton *)GetDlgItem(IDC_SOUND);
pButton -> SetIcon(m_hSoundStopIcon);
}
// continue before stop.Add by lgl at 9-19;
m_bPause=FALSE;
// stop
m_bPlaying = !Hik_PlayM4_Stop(PORT);
if (!m_bPlaying)
{
SetStopState();
if (m_bStreamType)
ResetEvent(m_hEventInput);
}
}
C# Code:
private bool isPause;
/// <summary>
/// 播放
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPlay_Click( object sender, EventArgs e)
{
if ( ! string .IsNullOrEmpty(m_strPlayFileName))
{
// 是否暂停->播放
if (isPause)
{
HikPlayer.Hik_PlayM4_Pause(PORT, false );
isPause = false ;
}
else
OpenFile();
}
}
/// <summary>
/// 暂停
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPause_Click( object sender, EventArgs e)
{
HikPlayer.Hik_PlayM4_Pause(PORT, true );
isPause = true ;
}
/// <summary>
/// 停止
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStop_Click( object sender, EventArgs e)
{
HikPlayer.Hik_PlayM4_Stop(PORT);
HikPlayer.Hik_PlayM4_CloseFile(PORT);
HikPlayer.Hik_PlayM4_RealeseDDraw();
pVideo.Invalidate( true );
}
代码说明:
1. 关于变量PORT、m_strPlayFileName和方法OpenFile可以看上篇文章的代码。
2. 注意Hik_PlayM4_Pause的第二个参数用法。
1.2 快进/慢进
VC++ Code:
// Funtion: Fast
//////////////////////////////////////////////////////////////////////////////
void CPlayerDlg::OnFastForward()
{
// TODO: Add your control notification handler code here
// Throw B-Frame ,improve the performance;
if (Hik_PlayM4_Fast(PORT))
{
m_nSpeed ++ ;
if (m_nSpeed > 0 )
OnThrow2();
SetFastForwardState();
}
}
//////////////////////////////////////////////////////////////////////////////
// Funtion: Slow;
//////////////////////////////////////////////////////////////////////////////
void CPlayerDlg::OnFastBackward()
{
// TODO: Add your control notification handler code here
if (Hik_PlayM4_Slow(PORT))
{
m_nSpeed -- ;
if (m_nSpeed <= 0 )
OnThrow0();
SetFastBackWardState();
}
}
C# Code:
/// <summary>
/// 快进
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnFastForward_Click( object sender, EventArgs e)
{
if (HikPlayer.Hik_PlayM4_Fast(PORT))
{
m_nSpeed ++ ;
if (m_nSpeed > 0 )
OnThrow2();
}
}
/// <summary>
/// 慢放
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnFastBackward_Click( object sender, EventArgs e)
{
// 慢速播放
if (HikPlayer.Hik_PlayM4_Slow(PORT))
{
// timer1.Interval
m_nSpeed -- ;
if (m_nSpeed <= 0 )
OnThrow0();
}
}
public void OnThrow0()
{
HikPlayer.Hik_PlayM4_ThrowBFrameNum(PORT, 0 );
}
public void OnThrow2()
{
HikPlayer.Hik_PlayM4_ThrowBFrameNum(PORT, 2 );
}
代码说明:
1. 注意关于这两个函数API的说明:
Hik_PlayM4_Fast:快速播放,每次调用将使当前播放速度加快一倍,最多调用4次;要恢复正常播放调用Hik_PlayM4_Play(),从当前位置开始正常播放。
Hik_PlayM4_Slow:慢速播放,每次调用将使当前播放速度慢一倍;最多调用4次;要恢复正常播放调用Hik_PlayM4_Play。
1.3 开始/末尾
VC++ Code:
// Funtion:Locate to the file head.
//////////////////////////////////////////////////////////////////////////////
void CPlayerDlg::OnGotoStart()
{
// TODO: Add your control notification handler code here
if (m_bFileRefCreated)
Hik_PlayM4_SetCurrentFrameNum(PORT, 0 );
else
Hik_PlayM4_SetPlayPos(PORT, 0 );
}
////////////////////////////////////////////////////////////////////////////// /
// Funtion:Locate to the end.
//////////////////////////////////////////////////////////////////////////////
void CPlayerDlg::OnGotoEnd()
{
// TODO: Add your control notification handler code here
if (m_bFileRefCreated)
{
// Note: May create many WM_FILE_END message. The best way is to synchronize the option;
int nEndFrame = m_nTotalFrames;
while ( ! Hik_PlayM4_SetCurrentFrameNum(PORT,nEndFrame -- ))
{
// TRACE("FrameNum is :%d\n",nEndFrame);
if (nEndFrame == 0 )
break ;
}
}
else
Hik_PlayM4_SetPlayPos(PORT, 1 );
}
C# Code:
/// 开始位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnGotoStart_Click( object sender, EventArgs e)
{
HikPlayer.Hik_PlayM4_SetPlayPos(PORT, 0 );
}
/// <summary>
/// 末尾位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnGotoEnd_Click( object sender, EventArgs e)
{
HikPlayer.Hik_PlayM4_SetPlayPos(PORT, 1 );
}
代码说明:
1. 注意Hik_PlayM4_SetPlayPos的第二个参数取值范围是0-1之间,即可以理解0是开始位置,1是结束位置;但是有一点比较奇怪,每次都会延迟3秒,即到末尾后还播放3秒钟!
二、截图
VC++ Code:
// Function:The call back funtion for capture image!
/////////////////////////////////////////////////////////////// //
void CALLBACK DisplayCBFun( long nPort,\
char * pBuf, long nSize,\
long nWidth, long nHeight,\
long nStamp, long nType, long nReceaved)
{
if ( ! g_bCapPic)
return ;
CString csFile;
csFile.Format( " capture%02d.bmp " ,pic);
/* switch(nType)
{
case T_UYVY:
csFile="uyvy.bmp";
break;
case T_YV12:
csFile="yv12.bmp";
break;
case T_RGB32:
csFile="rgb.bmp";
break;
default:
return ;
} */
// Note:this funtion is slow,so if you want to save as a .bmp file,don't call!
if ( ! Hik_PLayM4_ConvertToBmpFile(pBuf,nSize,nWidth,nHeight,nType,csFile.GetBuffer(csFile.GetLength())))
{
CString csErr;
csErr.Format( " Convert to bmp faild(%d). " ,Hik_PlayM4_GetLastError(nPort));
AfxMessageBox(csErr);
}
pic ++ ;
g_bCapPic = FALSE;
}
C# Code:
/// <summary>
/// 截图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCapImage_Click( object sender, EventArgs e)
{
DisCB = new DisplayCBFun(DisplayCBFun);
HikPlayer.Hik_PlayM4_SetDisplayCallBack(PORT, DisCB);
}
/// <summary>
/// 截图回调函数
/// </summary>
/// <param name="nPort"></param>
/// <param name="pBuf"></param>
/// <param name="nSize"></param>
/// <param name="nWidth"></param>
/// <param name="nHeight"></param>
/// <param name="nStamp"></param>
/// <param name="nType"></param>
/// <param name="nReceaved"></param>
public void DisplayCBFun( int nPort, IntPtr pBuf, int nSize, int nWidth, int nHeight, int nStamp, int nType, int nReceaved)
{
if (HikPlayer.Hik_PLayM4_ConvertToBmpFile(pBuf, nSize, nWidth, nHeight, nType, string .Format( " C:\\capture{0}.bmp " , nPort)))
{
MessageBox.Show( " 转换bmp失败! " );
}
// 停止回调
HikPlayer.Hik_PlayM4_SetDisplayCallBack(PORT, null );
}
代码说明:
1. 这里和源代码有点出入,他用的是g_bCapPic变量来控制是否捕获图片,我用的是设置委托实例和null来达到。API说明:设置抓图回调函数;注意要尽快返回,如果要停止回调,可以把回调函数指针DisplayCBFun设为NULL。
结束
现在在做语音部分,受阻中...