最近本人在学习大华相机的二次开发时遇到一个问题:大华SDK开发文档并没有说明如何获取相机H264裸码流及其如何封装成mp4文件。在研究了海康的相关代码之后,才明白如何操作。
main.cpp
#include
#include "dhnetsdk.h"
#include "MP4Encoder.h"
using namespace std;
LLONG g_lRealHandle;
MP4Encoder* pMP4;
void CALLBACK RealDataCallBackEx2(LLONG lRealHandle, DWORD dwDataType, BYTE*pBuffer, DWORD dwBufSize, tagVideoFrameParam param, LDWORD dwUser)
{
// 若多个实时监视使用相同的数据回调函数,则用户可通过 lRealHandle 进行一一对应
if (lRealHandle == g_lRealHandle)
{
int type = param.frametype;
switch (type)
{
case 0: // I 帧
pMP4->getConvertMP4File(pBuffer, dwBufSize, type);
break;
case 1: // P 帧
pMP4->getConvertMP4File(pBuffer, dwBufSize, type);
break;
default:
break;
}
}
}
int main()
{
BOOL g_bNetSDKInitFlag = FALSE;
// 初始化 SDK
g_bNetSDKInitFlag = CLIENT_Init(NULL, 0);
if (FALSE == g_bNetSDKInitFlag)
{
cout << "Initialize client SDK fail;" << endl;
return 0;
}
else
cout << "Initialize client SDK done; " << endl;
NET_DEVICEINFO_Ex deviceInfo = { 0 };
int nError = 0;
LLONG login_handle = CLIENT_LoginEx2("192.168.1.64", 37777, "admin", "admin", EM_LOGIN_SPEC_CAP_TCP, nullptr, &deviceInfo, &nError);
/*登录失败*/
if (login_handle != 0)
{
cout << "登录成功" << endl;
//开启实时监视
int nChannelID = 0; // 预览通道号
DH_RealPlayType emRealPlayType = DH_RType_Realplay; // 实时监视
HWND hWnd = GetConsoleWindow();
g_lRealHandle = CLIENT_RealPlayEx(login_handle, nChannelID, hWnd, emRealPlayType);
pMP4 = new MP4Encoder;
if (0 == g_lRealHandle)
{
cout << "CLIENT_RealPlayEx: failed! Error code:" << CLIENT_GetLastError() << endl;
system("pause");
return 0;
}
else
{
//DWORD dwFlag = 0x00000001;
if (FALSE == CLIENT_SetRealDataCallBackEx2(g_lRealHandle, &RealDataCallBackEx2, NULL, REALDATA_FLAG_DATA_WITH_FRAME_INFO))
{
cout << "CLIENT_SetRealDataCallBackEx: failed! Error code: " << CLIENT_GetLastError() << endl;
return 0;
}
Sleep(10000);
}
}
pMP4->getMP4FileClose();
delete pMP4;
//关闭预览
if (CLIENT_StopRealPlayEx(g_lRealHandle))
{
g_lRealHandle = 0;
};
// 退出设备
if (0 != login_handle)
{
if (FALSE == CLIENT_Logout(login_handle))
{
cout << "CLIENT_Logout Failed!Last Error \n" << CLIENT_GetLastError() << endl;
}
else
{
login_handle = 0;
}
}
// 清理初始化资源
if (TRUE == g_bNetSDKInitFlag)
{
CLIENT_Cleanup();
g_bNetSDKInitFlag = FALSE;
}
return 0;
}
MP4Encoder.cpp,通过libmp4V2实现MP4写封装生成MP4视频文件
#include "MP4Encoder.h"
void MP4Encoder::getMP4FileClose()
{
MP4Close(mFile);
}
bool MP4Encoder::getConvertMP4File(BYTE *pBuffer, DWORD dwBufSize, int dwDataType)
{
CreateMP4File();
WriteH264Data(mFile, pBuffer, dwBufSize, dwDataType);
return true;
}
MP4Encoder::MP4Encoder()
{
mFile = MP4_INVALID_FILE_HANDLE;
mVideoId = MP4_INVALID_TRACK_ID;
}
MP4Encoder::~MP4Encoder()
{
}
string MP4Encoder::GetSystemTime()
{
SYSTEMTIME m_time;
GetLocalTime(&m_time);
char szDateTime[100] = { 0 };
sprintf_s(szDateTime, "%02d%02d%02d%02d%02d%02d", m_time.wYear, m_time.wMonth,
m_time.wDay, m_time.wHour, m_time.wMinute, m_time.wSecond);
string time(szDateTime);
return time;
}
MP4FileHandle MP4Encoder::CreateMP4File()
{
if (mFile == NULL)
{
string s = GetSystemTime() + ".mp4";
const char* FileName = s.c_str();
mFile = MP4Create(FileName);
if (mFile == MP4_INVALID_FILE_HANDLE)
{
cout << "Open file failed!\n";
return 0;
}
if (mFile == NULL)
{
printf("ERROR:Create file failed!");
return false;
}
// 设置时间片
MP4SetTimeScale(mFile, VIDEO_TIME_SCALE);
}
return mFile;
}
int MP4Encoder::ReadOneNaluFromBuf(const unsigned char *pBuffer, unsigned int nBufferSize, unsigned int offSet, MP4ENC_NaluUnit &nalu)
{
unsigned int i = offSet;
int j = 0;
while (i> 24;
data[1] = nalu.size >> 16;
data[2] = nalu.size >> 8;
data[3] = nalu.size & 0xff;
memcpy(data + 4, nalu.data, nalu.size);
if (dwDataType == 0)
{
MP4WriteSample(MP4File, mVideoId, data, datalen, MP4_INVALID_DURATION, 0, 1);
}
if (dwDataType == 1)
{
MP4WriteSample(MP4File, mVideoId, data, datalen, MP4_INVALID_DURATION, 0, 0);
}
delete[] data;
}
pos += len;
}
return pos;
}
整个项目(VS2015-X64)下载链接:https://download.csdn.net/download/qq_35135771/12526926