Покадровый анализ из .mov с использованием ffmpeg - PullRequest
5 голосов
/ 15 августа 2011

Я пытаюсь разобрать кадры H.264 из файла .mov. Я думаю, что пришел к выводу, что mov.c из AVFormat-части FFMPEG - это путь. Но mov.c - это ~ 2600 строк рядом с некомментированным кодом. Я ищу примеры использования FFMPEG, особенно разбора структуры любого типа файла. не имеет значения, MPEG4 или Quicktime Movie, поскольку они очень похожи по структуре.

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

Что я пытаюсь сделать: я использую AVCaptureSession для захвата образцов с видеокамеры, эти образцы затем кодируются в H264 и записываются в файл с помощью AVAssetsWriter, AVAssetsWriterInput и AVAssetsWriterInputPixelBufferAdaptor. Причина в том, что я не могу получить доступ к аппаратной кодировке H264 напрямую, так как Apple не позволит этого. То, что мне теперь нужно сделать ( я думаю, что не уверен ), это разобрать:

Атом " mdat " (данные фильма, их может быть несколько) из файла .mov. затем атом " vide " - и затем внутри видеоатома (выборка видеоданных может быть более одного). Я думаю, что будет несколько атомов, которые, как я верю, это рамки. они будут иметь тип "avc1" (это тип для H264). Пожалуйста, исправьте меня в этом, потому что я совершенно уверен, что еще не все правильно понял .

Мой вопрос: как мне разобрать отдельные кадры? Я читал документацию и смотрел на iFrameExtractor (что не очень полезно, так как декодирует кадры). Я думаю, что я правильно понял, когда я должен использовать mov.c из FFMPEG-AVFormat, но я не уверен.

Edit: Я сейчас пытаюсь так:

  1. Я запускаю слегка уменьшенную функцию инициализации iFrameExtractor, которая находит видеопоток в .mov-файле.

  2. Я получаю данные для кадра следующим образом:

    AVPacket packet;
    av_read_frame(pFormatCtx, &packet);
    NSData *frame;
    if(packet.stream_index == videoStream){
        frame = [NSData dataWithBytes:packet.data length:packet.size];
    }
    videoStream++;
    av_free_packet(&packet);
    return frame;
    

Затем я передаю его подклассу NSOperation, где он сохраняется в ожидании загрузки. но я получаю EXC_BAD_ACC, я делаю что-то не так при копировании данных из кадра? есть идеи. я получаю EXC _... когда я пытаюсь установить переменную класса NSData* frame, используя ее (неатомное, сохраняемое) свойство. (в строке синтеза написано EXC_BAD_ACC)

Ответы [ 3 ]

1 голос
/ 18 августа 2011

Я использую следующее для анализа каждого кадра из файла MOV.

-(NSData *)nextFrame {
    AVPacket packet;
    NSData *frame = nil;

    while(!frame && av_read_frame(pFormatCtx, &packet)>=0) {

        if(packet.stream_index == streamNo) {
            frame = [[[NSData alloc] initWithBytes:packet.data length:packet.size] autorelease];
        }
        av_free_packet(&packet);
    }
    return frame;
}

хотя будьте внимательны, поскольку av_read_frame не проверяет кадры, что делается на этапе декодирования. это означает, что возвращаемые «кадры» могут содержать дополнительную информацию, которая не является частью фактического кадра.

для инициализации AVFormatContext * pFormatCtx и AVCodecContext * pCodecCtx Я использую этот код (который, я считаю, получен из примера кода Мартина Беме):

    AVCodec *pCodec;

    // Register all formats and codecs
    av_register_all();

    // Open video file
    if(avformat_open_input(&pFormatCtx, [moviePath cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL)!=0)
        goto initError; // Couldn't open file

    // Retrieve stream information
    if(avformat_find_stream_info(pFormatCtx,NULL)<0)
        goto initError; // Couldn't find stream information

    // Find the video stream
    streamNo = -1;
    for(int i=0; i<pFormatCtx->nb_streams; i++){
        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            streamNo = i;
            break;
        }
    }
    if(streamNo == -1)
        goto initError; // Didn't find a video stream

    // Get a pointer to the codec context for the video stream
    pCodecCtx=pFormatCtx->streams[streamNo]->codec;

    // Find the decoder for the video stream
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL)
        goto initError; // Codec not found

    // Open codec
    if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
        goto initError; // Could not open codec

    return self;

initError:
    NSLog(@"initError in VideoFrameExtractor");
    [self release];
    return nil;

надеюсь, что это поможет кому-то в будущем.

0 голосов
/ 15 августа 2011

Если вы транслируете H264 на iOS, вам нужна сегментированная потоковая передача (так называемая прямая трансляция Apple).

Вот проект с открытым исходным кодом: http://code.google.com/p/httpsegmenter/

0 голосов
/ 15 августа 2011

Есть довольно хорошее руководство по использованию libavcodec / libavformat здесь .Похоже, что вам это интересно, это функция DoSomethingWithTheImage(), которую они не реализовали.

...