随笔-377  评论-2092  文章-0  trackbacks-6

C# 视频监控系列(13):H264播放器——控制播放和截图

 

前言

     本该把这部分和上一篇合成一篇的,无奈挣扎半天,还是想对称起来,客户端3篇、服务器端3篇——所有播放器也勉强凑3篇吧(封装API的文章不算) : )

 

注意

     本系列文章限于学习交流,注重过程,由于涉及公司,所以不提供源代码下载,非常抱歉!!但是请大家放心,核心、实现以及其他能够贴出来的代码我都会贴出来,并且争取尽所能的回答留言里的每一个问题,感谢大家关注,欢迎交流 :)

 

系列

     1.     C# 视频监控系列(1):准备

     2.     C# 视频监控系列(2):客户端——封装API

     3.     C# 视频监控系列(3):客户端——连接服务器

     4.     C# 视频监控系列(4):客户端——音频接收和抓图

     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:

        int m_nSpeed;

        
/// <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>
        
/// 开始位置
        
/// </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:

        DisplayCBFun DisCB;

        
/// <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。

 

结束

     现在在做语音部分,受阻中...
posted on 2009-03-30 10:44 农民伯伯 阅读(3550) 评论(9) 编辑 收藏

评论:
#1楼 2009-05-12 15:30 | dazuo0312[未注册用户]
楼主有没有做直接抓图的试验?因为回调抓图没有办法在暂停下抓图。
 回复 引用   
#2楼[楼主] 2009-05-12 15:41 | 农民伯伯      
@dazuo0312
直接抓图也得他支持,不过我在API文档里面有找到,不过是4.8版(build0813)新增的接口。你可以试一下
---------------------------------------------
95. BOOL __stdcall Hik_PlayM4_GetBMP(LONG nPort,PBYTE pBitmap,DWORD nBufSize,DWORD*
pBmpSize);
说明: 抓取bmp图像
参数: nPort: 通道号
pBitmap: 存放BMP图像数据地址,由用户分配,不得小于bmp图像大小,即
sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + w * h * 4, 其中w和h分别为图像宽高。
nBufSize: 申请的缓冲区大小。
pBmpSize: 获取到的实际bmp图像大小。
返回值: TRUE: 获取成功
FALSE: 获取失败

---------------------
96. BOOL __stdcall Hik_PlayM4_GetJPEG(LONG nPort,PBYTE pJpeg,DWORD nBufSize,DWORD*
pJpegSize);
说明: 抓取jpeg图像
参数: nPort: 通道号
pJPeg: 存放JEPG图像数据地址,由用户分配,不得小于JPEG图像大小,建议大小w * h * 3/2, 其
中w和h分别为图像宽高。
nBufSize: 申请的缓冲区大小。
pJpegSize: 获取到的实际bmp图像大小。
返回值: TRUE: 获取成功
FALSE: 获取失败

 回复 引用 查看   
#3楼 2009-05-12 16:40 | dazuo0312[未注册用户]
呵呵,搞定了
[DllImport("PlayCtrl.dll")]
public static extern bool PlayM4_GetJPEG(int nPort, byte[] pJpeg, int nBufSize, out int pJpegSize);
调用:

int pBufferSize = 1200*1600*3/2;
byte[] pDIBImage = new byte[pBufferSize];
int tpBufferSize = 0;
HikPlayer.PlayM4_GetJPEG(g_iPort, pDIBImage, pBufferSize, out tpBufferSize);
if (tpBufferSize > 0)
{
FileStream fs = new FileStream(@"C:/123456789.jpg", FileMode.Create);
//开始写入
fs.Write(pDIBImage, 0, tpBufferSize);
//清空缓冲区、关闭流
fs.Flush();
fs.Close();
}

简单调用了一下,居然可以,终于搞定了,呵呵,送给遇到类似问题的朋友,不知道对不对,谢谢楼主

 回复 引用   
#4楼 2009-06-17 10:12 | 阿斯顿啊
感觉在看API封装的时候有点吃力,感觉看不清楚结构。能教个方法么?
像一些结构体,枚举,委托等

 回复 引用   
#5楼[楼主] 2009-06-17 10:19 | 农民伯伯      
@阿斯顿啊
这个基本靠经验了,为了出结果,可以先不看那么多,用到哪个看哪个,多看他的文档,系列后面有一篇文章我稍有总结。

多搜索,比如我经常用的一个搜索就是 Vc++ 指针 C# ,这样格式的,虽然不是最好,但是还是能搜到很多有用的文章。

 回复 引用 查看   
#6楼 2009-12-10 19:57 | 小強      
  萬分佩服樓主的無私,這幾天就在研究海康的視頻卡,說實話,他們技術支持做得很不夠,我打總公司電話要一個Delphi的Demo,他們就是沒有,一開始我上網找,找了很多都是要收費的封裝包,沒辦法只好自己一行行翻譯,剛做到可以本地看視頻,正著手開發服務端。
  看完樓主的文章,太崇拜你了

 回复 引用 查看   
#7楼[楼主] 2009-12-10 20:06 | 农民伯伯      
@小強
和你一样,C# 视频监控系列(1):准备,前言里面有描述我当时的情况: )想想能帮到大家也非常开心,我觉得在不影响公司利益情况下适当分享还是非常有益的,从互联网中得到太多,偶尔回报点滴:)

 回复 引用 查看   
#8楼 2011-09-08 11:26 | 蚁蝶      
楼主请教一下,当调用HikPlayer.HikPlayer.Hik_PlayM4_SetDisplayCallBack(1, DisCB)时报:无法加载 DLL“HikPlayM4.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)是怎么回事,在我的电脑中根本就找不到HikPlayM4.dll 请问一下它是什么时候生成,在什么地方可以找到。谢谢。。。。。。
 回复 引用 查看   
#9楼[楼主] 2011-09-08 20:01 | 农民伯伯      
@蚁蝶
SDK里面有这个,如果没有 那么例子里面也会有。

 回复 引用 查看   
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1421531 ESD4vuD5iXs=
新浪微博分享Android中文Wiki
新浪微博分享Android翻译组官方网址
新浪微博分享Android中文翻译组官方微博
昵称:农民伯伯
园龄:4年5个月
荣誉:推荐博客
粉丝:862
关注:5

搜索

 
 

常用链接

随笔分类(396)

相册

积分与排名

  • 积分 - 642851
  • 排名 - 74

阅读排行榜

推荐排行榜