5

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

如果没有现有示例(我找不到任何示例),也许有人已经使用它并且可以给我几行代码,或者解释如何开始?

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

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

那么我的问题是,我将如何解析单帧。我一直在阅读文档并查看了iFrameExtractor(这不是很有帮助,因为它会解码帧)。我想当我应该使用来自 FFMPEG-AVFormat 的 mov.c 时,我已经正确理解了,但我不确定。

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

  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,从帧复制数据时我做错了吗?有任何想法吗。当我尝试NSData* frame使用其(非原子,保留)属性设置类变量时,我得到了 EXC_...。(它在合成行上显示 EXC_BAD_ACC)

4

3 回答 3

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 我使用这段代码(我相信它来自 Martin Bö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;

希望这对将来的某人有所帮助。

于 2011-08-18T12:49:35.763 回答
0

这里有一个很好的关于使用 libavcodec/libavformat 的教程。听起来您感兴趣的是DoSomethingWithTheImage()他们未实现的功能。

于 2011-08-15T11:37:24.750 回答
0

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

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

于 2011-08-15T12:48:56.477 回答