目前市面上海康的摄像头占有率还是很高的,经常会用到海康的摄像头。如果要用海康的摄像头进行视频播放,可以去海康官网下载SDK,里面包含的有demo,可以很快完成
简单开发工作。
海康的demo只写清楚了自带的预览视频播放方式(不用自己解码,直接给显示控件的句柄就可以显示,性能很好,可以多路高清视频显示),而对于进行自解码播放却没有真实的例子,只是给出了获取到YUV数据的示例。我们有很多时候还是需要进行图像处理,所以还是需要自己去解码图像,YUV数据的处理是个考验性能的地方,一般如果采用软件算法将YUV转为RGB然后送给PictureBox显示,将会很慢,高清视频还会卡。我这里就简单给出一份采用D3D解码的方案,也是参考别人的博客“WPF下YUV播放的D3D解决方案”。
下面的代码有点乱,因为写了两种视频播放的方式,一路播放的主码流,采用的是不自己解码的方式,另一路播放的次码流,采用自己解码的方式。为了方便调用D3D,使用了SlimDX库。
///
/// 海康摄像头,双路视频,主码流用于抓取人脸,次码流用于自解码添加人脸框显示
///
public class CHCCameraForTwoVideo:ICamera
{
private static readonly ILog log = LogManager.GetLogger(typeof(CHCCameraForTwoVideo));
private readonly int showVideoWidth = 704;//子码流1大小704*576 子码流2大小640*480
private readonly int showVideoHeight = 576;
#region 变量定义
private uint iLastErr = 0;
private Int32 m_lUserID = -1;
private bool m_bInitSDK = false;
private Int32 m_lRealHandle_snap = -1;
private Int32 m_lRealHandle_show = -1;
private int lPort = -1;//全局的播放库port号
private D3DImageSource d3dSource = null;
CHCNetSDK.REALDATACALLBACK RealData = null;
private PictureBox snapPicBox;
private PictureBox showPicBox;
public string Direction
{
get;set;
}
public int Id
{
get;set;
}
public string Ip
{
get;set;
}
public ushort Port
{
get;set;
}
public string UserName
{
get;set;
}
public string Password
{
get;set;
}
public PictureBox RealPlayPicBox
{
get;set;
}
public bool IsRunning
{
get;set;
}
#endregion
public CHCCameraForTwoVideo(string ip, ushort port, string userName, string password, string direction, PictureBox snapPic,PictureBox showPic)
{
IsRunning = false;
Id = -1;
Ip = ip;
Port = port;
UserName = userName;
Password = password;
Direction = direction;
RealPlayPicBox = showPic;
showPicBox = showPic;
snapPicBox = snapPic;
//初始化设备
m_bInitSDK = CHCNetSDK.NET_DVR_Init();
if (m_bInitSDK == false)
{
log.Error("海康摄像头初始化失败!");
return;
}
log.Info("海康摄像头初始化成功!");
//登录设备 Login the device
CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();
m_lUserID = CHCNetSDK.NET_DVR_Login_V30(ip, port, userName, password, ref DeviceInfo);
if (m_lUserID < 0)
{
iLastErr = CHCNetSDK.NET_DVR_GetLastError();
log.Error("海康摄像头登陆失败,错误代码: " + iLastErr);
return;
}
log.Info("海康摄像头登陆成功!");
//预览视频 抓图用
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo.hPlayWnd = snapPic.Handle;//预览窗口句柄
lpPreviewInfo.lChannel = 1;//预览的设备通道
lpPreviewInfo.dwStreamType = 0;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
lpPreviewInfo.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
lpPreviewInfo.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流
lpPreviewInfo.dwDisplayBufNum = 15; //播放库播放缓冲区最大缓冲帧数
m_lRealHandle_snap = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null/*RealData*/, IntPtr.Zero);
if (m_lRealHandle_snap < 0)
{
iLastErr = CHCNetSDK.NET_DVR_GetLastError();
log.Error("海康摄像头抓图视频预览失败,错误代码: " + iLastErr);
return;
}
else
{
CHCNetSDK.NET_DVR_SetCapturePictureMode(0);//BMP_MODE = 0,JPEG_MODE = 1
IsRunning = true;
}
log.Info("海康摄像头抓图视频预览成功");
//解码视频,播放用
d3dSource = new D3DImageSource();
if (!d3dSource.SetupSurface(showVideoWidth, showVideoHeight, FrameFormat.YV12))
{
log.Error("D3D初始化失败,本机不支持这种格式");
d3dSource.Clear();
d3dSource.Dispose();
return;
}
log.Info("D3D初始化成功!");
RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数
CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo_show = new CHCNetSDK.NET_DVR_PREVIEWINFO();
lpPreviewInfo_show.hPlayWnd = IntPtr.Zero;//预览窗口句柄
lpPreviewInfo_show.lChannel = 1;//预览的设备通道
lpPreviewInfo_show.dwStreamType = 1;//码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推
lpPreviewInfo_show.dwLinkMode = 0;//连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
lpPreviewInfo_show.bBlocked = true; //0- 非阻塞取流,1- 阻塞取流
lpPreviewInfo_show.dwDisplayBufNum = 15; //播放库播放缓冲区最大缓冲帧数
m_lRealHandle_show = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo_show, RealData, IntPtr.Zero);
}
public Image CapturePicture()
{
if (m_lRealHandle_snap >= 0)
{
/************************************内存抓拍,不存文件方式**************/
byte[] bmpBytes = new byte[3072 * 2048 * 4 + 100];
UInt32 sizeReturned = 0;
if (!CHCNetSDK.NET_DVR_CapturePictureBlock_New(m_lRealHandle_snap, bmpBytes, bmpBytes.Length, ref sizeReturned))
{
iLastErr = CHCNetSDK.NET_DVR_GetLastError();
log.Error("海康摄像头抓拍图片失败,失败原因: " + iLastErr);
return null;
}
byte[] realBytes = new byte[sizeReturned];
Buffer.BlockCopy(bmpBytes, 0, realBytes, 0, realBytes.Length);
MemoryStream ms = new MemoryStream(realBytes);
Bitmap bm = (Bitmap)Image.FromStream(ms);
return new Image(bm);
/*
//图片保存路径和文件名 the path and file name to save
string sBmpPicFileName = "temp.bmp";
if (!CHCNetSDK.NET_DVR_CapturePicture(m_lRealHandle, sBmpPicFileName))
{
iLastErr = CHCNetSDK.NET_DVR_GetLastError();
log.Error("海康摄像头抓拍图片失败,失败原因: "+iLastErr);
return null;
}
else
{
log_debug("海康摄像头抓拍图片成功,$AppStartPath\temp.bmp");
}
try
{
return new Image(sBmpPicFileName);
}catch(Exception ex)
{
log.Error("海康摄像头抓图成功,返回失败",ex);
}
*/
}
return null;
}
private static PlayCtrl.DECCBFUN m_fDisplayFun = null;
string str;
//预览实时流回调处理方法
private void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
{
switch (dwDataType)
{
case CHCNetSDK.NET_DVR_SYSHEAD://系统头
if (dwBufSize > 0)
{
if (lPort >= 0)
{
return;//同一路码流不需要多次调用开流接口
}
if (!PlayCtrl.PlayM4_GetPort(ref lPort))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_GetPort failed, error code= " + iLastErr;
//this.BeginInvoke(AlarmInfo, str);
break;
}
//设置实时流播放模式
if (!PlayCtrl.PlayM4_SetStreamOpenMode(lPort, PlayCtrl.STREAME_REALTIME))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "Set STREAME_REALTIME mode failed, error code= " + iLastErr;
break;
}
//打开流接口
if (!PlayCtrl.PlayM4_OpenStream(lPort, pBuffer, dwBufSize, 1024 * 1024))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_OpenStream failed, error code= " + iLastErr;
break;
}
//设置显示缓冲区个数 Set the display buffer number
if (!PlayCtrl.PlayM4_SetDisplayBuf(lPort, 15))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;
}
//设置解码回调函数,获取解码后音视频原始数据 Set callback function of decoded data
m_fDisplayFun = new PlayCtrl.DECCBFUN(DecCallbackFUN);
if (!PlayCtrl.PlayM4_SetDecCallBackEx(lPort, m_fDisplayFun, IntPtr.Zero, 0))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;
break;
}
//设置硬解码
//if (!PlayCtrl.PlayM4_SetDecodeEngineEx(lPort, PlayCtrl.HARD_DECODE_ENGINE))
//{
// break;
//}
//播放开始
if (!PlayCtrl.PlayM4_Play(lPort, IntPtr.Zero))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_SetDisplayBuf failed, error code= " + iLastErr;
break;
}
}
break;
case CHCNetSDK.NET_DVR_STREAMDATA://码流数据
if (dwBufSize > 0 && lPort != -1)
{
for (int i = 0; i < 999; i++)
{
//送入码流数据进行解码 Input the stream data to decode
if (!PlayCtrl.PlayM4_InputData(lPort, pBuffer, dwBufSize))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_InputData failed, error code= " + iLastErr;
Thread.Sleep(2);
}
else
{
break;
}
}
}
break;
default://其他数据
if (dwBufSize > 0 && lPort != -1)
{
//送入其他数据 Input the other data
for (int i = 0; i < 999; i++)
{
if (!PlayCtrl.PlayM4_InputData(lPort, pBuffer, dwBufSize))
{
iLastErr = PlayCtrl.PlayM4_GetLastError(lPort);
str = "PlayM4_InputData failed, error code= " + iLastErr;
Thread.Sleep(2);
}
else
{
break;
}
}
}
break;
}
}
//解码回调
private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
{
// 将pBuf解码后视频输入写入文件中(解码后YUV数据量极大,尤其是高清码流,不建议在回调函数中处理)
if (pFrameInfo.nType == 3) //#define T_YV12 3
{
try
{
d3dSource.Render(pBuf);
Surface s = d3dSource.RenderSurface;
using (var stream = Surface.ToStream(s, ImageFileFormat.Bmp))
{
Bitmap bmp = new Bitmap(stream);
Image currentFrame = new Image(bmp);
Image gray_frame = currentFrame.Convert();
FaceInfo[] faceinfo = FaceDetection.frontal_surveillance(gray_frame);
for (int i = 0; i < faceinfo.Length; i++)// (Rectangle face_found in facesDetected)
{
Rectangle rect = new Rectangle(faceinfo[i].x, faceinfo[i].y, faceinfo[i].w, faceinfo[i].h);
currentFrame.Draw(rect, new Bgr(Color.Red), 1);
// currentFrame.Draw(faceinfo[i].w + " * " + faceinfo[i].h, ref font, new Point(faceinfo[i].x + 20, faceinfo[i].y + faceinfo[i].h + 20), new Bgr(Color.Green));
}
showPicBox.Image =currentFrame.ToBitmap();
bmp.Dispose();
}
//画人脸框
}
catch (Exception ex)
{
}
}
}
public void Dispose()
{
IsRunning = false;
if (m_lRealHandle_snap >= 0)
{
CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_snap);
}
if (m_lRealHandle_show >= 0)
{
CHCNetSDK.NET_DVR_StopRealPlay(m_lRealHandle_show);
}
if (m_lUserID >= 0)
{
CHCNetSDK.NET_DVR_Logout(m_lUserID);
}
if (m_bInitSDK == true)
{
CHCNetSDK.NET_DVR_Cleanup();
}
if (d3dSource != null)
{
//d3dSource.Clear();
d3dSource.Dispose();
}
}
}