我正在尝试从.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但我不确定时,我想我已经理解了它。
编辑: 我现在正在尝试这样:
我运行略微减少的init函数i iFrameExtractor,它在.mov文件中找到了视频流。
我得到了这样的框架数据:
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)
答案 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,则需要分段流式传输(又称苹果直播)。