2013-09-03 2 views
1

У меня есть avi-файл, содержащий несжатые серые видеоданные. Мне нужно извлечь кадры из него. Размер файла - 22 Гб.Как читать данные YUV8 из avi-файла?

Как это сделать?

Я уже пробовал ffmpeg, но он дает мне сообщение «не удалось найти параметры кодека для видеопотока» - потому что на рабочем месте нет кодеков, просто кадров.

Поскольку Opencv просто использует ffmpeg для чтения видео, это также исключает opencv.

Единственный путь, который, кажется, оставлен, состоит в том, чтобы попытаться вычислить необработанные данные, но я не знаю, как это сделать.

Редактировать: это код, который я использую для чтения из файла с opencv. Ошибка происходит во второй, если. Запуск FFmpeg бинарного на файл также завершается с сообщением выше (не может найти кодек aprameters и т.д.)

/* register all formats and codecs */ 
av_register_all(); 

/* open input file, and allocate format context */ 
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { 
    fprintf(stderr, "Could not open source file %s\n", src_filename); 
    ret = 1; 
    goto end; 
} 
fmt_ctx->seek2any = true; 
/* retrieve stream information */ 
int res = avformat_find_stream_info(fmt_ctx, NULL); 
if (res < 0) { 
    fprintf(stderr, "Could not find stream information\n"); 
    ret = 1; 
    goto end; 
} 

Edit:

Вот пример кода, я попытался сделать добычу: pastebin. Результат, который я получаю, является неизменным буфером после каждого вызова AVIStreamRead.

+0

См. Редактирование моего ответа на решение. –

ответ

2

Если вам не нужна функция перекрестной платформы Видео для Windows (VFW) API является хорошей альтернативой (http://msdn.microsoft.com/en-us/library/windows/desktop/dd756808(v=vs.85).aspx), я не буду размещать весь блок кода, так как вам нужно много сделать, но вы должны иметь возможность рисовать это из ссылки. В основном, вы делаете AVIFileOpen, затем получаете видеопоток через AVIFileGetStream с streamtypeVIDEO или, наоборот, делаете это сразу с AVIStreamOpenFromFile, а затем читаете образцы из потока с AVIStreamRead. Если вы доберетесь до точки, где вы потерпите неудачу, я могу попытаться помочь, но это должно быть довольно просто.

Кроме того, не знаю, почему ffmpeg терпит неудачу, я делаю необработанное чтение AVI с помощью ffmpeg без участия каких-либо кодеков, можете ли вы опубликовать, какой вызов ffpeg на самом деле не удается?

EDIT:

Для вопроса, который вы видите, когда размер данных для чтения 0. Файл AVI имеет N слоты для кадров в каждом втором, где N является кадром видео. В реальной жизни образцы не будут поступать именно на такой скорости (например, камеры IP-наблюдения), поэтому фактические индексы образцов данных могут быть не непрерывными, как 1,5,11, ... и VFW будут вставлять пустые образцы между ними (то есть откуда вы читаете образец с нулевым размером). Вам нужно позвонить AVIStreamRead с NULL в качестве буфера и 0 в размере до bRead не 0 или вы пропустите последний образец. Когда вы получите фактический размер, вы можете снова позвонить AVIStreamRead по этому образцу с указателем и размером буфера. Я обычно делаю сжатое видео, так что я не использовать предложенный размер, но, по крайней мере, в соответствии с вашим кодом snipplet я хотел бы сделать что-то вроде этого:

... 
bRead = 0; 
do 
{ 
    aviOpRes = AVIStreamRead(ppavi,smpS,1,NULL,0,&bRead,&smpN); 
} while (bRead == 0 && ++smpS < si.dwLength + si.dwStart); 
if(smpS >= si.dwLength + si.dwStart) 
    break; 
PUCHAR tempBuffer = new UCHAR[bRead]; 
aviOpRes = AVIStreamRead(ppavi,smpS,1,tempBuffer,bRead,&bRead,&smpN); 
/* do whatever you need */ 
delete tempBuffer; 
... 

EDIT 2:

Так как это может пригодиться кому-то или самому себе сделать выбор между VFW и FFMPEG. Я также обновил ваш пример FFMPEG, чтобы он разбирал один и тот же файл (извините за качество кода, поскольку он не имеет проверки ошибок, но я думаю, вы можете видеть логический поток):

/* register all formats and codecs */ 
av_register_all(); 
AVFormatContext* fmt_ctx = NULL; 
/* open input file, and allocate format context */ 
const char *src_filename = "E:\\Output.avi"; 
if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { 
    fprintf(stderr, "Could not open source file %s\n", src_filename); 
    abort(); 
} 
/* retrieve stream information */ 
int res = avformat_find_stream_info(fmt_ctx, NULL); 
if (res < 0) { 
    fprintf(stderr, "Could not find stream information\n"); 
    abort(); 
} 
int video_stream_index = 0; /* video stream is usualy 0 but still better to lookup in case it's not present */ 
for(; video_stream_index < fmt_ctx->nb_streams; ++video_stream_index) 
{ 
    if(fmt_ctx->streams[video_stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
     break; 
} 
if(video_stream_index == fmt_ctx->nb_streams) 
    abort(); 
AVPacket *packet = new AVPacket; 
while(av_read_frame(fmt_ctx, packet) == 0) 
{ 
    if (packet->stream_index == video_stream_index) 
     printf("Sample nr %d\n", packet->pts); 
    av_free_packet(packet); 
} 

В основном вы открываете контекст и читать пакеты из него.Вы получите как аудио-, так и видеопакеты, чтобы вы могли проверить, принадлежит ли пакет потоку интереса. FFMPEG избавит вас от проблем с пустыми кадрами и даст только те образцы, в которых есть данные.

+0

Я добавил свой пример кода; Я пытаюсь использовать VFW сейчас, и я бы очень признателен за ясный пример. – Srv19

+0

Установлен ли 'fmt_ctx' в NULL? Также, что произойдет, если вы просто попробуете 'av_read_frame' в этом контексте? Я попытаюсь найти что-то из своего старого материала с помощью VFW. –

+0

Да, 'fmt_ctx' - NULL, прежде чем все начнется. Я не пробовал вызывать 'av_read_frame', потому что я не очень хорошо понимаю используемый код, и для этого потребуется существенное изменение. Тем не менее, я могу поместить код в pastebin для проверки. – Srv19

Смежные вопросы