обрабатывать видеопоток из буфера памяти - PullRequest
8 голосов
/ 08 марта 2011

Мне нужно проанализировать видеопоток (mpeg ts) по проприетарному сетевому протоколу (который я уже знаю, как это сделать), а затем я хотел бы использовать OpenCV для обработки видеопотока в кадры.Я знаю, как использовать cv :: VideoCapture из файла или со стандартного URL, но я хотел бы настроить OpenCV для чтения из буфера (ов) в памяти, где я могу хранить данные видеопотока, пока они не понадобятся.Есть ли способ настроить метод обратного вызова (или любой другой интерфейс), чтобы я все еще мог использовать объект cv :: VideoCapture?Есть ли лучший способ выполнить обработку видео без записи его в файл, а затем перечитать его.Я также хотел бы развлечь использование FFMPEG напрямую, если это лучший выбор.Я думаю, что могу конвертировать AVFrames в Mat при необходимости.

1 Ответ

14 голосов
/ 06 июня 2012

У меня недавно была похожая потребность.Я искал способ в 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 в highgui DLL, аналогичный 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 в функции CvCapture_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;
}

В этом решении предполагается, что все видео содержится в буфере памяти и, возможно, придется настроить его для работы с потоковыми данными.

Вот и все!Кстати, я использую OpenCV версии 2.1, поэтому YMMV.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...