处理来自内存缓冲区的视频流

Dan*_*Dan 10 c++ opencv ffmpeg

我需要从专有网络协议(我已经知道如何做)解析视频流(mpeg ts),然后我想使用OpenCV将视频流处理成帧.我知道如何从文件或标准URL使用cv :: VideoCapture,但我想设置OpenCV从内存中的缓冲区读取,我可以存储视频流数据,直到需要它为止.有没有办法设置回调方法(或任何其他interfrace),以便我仍然可以使用cv :: VideoCapture对象?有没有更好的方法来完成处理视频而不将其写入文件然后重新读取它.如果这是一个更好的选择,我也会直接使用FFMPEG.我想我可以根据需要将AVFrame转换为Mat.

smo*_*sen 15

我最近有类似的需求.我正在寻找一种方法在OpenCV中播放已经在内存中的视频,但无需将视频文件写入磁盘.我发现ffmpeg接口已经支持了这个av_open_input_stream.与av_open_input_fileOpenCV中用于打开文件的调用相比,只需要更多的准备工作.

在以下两个网站之间,我能够使用ffmpeg调用拼凑出一个有效的解决方案.有关更多详细信息,请参阅这些网站上的信息:

http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=8&t=1170

http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/

为了让它在OpenCV中运行,我最终在CvCapture_FFMPEG类中添加了一个新函数:

virtual bool openBuffer( unsigned char* pBuffer, unsigned int bufLen );
Run Code Online (Sandbox Code Playgroud)

我通过highgui DLL中的新API调用提供了对它的访问,类似于cvCreateFileCapture.新openBuffer功能与功能基本相同,但open( const char* _filename )有以下区别:

err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
Run Code Online (Sandbox Code Playgroud)

被替换为:

ic = avformat_alloc_context();
ic->pb = av_alloc_put_byte(pBuffer, bufLen, 0, pBuffer, read_buffer, NULL, NULL);

if(!ic->pb) {
    // handle error
}

// Need to probe buffer for input format unless you already know it
AVProbeData probe_data;
probe_data.buf_size = (bufLen < 4096) ? bufLen : 4096;
probe_data.filename = "stream";
probe_data.buf = (unsigned char *) malloc(probe_data.buf_size);
memcpy(probe_data.buf, pBuffer, 4096);

AVInputFormat *pAVInputFormat = av_probe_input_format(&probe_data, 1);

if(!pAVInputFormat)
    pAVInputFormat = av_probe_input_format(&probe_data, 0);

// cleanup
free(probe_data.buf);
probe_data.buf = NULL;

if(!pAVInputFormat) {
    // handle error
}

pAVInputFormat->flags |= AVFMT_NOFILE;

err = av_open_input_stream(&ic , ic->pb, "stream", pAVInputFormat, NULL);
Run Code Online (Sandbox Code Playgroud)

此外,请确保调用av_close_input_streamCvCapture_FFMPEG::close()函数,而不是av_close_input_file在这种情况下.

现在read_buffer传递给av_alloc_put_byte我的回调函数定义为:

static int read_buffer(void *opaque, uint8_t *buf, int buf_size)
{
    // This function must fill the buffer with data and return number of bytes copied.
    // opaque is the pointer to private_data in the call to av_alloc_put_byte (4th param)

    memcpy(buf, opaque, buf_size);
    return buf_size;
}
Run Code Online (Sandbox Code Playgroud)

该解决方案假设整个视频包含在内存缓冲区中,可能需要进行调整才能使用流数据.

就是这样了!顺便说一下,我正在使用OpenCV 2.1版,所以YMMV.

  • 一些注意事项:`memcpy(probe_data.buf,data,4096)`应该使用probe_data.buf_size而不是4096(或者对于小于4096的输入它会崩溃).`av_alloc_put_byte`已重命名为`avio_alloc_context` (3认同)