本文實作服務端兩大核心儲存功能:JPEG 抓圖與 H.264 碼流錄像。重點解析回調中取得檔案頭、資料幀、檔案尾的完整流程,並給出可直接使用的 C# 程式碼。
byte[] imageBuf = new byte[704 * 576 * 2];
int size = imageBuf.Length;
int ret = HikVisionSDK.GetJpegImage(channelHandle, imageBuf, out size, 100);
if (ret == 0)
{
using (MemoryStream ms = new MemoryStream(imageBuf, 0, size))
{
Image img = Image.FromStream(ms);
img.Save(@"C:\snapshot.jpg", ImageFormat.Jpeg);
}
}
API 修正:GetJpegImage 簽名為 (IntPtr hChannel, byte[] buf, out int size, uint quality),GetOriginalImage 同理但無 quality 參數。
錄像檔結構:檔案頭 + 多個資料幀 + 檔案尾 (0x00000002)。
byte[] fileHeader; // 暫存檔案頭
int fileHeaderLen;
volatile int captureState; // 0=停止, 1=錄製中
private void btnStart_Click(object sender, EventArgs e)
{
using (var fs = new FileStream(@"C:\hik.264", FileMode.Create))
using (var bw = new BinaryWriter(fs))
{
bw.Write(fileHeader);
}
captureState = 1;
}
private void btnStop_Click(object sender, EventArgs e)
{
captureState = 0;
uint endCode = 0x00000002;
using (var fs = new FileStream(@"C:\hik.264", FileMode.Append))
using (var bw = new BinaryWriter(fs))
{
bw.Write(endCode);
}
}
public int STREAM_DIRECT_READ_CALLBACK1(int channelNum, IntPtr dataBuf, int length, FrameType frameType, IntPtr context)
{
int status = 0;
if (frameType > 0)
{
if (frameType == FrameType.PktSysHeader) // 檔案頭
{
fileHeader = new byte[length];
Marshal.Copy(dataBuf, fileHeader, 0, length);
fileHeaderLen = length;
}
if (frameType == FrameType.PktIFrames || frameType == FrameType.PktSubIFrames)
status = 1; // 關鍵幀標記
else
status = 0;
if (frameType == FrameType.PktMotionDetection || frameType == FrameType.PktOrigImage)
return 0;
}
if (length == 0) return 0;
// 寫入伺服器發送緩衝(供客戶端預覽)
if (frameType == FrameType.PktAudioFrames)
{
WriteVideoCapture(length, dataBuf);
HikServer.MP4_ServerWriteDataEx(channelNum, dataBuf, length, (int)frameType, status, 0);
}
else if (frameType == FrameType.PktSubIFrames || frameType == FrameType.PktSubPFrames || frameType == FrameType.PktSubBBPFrames || frameType == FrameType.PktSubSysHeader)
{
HikServer.MP4_ServerWriteDataEx(channelNum, dataBuf, length, (int)frameType, status, 1); // 子碼流
}
else
{
WriteVideoCapture(length, dataBuf); // 主碼流寫檔
HikServer.MP4_ServerWriteDataEx(channelNum, dataBuf, length, (int)frameType, status, 0);
}
return 0;
}
private void WriteVideoCapture(int length, IntPtr dataBuf)
{
if (captureState == 1)
{
using (var fs = new FileStream(@"C:\hik.264", FileMode.Append))
using (var bw = new BinaryWriter(fs))
{
byte[] buf = new byte[length];
Marshal.Copy(dataBuf, buf, 0, length);
bw.Write(buf);
}
}
}
PktSysHeader 僅第一次觸發,必須暫存供開始錄像時寫入。FileMode.Create,過程用 FileMode.Append,結尾寫入 0x00000002。MP4_ServerWriteDataEx 才能讓客戶端看到畫面;nImgFormat=0 主碼流、1 子碼流。用海康官方播放器拖曳產生的 .264 檔,能正常播放即表示錄製無誤。