DLLEXPORT_API int __stdcall StartVideoCapture(HANDLE hChannelHandle);
DLLEXPORT_API int __stdcall StopVideoCapture(HANDLE hChannelHandle);
我在C#中定义了以下方法
/// <summary>
/// 启动主通道编码数据流捕获
/// 说 明: 启动主通道编码数据流捕获。用户程序可以使用直接读取方式,使用
/// StreamDirectReadCallback回调函数直接对数据流进行处理;也可以与H卡一样,通过消息读取方式,等SDK向用户程序发送在 RegisterMessageNotifyHandle中注册的消息,用户程序使用ReadStreamData来读取数据流。
/// </summary>
/// <param name="hChannelHandle">通道句柄</param>
/// <returns>成功返回0;失败返回错误号</returns>
[DllImport("DS40xxSDK.dll")]
public static extern int StartVideoCapture(IntPtr hChannelHandle);
/// <summary>
/// 停止主通道编码数据流捕获
/// </summary>
/// <param name="hChannelHandle">通道句柄</param>
/// <returns>成功返回0;失败返回错误号</returns>
[DllImport("DS40xxSDK.dll")]
public static extern int StopVideoCapture(IntPtr hChannelHandle);
/// <summary>
/// 编码数据流直接读取回调函数委托
/// </summary>
/// <param name="channelNumber">通道号</param>
/// <param name="DataBuf">缓冲区地址</param>
/// <param name="Length">缓冲区长度</param>
/// <param name="FrameType">缓冲区数据帧类型</param>
/// <param name="context">设备上下文</param>
/// <returns></returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int STREAM_DIRECT_READ_CALLBACK(uint channelNumber, IntPtr DataBuf, uint Length, int FrameType, IntPtr context);
/// <summary>
/// 编码数据流直接读取回调函数
/// </summary>
/// <param name="channelNumber">通道号</param>
/// <param name="DataBuf">缓冲区地址</param>
/// <param name="Length">缓冲区长度</param>
/// <param name="FrameType">缓冲区数据帧类型</param>
/// <param name="context">设备上下文</param>
/// <returns></returns>
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, int FrameType, IntPtr context)
{
}
在这个回调函数中,我怎么才能把视频数据保存到文件?谢谢
解决问题,全分奉上!
19 个解决方案
#1
DataBuf这个是数据缓冲区的地址.把这块的数据读出来,写入到你自己的流中去.
#2
好强大,学习,收藏,帮顶
#3
可通过System.Runtime.InteropServices.Marshal.Copy(DataBuf, databuffers, 0, databuffers.Length);
#4
从而获取某个地址的数据.databuffers这是一个byte[],你可自己开辟.Length这个可用.
我没搞过视频卡.不过理论上我觉得应该是我上面这样.
private void vc_VideoCaptured(object sender, VIDEOHDR hdr)
{
if (this.chanel == null || !this.chanel.Connected) return;
try
{
byte[] data = new byte[hdr.dwBytesUsed];
Marshal.Copy(hdr.lpData, data, 0, hdr.dwBytesUsed);
this.chanel.SendVideo(data);
}
catch (System.Exception ex)
{
}
}
我没搞过视频卡.不过理论上我觉得应该是我上面这样.
private void vc_VideoCaptured(object sender, VIDEOHDR hdr)
{
if (this.chanel == null || !this.chanel.Connected) return;
try
{
byte[] data = new byte[hdr.dwBytesUsed];
Marshal.Copy(hdr.lpData, data, 0, hdr.dwBytesUsed);
this.chanel.SendVideo(data);
}
catch (System.Exception ex)
{
}
}
#5
视频和音频一起写入?我试下!
#6
@greystar
感谢!
感谢!
#7
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, int FrameType, IntPtr context)
{
}
这个函数参数中context在C++中的定义是void *context,标注为"设备上下文",我在C#定义为IntPtr没问题吧?
另外,请教"设备上下文"是什么意思?在C#中应做何理解?
谢谢!
{
}
这个函数参数中context在C++中的定义是void *context,标注为"设备上下文",我在C#定义为IntPtr没问题吧?
另外,请教"设备上下文"是什么意思?在C#中应做何理解?
谢谢!
#8
写入是没有问题,不过,这是个回调函数,在启动录像后,将不停的向某个文件中写入数据,我每次录像的
文件只有6KB,代码如下,
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, FrameType_t FrameType, IntPtr context)
{
byte[][] FileHeader = new byte[64][];
FileHeader[channelNumber] = new byte[Length];
if (FrameType > 0)
{
if (FrameType == FrameType_t.PktSysHeader)
{
Marshal.Copy(DataBuf, FileHeader[channelNumber], 0, (int)Length);
}
}
string fileName = "D:\\" + DateTime.Now.ToString("yyyyMMdd") + ".264";
FileStream fileStream;
if (!System.IO.File.Exists(fileName))
{
System.IO.File.Create(fileName);
}
fileStream = System.IO.File.OpenWrite(fileName);
fileStream.Write(FileHeader[channelNumber], 0, (int)Length);
fileStream.Close();
return 0;
}
怎么可以在上次文件里继续写入数据?
文件只有6KB,代码如下,
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, FrameType_t FrameType, IntPtr context)
{
byte[][] FileHeader = new byte[64][];
FileHeader[channelNumber] = new byte[Length];
if (FrameType > 0)
{
if (FrameType == FrameType_t.PktSysHeader)
{
Marshal.Copy(DataBuf, FileHeader[channelNumber], 0, (int)Length);
}
}
string fileName = "D:\\" + DateTime.Now.ToString("yyyyMMdd") + ".264";
FileStream fileStream;
if (!System.IO.File.Exists(fileName))
{
System.IO.File.Create(fileName);
}
fileStream = System.IO.File.OpenWrite(fileName);
fileStream.Write(FileHeader[channelNumber], 0, (int)Length);
fileStream.Close();
return 0;
}
怎么可以在上次文件里继续写入数据?
#9
你写文件时要使用追加的方式,
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
#10
filemode.Append
#11
fileStream = System.IO.File.Open(fileName,FileMode.Append);
很是感谢!
我再仔细看看他们给的C++示例!
很是感谢!
我再仔细看看他们给的C++示例!
#12
//typedef int (*STREAM_DIRECT_READ_CALLBACK)(ULONG channelNumber,void *DataBuf,DWORD Length,int FrameType,void *context);
int __cdecl StreamDirectReadCallback(ULONG channelNum,void *DataBuf,DWORD Length,int frameType,void *context)
{
BOOL breakable;
int nframetype =0;
CHKVisionDlg *hkdlg = (CHKVisionDlg *)context;
if(frameType >0)
{
if (frameType == PktSysHeader)
{
memcpy(FileHeader[channelNum],DataBuf,Length);
FileHeaderLen = Length;
}
else if (frameType == PktSubSysHeader)
{
memcpy(FileHeaderQcif[channelNum],DataBuf,Length);
FileHeaderLen = Length;
}
if (frameType == PktMotionDetection)
{
int result[4];
if(bOverlayMode)
{
hkdlg->m_VideoWin.DrawVectEx(channelNum, (char *)DataBuf);
}
else
{
hkdlg->m_bMoving[channelNum] = TRUE;
memcpy(motionData[channelNum],(char*)DataBuf,Length);
}
MotionAnalyzer(ChannelHandle[channelNum],(char*)DataBuf,15,result);
if((result[0] + result[1] + result[2] + result[3]))
{
if (channelNum ==0)
TRACE("!!!!!!!!!!!!!!!!CH=%d motion detect result is %d %d %d %d\n",channelNum,result[0],\
result[1],result[2],result[3]);
// Trigger函数的作用是把报警前的数据按setup里面的设置,把相应的警前帧写入文件
if(!hkdlg->baftermotion[channelNum])
alarmFile[channelNum].Trigger(gFileHandle[channelNum]);
//每次有移动侦测帧上来,自动把ualreadywriteframes[channelNum]清为0 ,为写入警后帧作准备
hkdlg->ualreadywriteframes[channelNum]=0;
hkdlg->baftermotion[channelNum]=TRUE;
}
return 0;
}
if (frameType == PktIFrames || frameType ==PktSubIFrames)
breakable = TRUE;
else
breakable = FALSE;
}
gChannelTotalLength[channelNum].QuadPart +=Length;
gCurrentFileLen[channelNum] +=Length;
if ((gCurrentFileLen[channelNum] > gFileSize*1000*1000) && (breakable) )
{
char fileName[256];
CTime m_StartTime1=CTime::GetCurrentTime();
CString csStartTime=m_StartTime1.Format("%Y%m%d%H%M%S");
if (gFileHandle[channelNum])
{
_close(gFileHandle[channelNum]);
sprintf(fileName, "ch%02d_%s.264", channelNum,csStartTime);
gFileHandle[channelNum] = _open(fileName,_O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD|_S_IWRITE);
_write(gFileHandle[channelNum],FileHeader[channelNum],FileHeaderLen);
}
if (gFileHandleQcif[channelNum])
{
_close(gFileHandleQcif[channelNum]);
sprintf(fileName, "ch%02d_%s_sub.264", channelNum,csStartTime);
gFileHandleQcif[channelNum] = _open(fileName,_O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD|_S_IWRITE);
_write(gFileHandleQcif[channelNum],FileHeaderQcif[channelNum],FileHeaderLen);
}
gCurrentFileLen[channelNum] -=gFileSize*1000*1000;
}
if(bAlarmFileSave)
{
if(frameType == PktSysHeader)
_write(gFileHandle[channelNum],DataBuf,Length);
else
{
//统计移动侦测帧上来之后的音视频数据,统计它们 ,并把它们写入文件,每一次有 新的移动侦测数据上来,
//ualreadywriteframes都会先清0,然后统计写入文件的音视频数据
hkdlg->ualreadywriteframes[channelNum] += hkdlg->TypeToFrames((FrameType_t)frameType);
if (hkdlg->ualreadywriteframes[channelNum] <6*(25+25)) //录制移动侦测帧上来之后 6秒钟的音视频数据,也就是警后数据
_write(gFileHandle[channelNum],DataBuf,Length);
else
{
// 如果移动侦测上来之后,写入文件的音视频数据已经足够,那么把接下来上来的音视频数据压缓冲,
// 压入缓冲的数据有两种处理方式:1 如果缓冲满了,自动被删除;2 作为下次报警上来的警前帧写入文件;
alarmFile[channelNum].FramePush(gFileHandle[channelNum],(unsigned char *)DataBuf,Length,(FrameType_t)frameType,breakable);
hkdlg->baftermotion[channelNum] = FALSE;
}
}
}
else
{
if(frameType ==PktAudioFrames)
{
_write(gFileHandle[channelNum],DataBuf,Length);
_write(gFileHandleQcif[channelNum],DataBuf,Length);
}else if (frameType ==PktSubIFrames || frameType ==PktSubPFrames || frameType == PktSubBBPFrames || frameType == PktSubSysHeader)
{
_write(gFileHandleQcif[channelNum],DataBuf,Length);
}else
{
_write(gFileHandle[channelNum],DataBuf,Length);
}
}
return 0;
}
以上这段代码
#13
视频采集卡,我也开发过,是天敏的
up
up
#14
这个录像让我郁闷了一天!
谁能给点这个回调函数内数据处理的代码?
谁能给点这个回调函数内数据处理的代码?
#15
解决了!!!结贴
#17
你们都是高手啊!学习学习
#18
这位仁兄,能帮我看看我说我这个视频采集卡的回调函数吗?我不太明白怎么将视频显示在界面窗口上?
BOOL TwRegisterVideoStreamCallback(TwVideoStreamCallback VideoStreamCallback, void *Context)
功能:注册视频数据流回调函数
参数:[in]VideoStreamReadCallback,指定的回调函数指针
[in]Context,指定的回调函数上下文指针
返回:成功返回TRUE,否则返回FALSE,调用TwGetLastError获取错误码
#19
typedef int (__stdcall *TwVideoStreamCallback)(int nChannel, VOID *DataBuf, int width, int height, BOOL bField2, void *Context, __int64 pts)
功能:提供视频原始数据流给用户
参数:[in]nChannel,通道索引号
[in]DataBuf,数据缓存的指针
[in]width,视频宽度
[in]height,视频高度
[in]bField2,是否是偶场数据
[in]Context,上下文指针
[in]pts,帧时间戳
返回:成功返回TRUE,否则返回FALSE
怎么来写程序,我买的板卡没有实例,不知道怎么开发?
#20
#1
DataBuf这个是数据缓冲区的地址.把这块的数据读出来,写入到你自己的流中去.
#2
好强大,学习,收藏,帮顶
#3
可通过System.Runtime.InteropServices.Marshal.Copy(DataBuf, databuffers, 0, databuffers.Length);
#4
从而获取某个地址的数据.databuffers这是一个byte[],你可自己开辟.Length这个可用.
我没搞过视频卡.不过理论上我觉得应该是我上面这样.
private void vc_VideoCaptured(object sender, VIDEOHDR hdr)
{
if (this.chanel == null || !this.chanel.Connected) return;
try
{
byte[] data = new byte[hdr.dwBytesUsed];
Marshal.Copy(hdr.lpData, data, 0, hdr.dwBytesUsed);
this.chanel.SendVideo(data);
}
catch (System.Exception ex)
{
}
}
我没搞过视频卡.不过理论上我觉得应该是我上面这样.
private void vc_VideoCaptured(object sender, VIDEOHDR hdr)
{
if (this.chanel == null || !this.chanel.Connected) return;
try
{
byte[] data = new byte[hdr.dwBytesUsed];
Marshal.Copy(hdr.lpData, data, 0, hdr.dwBytesUsed);
this.chanel.SendVideo(data);
}
catch (System.Exception ex)
{
}
}
#5
视频和音频一起写入?我试下!
#6
@greystar
感谢!
感谢!
#7
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, int FrameType, IntPtr context)
{
}
这个函数参数中context在C++中的定义是void *context,标注为"设备上下文",我在C#定义为IntPtr没问题吧?
另外,请教"设备上下文"是什么意思?在C#中应做何理解?
谢谢!
{
}
这个函数参数中context在C++中的定义是void *context,标注为"设备上下文",我在C#定义为IntPtr没问题吧?
另外,请教"设备上下文"是什么意思?在C#中应做何理解?
谢谢!
#8
写入是没有问题,不过,这是个回调函数,在启动录像后,将不停的向某个文件中写入数据,我每次录像的
文件只有6KB,代码如下,
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, FrameType_t FrameType, IntPtr context)
{
byte[][] FileHeader = new byte[64][];
FileHeader[channelNumber] = new byte[Length];
if (FrameType > 0)
{
if (FrameType == FrameType_t.PktSysHeader)
{
Marshal.Copy(DataBuf, FileHeader[channelNumber], 0, (int)Length);
}
}
string fileName = "D:\\" + DateTime.Now.ToString("yyyyMMdd") + ".264";
FileStream fileStream;
if (!System.IO.File.Exists(fileName))
{
System.IO.File.Create(fileName);
}
fileStream = System.IO.File.OpenWrite(fileName);
fileStream.Write(FileHeader[channelNumber], 0, (int)Length);
fileStream.Close();
return 0;
}
怎么可以在上次文件里继续写入数据?
文件只有6KB,代码如下,
public static int _StreamDirectReadCallBack(uint channelNumber, IntPtr DataBuf, uint Length, FrameType_t FrameType, IntPtr context)
{
byte[][] FileHeader = new byte[64][];
FileHeader[channelNumber] = new byte[Length];
if (FrameType > 0)
{
if (FrameType == FrameType_t.PktSysHeader)
{
Marshal.Copy(DataBuf, FileHeader[channelNumber], 0, (int)Length);
}
}
string fileName = "D:\\" + DateTime.Now.ToString("yyyyMMdd") + ".264";
FileStream fileStream;
if (!System.IO.File.Exists(fileName))
{
System.IO.File.Create(fileName);
}
fileStream = System.IO.File.OpenWrite(fileName);
fileStream.Write(FileHeader[channelNumber], 0, (int)Length);
fileStream.Close();
return 0;
}
怎么可以在上次文件里继续写入数据?
#9
你写文件时要使用追加的方式,
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
public FileStream (
string path,
FileMode mode,
FileAccess access,
FileShare share
)
#10
filemode.Append
#11
fileStream = System.IO.File.Open(fileName,FileMode.Append);
很是感谢!
我再仔细看看他们给的C++示例!
很是感谢!
我再仔细看看他们给的C++示例!
#12
//typedef int (*STREAM_DIRECT_READ_CALLBACK)(ULONG channelNumber,void *DataBuf,DWORD Length,int FrameType,void *context);
int __cdecl StreamDirectReadCallback(ULONG channelNum,void *DataBuf,DWORD Length,int frameType,void *context)
{
BOOL breakable;
int nframetype =0;
CHKVisionDlg *hkdlg = (CHKVisionDlg *)context;
if(frameType >0)
{
if (frameType == PktSysHeader)
{
memcpy(FileHeader[channelNum],DataBuf,Length);
FileHeaderLen = Length;
}
else if (frameType == PktSubSysHeader)
{
memcpy(FileHeaderQcif[channelNum],DataBuf,Length);
FileHeaderLen = Length;
}
if (frameType == PktMotionDetection)
{
int result[4];
if(bOverlayMode)
{
hkdlg->m_VideoWin.DrawVectEx(channelNum, (char *)DataBuf);
}
else
{
hkdlg->m_bMoving[channelNum] = TRUE;
memcpy(motionData[channelNum],(char*)DataBuf,Length);
}
MotionAnalyzer(ChannelHandle[channelNum],(char*)DataBuf,15,result);
if((result[0] + result[1] + result[2] + result[3]))
{
if (channelNum ==0)
TRACE("!!!!!!!!!!!!!!!!CH=%d motion detect result is %d %d %d %d\n",channelNum,result[0],\
result[1],result[2],result[3]);
// Trigger函数的作用是把报警前的数据按setup里面的设置,把相应的警前帧写入文件
if(!hkdlg->baftermotion[channelNum])
alarmFile[channelNum].Trigger(gFileHandle[channelNum]);
//每次有移动侦测帧上来,自动把ualreadywriteframes[channelNum]清为0 ,为写入警后帧作准备
hkdlg->ualreadywriteframes[channelNum]=0;
hkdlg->baftermotion[channelNum]=TRUE;
}
return 0;
}
if (frameType == PktIFrames || frameType ==PktSubIFrames)
breakable = TRUE;
else
breakable = FALSE;
}
gChannelTotalLength[channelNum].QuadPart +=Length;
gCurrentFileLen[channelNum] +=Length;
if ((gCurrentFileLen[channelNum] > gFileSize*1000*1000) && (breakable) )
{
char fileName[256];
CTime m_StartTime1=CTime::GetCurrentTime();
CString csStartTime=m_StartTime1.Format("%Y%m%d%H%M%S");
if (gFileHandle[channelNum])
{
_close(gFileHandle[channelNum]);
sprintf(fileName, "ch%02d_%s.264", channelNum,csStartTime);
gFileHandle[channelNum] = _open(fileName,_O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD|_S_IWRITE);
_write(gFileHandle[channelNum],FileHeader[channelNum],FileHeaderLen);
}
if (gFileHandleQcif[channelNum])
{
_close(gFileHandleQcif[channelNum]);
sprintf(fileName, "ch%02d_%s_sub.264", channelNum,csStartTime);
gFileHandleQcif[channelNum] = _open(fileName,_O_CREAT|_O_BINARY|_O_WRONLY|_O_TRUNC,_S_IREAD|_S_IWRITE);
_write(gFileHandleQcif[channelNum],FileHeaderQcif[channelNum],FileHeaderLen);
}
gCurrentFileLen[channelNum] -=gFileSize*1000*1000;
}
if(bAlarmFileSave)
{
if(frameType == PktSysHeader)
_write(gFileHandle[channelNum],DataBuf,Length);
else
{
//统计移动侦测帧上来之后的音视频数据,统计它们 ,并把它们写入文件,每一次有 新的移动侦测数据上来,
//ualreadywriteframes都会先清0,然后统计写入文件的音视频数据
hkdlg->ualreadywriteframes[channelNum] += hkdlg->TypeToFrames((FrameType_t)frameType);
if (hkdlg->ualreadywriteframes[channelNum] <6*(25+25)) //录制移动侦测帧上来之后 6秒钟的音视频数据,也就是警后数据
_write(gFileHandle[channelNum],DataBuf,Length);
else
{
// 如果移动侦测上来之后,写入文件的音视频数据已经足够,那么把接下来上来的音视频数据压缓冲,
// 压入缓冲的数据有两种处理方式:1 如果缓冲满了,自动被删除;2 作为下次报警上来的警前帧写入文件;
alarmFile[channelNum].FramePush(gFileHandle[channelNum],(unsigned char *)DataBuf,Length,(FrameType_t)frameType,breakable);
hkdlg->baftermotion[channelNum] = FALSE;
}
}
}
else
{
if(frameType ==PktAudioFrames)
{
_write(gFileHandle[channelNum],DataBuf,Length);
_write(gFileHandleQcif[channelNum],DataBuf,Length);
}else if (frameType ==PktSubIFrames || frameType ==PktSubPFrames || frameType == PktSubBBPFrames || frameType == PktSubSysHeader)
{
_write(gFileHandleQcif[channelNum],DataBuf,Length);
}else
{
_write(gFileHandle[channelNum],DataBuf,Length);
}
}
return 0;
}
以上这段代码
#13
视频采集卡,我也开发过,是天敏的
up
up
#14
这个录像让我郁闷了一天!
谁能给点这个回调函数内数据处理的代码?
谁能给点这个回调函数内数据处理的代码?
#15
解决了!!!结贴
#16
#17
你们都是高手啊!学习学习
#18
这位仁兄,能帮我看看我说我这个视频采集卡的回调函数吗?我不太明白怎么将视频显示在界面窗口上?
BOOL TwRegisterVideoStreamCallback(TwVideoStreamCallback VideoStreamCallback, void *Context)
功能:注册视频数据流回调函数
参数:[in]VideoStreamReadCallback,指定的回调函数指针
[in]Context,指定的回调函数上下文指针
返回:成功返回TRUE,否则返回FALSE,调用TwGetLastError获取错误码
#19
typedef int (__stdcall *TwVideoStreamCallback)(int nChannel, VOID *DataBuf, int width, int height, BOOL bField2, void *Context, __int64 pts)
功能:提供视频原始数据流给用户
参数:[in]nChannel,通道索引号
[in]DataBuf,数据缓存的指针
[in]width,视频宽度
[in]height,视频高度
[in]bField2,是否是偶场数据
[in]Context,上下文指针
[in]pts,帧时间戳
返回:成功返回TRUE,否则返回FALSE
怎么来写程序,我买的板卡没有实例,不知道怎么开发?