如何同时将AVAssetReader和AVAssetWriter用于多个轨道(音频和视频)? [英] How to use AVAssetReader and AVAssetWriter for multiple tracks (audio and video) simultaneously?
问题描述
我知道如何使用AVAssetReader和AVAssetWriter,并成功使用它们从一部电影中获取视频轨道并将其转码为另一部电影。不过,我也想用音频来做这件事。在完成初始转码后,我是否必须创建和AVAssetExportSession,或者在写入会话期间是否有某种方式在轨道之间切换?我不想处理AVAssetExportSession的开销。
I know how to use AVAssetReader and AVAssetWriter, and have successfully used them to grab a video track from one movie and transcode it into another. However, I'd like to do this with audio as well. Do I have to create and AVAssetExportSession after I've done with the initial transcode, or is there some way to switch between tracks while in the midst of a writing session? I'd hate to have to deal with the overhead of an AVAssetExportSession.
我问因为,使用拉式方法 - (while([assetWriterInput isReadyForMoreMediaData])
{...} - 仅假设一首曲目。它如何用于多个曲目,即音频和视频曲目?
I ask because, using the pull style method - (while ([assetWriterInput isReadyForMoreMediaData]) {...} - assumes one track only. How could it be used for more than one track, i.e. both an audio and a video track?
推荐答案
AVAssetWriter
将自动在其关联的 AVAssetWriterInput
上交错请求,以便集成不同的轨道输入文件。只需为你拥有的每个曲目添加 AVAssetWriterInput
,然后调用 requestMediaDataWhenReadyOnQueue:usingBlock:
在每个 AVAssetWriterInput
s。
AVAssetWriter
will automatically interleave requests on its associated AVAssetWriterInput
s in order to integrate different tracks into the output file. Just add an AVAssetWriterInput
for each of the tracks that you have, and then call requestMediaDataWhenReadyOnQueue:usingBlock:
on each of your AVAssetWriterInput
s.
这是我调用的方法 requestMediaDataWhenReadyOnQueue :usingBlock:
。我通过循环调用我的输出/输入对的这个方法。(一个单独的方法对于代码可读性和因为,与循环不同,每个调用都为块设置一个单独的堆栈帧。)
Here's a method I have that calls requestMediaDataWhenReadyOnQueue:usingBlock:
. I call this method from a loop over the number of output/input pairs I have. (A separate method is good both for code readability and also because, unlike a loop, each call sets up a separate stack frame for the block.)
你只需要一个 dispatch_queue_t
并可以将其重复用于所有曲目。请注意,您肯定应不从您的块中调用 dispatch_async
,因为 requestMediaDataWhenReadyOnQueue:usingBlock:
我希望该块能够阻塞,直到它填充了与 AVAssetWriterInput
将要采用的数据一样多的数据。你不想在那之前返回。
You only need one dispatch_queue_t
and can reuse it for all of the tracks. Note that you definitely should not call dispatch_async
from your block, because requestMediaDataWhenReadyOnQueue:usingBlock:
expects the block to, well, block until it has filled in as much data as the AVAssetWriterInput
will take. You don't want to return before then.
- (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;
}
}
}
];
}
这篇关于如何同时将AVAssetReader和AVAssetWriter用于多个轨道(音频和视频)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!