使用ffmpeg从.mov逐帧解析

Rob*_*Rye 5 parsing quicktime ffmpeg video-processing 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(电影数据,我认为可能不止一个).那么" 视频 "-atom然后在视频原子内(视频数据样本,可能有不止一个).我想我会相信几个原子是帧.这些将是"avc1"类型(这是H264的类型).请纠正我,因为我很确定我还没有正确地完成这一切.

我的问题是,我将如何解析单帧.我一直在阅读文档并查看了iFrameExtractor(由于它对帧进行解码,因此不是很有帮助).我想我理解正确的话时,我应该使用mov.c从FFMPEG-AVFormat,但我不知道.

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

  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;
    
    Run Code Online (Sandbox Code Playgroud)

然后我将它传递给NSOperation的子类,在那里保留等待上传.但我收到一个EXC_BAD_ACC,从框架中复制数据时我做错了什么?有任何想法吗.当我尝试NSData* frame使用其(非原子,保留)属性设置类变量时,我得到了EXC _... (它在合成行上说EXC_BAD_ACC)

Rob*_*Rye 1

我使用以下内容来解析 mov 文件中的每一帧。

\n\n
-(NSData *)nextFrame {\n    AVPacket packet;\n    NSData *frame = nil;\n\n    while(!frame && av_read_frame(pFormatCtx, &packet)>=0) {\n\n        if(packet.stream_index == streamNo) {\n            frame = [[[NSData alloc] initWithBytes:packet.data length:packet.size] autorelease];\n        }\n        av_free_packet(&packet);\n    }\n    return frame;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

尽管请注意,因为 av_read_frame 不会验证帧,但这是在解码步骤中完成的。这意味着返回的“帧”可能包含不属于实际帧的额外信息。

\n\n

要初始化 AVFormatContext *pFormatCtx 和 AVCodecContext *pCodecCtx 我使用此代码(我相信它源自 Martin B\xc3\xb6hme\ 的示例代码):

\n\n
    AVCodec *pCodec;\n\n    // Register all formats and codecs\n    av_register_all();\n\n    // Open video file\n    if(avformat_open_input(&pFormatCtx, [moviePath cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL)!=0)\n        goto initError; // Couldn\'t open file\n\n    // Retrieve stream information\n    if(avformat_find_stream_info(pFormatCtx,NULL)<0)\n        goto initError; // Couldn\'t find stream information\n\n    // Find the video stream\n    streamNo = -1;\n    for(int i=0; i<pFormatCtx->nb_streams; i++){\n        if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)\n        {\n            streamNo = i;\n            break;\n        }\n    }\n    if(streamNo == -1)\n        goto initError; // Didn\'t find a video stream\n\n    // Get a pointer to the codec context for the video stream\n    pCodecCtx=pFormatCtx->streams[streamNo]->codec;\n\n    // Find the decoder for the video stream\n    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);\n    if(pCodec==NULL)\n        goto initError; // Codec not found\n\n    // Open codec\n    if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)\n        goto initError; // Could not open codec\n\n    return self;\n\ninitError:\n    NSLog(@"initError in VideoFrameExtractor");\n    [self release];\n    return nil;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n