обработать видеопоток из буфера памяти
Мне нужно проанализировать видеопоток (mpeg ts) из проприетарного сетевого протокола (который я уже знаю, как это сделать), а затем я хотел бы использовать OpenCV для обработки видеопотока в кадры. Я знаю, как использовать CV::VideoCapture из файла или из стандартного URL-адреса, но я хотел бы настроить OpenCV для чтения из буфера(ов) в памяти, где я могу хранить данные видеопотока, пока это не понадобится. Есть ли способ настроить метод обратного вызова (или любой другой interfrace), чтобы я все еще мог использовать cv:: объект видеозаписи? Есть ли лучший способ выполнить обработку видео, записав его в файл, а затем перечитав его. Я также хотел бы использовать ffmpeg напрямую, если это лучший выбор. Я думаю, что могу преобразовать AVFrames в Mat, если это необходимо.
1 ответов
недавно у меня была аналогичная потребность. Я искал способ в OpenCV воспроизвести видео, которое уже было в памяти, но без необходимости записывать видеофайл на диск. Я узнал, что интерфейс ffmpeg уже поддерживает это через av_open_input_stream
. Существует только немного больше подготовительной работы требуется по сравнению с av_open_input_file
вызов, используемый в OpenCV для открытия файла.
между следующими двумя веб-сайтами я смог собрать рабочее решение с помощью вызовов 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 );
я предоставил доступ к нему через новый вызов API в DLL highgui, похожий на cvCreateFileCapture
. Новый openBuffer
функция в основном такая же, как open( const char* _filename )
функция со следующей разницей:
err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
заменить на:
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);
кроме того, не забудьте позвонить av_close_input_stream
на вместо 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;
}
это решение предполагает, что все видео содержится в буфере памяти и, вероятно, необходимо настроить для работы с потоковыми данными.
так вот оно что! Кстати, я использую OpenCV версии 2.1, так что YMMV.