C# 视频监控系列(9):服务器端——数据捕获(抓图 + 录像)
2009-04-08 08:23:40 来源:WEB开发网代码说明:
1. 从StartCap和StopCap的按钮事件可以看得出主要实现写文件头和文件尾的功能,注意_write函数。
2. 而上一章我们讲到了回调函数StreamDirectReadCallback,主要是将数据写到内存中,从代码能看出回调中是边写内存边写文件的代码,而且输出就是.264文件。由于回调从启动开始(允许被客户端访问),就一直不停的在调用这个回调,根据断点调试可以看得出当frameType == PktSysHeader时表示的就是文件头,并且只执行一次,这样在点击StartCap按钮时就直接将这个保存的文件头的数据写入文件了,用UE打开.264的文件可以发现前几个字符总是以4HKH开头的文件。
3. 注意gFileHandle是一个文件指针数组,文件被打开后回调中就一直往这个文件指针写数据!!
C#:
//用于存放头文件
byte[] FileHeader;
//文件头长度
int FileHeaderLen;
//是否开始捕获文件 0 未启用 1 启用
volatile int CaptureState;
/// <summary>
/// 开始录像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, EventArgs e)
{
//写入头文件
using (FileStream fs = new FileStream("C:hik.264", FileMode.Create))
{
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(FileHeader);
bw.Flush();
bw.Close();
}
CaptureState = 1;
}
uint endCode = 0x00000002;
/// <summary>
/// 停止录像
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStop_Click(object sender, EventArgs e)
{
CaptureState = 0;
using (FileStream fs = new FileStream("C:hik.264", FileMode.Append))
{
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(endCode);
bw.Close();
}
}
public int STREAM_DIRECT_READ_CALLBACK1(int channelNum, IntPtr DataBuf, int Length, FrameType_t frameType, IntPtr context)
{
//int status = 0;
//HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 0);
//return 0;
int status = 0;
if (frameType > 0)
{
if (frameType == FrameType_t.PktSysHeader)
{
FileHeader = new byte[Length];
Marshal.Copy(DataBuf, FileHeader, 0, Length);
FileHeaderLen = Length;
}
if (frameType == FrameType_t.PktIFrames || frameType == FrameType_t.PktSubIFrames)
status = 1;
else
status = 0;
if (frameType == FrameType_t.PktMotionDetection || frameType == FrameType_t.PktOrigImage)
return 0;
}
if (Length == 0)
{
//TRACE("no data ?n");
return 0;
}
if (frameType == FrameType_t.PktAudioFrames)
{
WriterVideoCapture(Length, DataBuf);
//写文件
// _write(gFileHandleQcif[channelNum],DataBuf,Length);
//HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 1);
// _write(gFileHandle[channelNum], DataBuf, Length);
HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 0);
}
else if (frameType == FrameType_t.PktSubIFrames || frameType == FrameType_t.PktSubPFrames || frameType == FrameType_t.PktSubBBPFrames || frameType == FrameType_t.PktSubSysHeader)
{
// _write(gFileHandleQcif[channelNum],DataBuf,Length);
HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 1);
}
else
{
WriterVideoCapture(Length, DataBuf);
HikServer.MP4_ServerWriteDataEx(channelNum, DataBuf, Length, (int)frameType, status, 0);
}
return 0;
}
/// <summary>
/// 将数据流写入视频文件
/// </summary>
/// <param name="length"></param>
/// <param name="dataBuf"></param>
private void WriterVideoCapture(int length, IntPtr dataBuf)
{
if (CaptureState == 1)
{
using (FileStream fs = new FileStream("C:hik.264", FileMode.Append))
{
BinaryWriter bw = new BinaryWriter(fs);
byte[] byteBuf = new byte[length];
Marshal.Copy(dataBuf, byteBuf, 0, length);
bw.Write(byteBuf);
bw.Flush();
bw.Close();
}
}
}
代码说明:
1. 回调函数STREAM_DIRECT_READ_CALLBACK1是在上篇文章的基础上修改的,也主要是参照的VC++的源代码改写的。
2. CaptureState变量主要用于STREAM_DIRECT_READ_CALLBACK1中控制是否写文件。
3. btnStart_Click与btnStop_Click分别代表界面上的开始录像和停止录像按钮。
4. 注意写文件的方式,开始录像用FileMode.Create,持续写入用FileMode.Append。
补充:
1. 录像的时候务必考虑单录像文件的大小以及磁盘空间不够的问题,最好还能考虑下分时段监控等。
2. 注意保存文件头的变量FileHeader,如果分文件连续保存的话有可能出现第一个文件能播放,后面的都不能播放了,可能是文件头变量的数据类型问题,你可以换byte[] -> IntPtr保存试试看。
3. 自带的示例里面有播放器极其源码,打开播放器,直接将.264文件拖拽到里面就可以播放了;如果报错那么说明你的录像有问题!!
结束
虽然代码都给出来了,但是里面整个过程还是需要理解的,一定要配合VC++自带的例子进行调试编写。
更多精彩
赞助商链接