使用ffmpeg从.mov逐帧解析

时间:2011-08-15 11:25:26

标签: parsing ffmpeg video-processing quicktime mpeg-4

我正在尝试从.mov文件解析H.264帧。我想我已经得出结论,来自AVFormat的mov.c - FFMPEG的一部分是要走的路。但mov.c是未注释代码旁边约2600行。我正在寻找FFMPEG的使用示例,尤其是解析任何文件类型的结构。无论是MPEG4还是Quicktime Movie都没关系,因为它们在结构上非常相似。

如果没有现有的例子(我找不到),也许有人使用过它,可以给我几行代码,或解释如何开始?

我正在尝试做什么: 我使用AVCaptureSession从摄像机捕获样本,然后在H264中对这些样本进行编码,并借助AVAssetsWriter,AVAssetsWriterInput和AVAssetsWriterInputPixelBufferAdaptor将其写入文件。原因是我无法直接访问硬件H264编码,因为苹果不允许这样做。我现在需要做的事情(我认为不确定)是解析出来的:

.mov文件中的“ mdat ” - atom(电影数据,我认为可能不止一个)。 然后是“ vide ” - 原子然后在视频原子内(视频数据样本,可能有多个)。我想我会相信几个原子是帧。这些将是“avc1”类型(这是H264的类型)。 请在此纠正我,因为我很确定我没有正确地完成所有这些

我的问题是,我将如何解析单帧。我一直在阅读the documentation并查看iFrameExtractor(由于它对帧进行解码,因此不是很有帮助)。当我应该使用FFMPEG-AVFormat中的mov.c但我不确定时,我想我已经理解了它。

编辑: 我现在正在尝试这样:

  1. 我运行略微减少的init函数i 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;
    
  3. 然后我将它传递给NSOperation的子类,在那里保留等待上传。 但我收到一个EXC_BAD_ACC,从框架中复制数据时我做错了什么?有任何想法吗。当我尝试使用其(非原子,保留)属性设置类变量NSData* frame时,我得到了EXC _... (它说合成行上的EXC_BAD_ACC)

3 个答案:

答案 0 :(得分:1)

我使用以下内容来解析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我使用这段代码(我相信它源于MartinBöhme的示例代码):

    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;

希望这有助于将来。

答案 1 :(得分:0)

有一个关于使用libavcodec / libavformat here的非常好的教程。听起来你感兴趣的是他们未实现的DoSomethingWithTheImage()函数。

答案 2 :(得分:0)

如果您将H264流式传输到iOS,则需要分段流式传输(又称苹果直播)。

这是一个开源项目:http://code.google.com/p/httpsegmenter/