我知道如何使用AVAssetReader
and AVAssetWriter
,并成功地使用它们从一部电影中抓取视频轨道并将其转码为另一部电影。不过,我也想用音频来做到这一点。我必须创建并AVAssetExportSession
在我完成初始转码之后,或者是否有某种方法可以在写作过程中在轨道之间切换?我不想处理一个AVAssetExportSession
.
我问是因为,使用拉式方法 -while ([assetWriterInput isReadyForMoreMediaData]) {...}
- 假设只有一首曲目。它如何用于多个轨道,即音频轨道和视频轨道?
AVAssetWriter
将自动交错与其关联的请求AVAssetWriterInput
s 以便将不同的轨道集成到输出文件中。只需添加一个AVAssetWriterInput
对于您拥有的每个曲目,然后调用requestMediaDataWhenReadyOnQueue:usingBlock:
在你的每一个AVAssetWriterInput
s.
这是我调用的方法requestMediaDataWhenReadyOnQueue:usingBlock:
。我从对我拥有的输出/输入对的数量的循环中调用此方法。 (单独的方法不仅有利于代码的可读性,而且还因为与循环不同,每个调用都会为块设置一个单独的堆栈帧。)
你只需要一个dispatch_queue_t
并可以将其重复用于所有轨道。请注意,您绝对应该not call dispatch_async
从你的街区开始,因为requestMediaDataWhenReadyOnQueue:usingBlock:
期望该块能够阻塞,直到它填充了与AVAssetWriterInput
会采取。在那之前你不想回来。
- (void)requestMediaDataForTrack:(int)i {
AVAssetReaderOutput *output = [[_reader outputs] objectAtIndex:i];
AVAssetWriterInput *input = [[_writer inputs] objectAtIndex:i];
[input requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock:
^{
[self retain];
while ([input isReadyForMoreMediaData]) {
CMSampleBufferRef sampleBuffer;
if ([_reader status] == AVAssetReaderStatusReading &&
(sampleBuffer = [output copyNextSampleBuffer])) {
BOOL result = [input appendSampleBuffer:sampleBuffer];
CFRelease(sampleBuffer);
if (!result) {
[_reader cancelReading];
break;
}
} else {
[input markAsFinished];
switch ([_reader status]) {
case AVAssetReaderStatusReading:
// the reader has more for other tracks, even if this one is done
break;
case AVAssetReaderStatusCompleted:
// your method for when the conversion is done
// should call finishWriting on the writer
[self readingCompleted];
break;
case AVAssetReaderStatusCancelled:
[_writer cancelWriting];
[_delegate converterDidCancel:self];
break;
case AVAssetReaderStatusFailed:
[_writer cancelWriting];
break;
}
break;
}
}
}
];
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)