[英]How can I use AVAssetReader and AVAssetWriter to create a AAC file?
[英]How to use AVAssetReader and AVAssetWriter for multiple tracks (audio and video) simultaneously?
我知道如何使用AVAssetReader
和AVAssetWriter
,并成功地使用它们从一部电影中抓取视频轨道并将其转码为另一部电影。 但是,我也想用音频来做到这一点。 在完成初始转码后,我是否必须创建和AVAssetExportSession
,或者是否有某种方法可以在编写会话期间在曲目之间切换? 我不想处理AVAssetExportSession
的开销。
我问是因为,使用拉式方法 - while ([assetWriterInput isReadyForMoreMediaData]) {...}
- 仅假设一首曲目。 它如何用于多个轨道,即音频和视频轨道?
AVAssetWriter
将自动在其关联的AVAssetWriterInput
上交错请求,以便将不同的轨道集成到输出文件中。 只需为您拥有的每个轨道添加一个AVAssetWriterInput
,然后在您的每个AVAssetWriterInput
上调用requestMediaDataWhenReadyOnQueue:usingBlock:
。
这是我调用requestMediaDataWhenReadyOnQueue:usingBlock:
。 我从我拥有的输出/输入对数量的循环中调用此方法。 (单独的方法有利于代码可读性,还因为与循环不同,每次调用都会为块设置单独的堆栈帧。)
您只需要一个dispatch_queue_t
并且可以将其重复用于所有轨道。 请注意,您绝对不应该叫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;
}
}
}
];
}
您是否尝试过使用两个 AVAssetWriterInputs 并通过工作队列推送样本? 这是一个粗略的草图。
processing_queue = dispatch_queue_create("com.mydomain.gcdqueue.mediaprocessor", NULL);
[videoAVAssetWriterInput requestMediaDataWhenReadyOnQueue:myInputSerialQueue usingBlock:^{
dispatch_asyc(processing_queue, ^{process video});
}];
[audioAVAssetWriterInput requestMediaDataWhenReadyOnQueue:myInputSerialQueue usingBlock:^{
dispatch_asyc(processing_queue, ^{process audio});
}];
您可以使用调度组!
查看 MacOSX 的 AVReaderWriter 示例...
我直接从示例 RWDocument.m 中引用:
- (BOOL)startReadingAndWritingReturningError:(NSError **)outError
{
BOOL success = YES;
NSError *localError = nil;
// Instruct the asset reader and asset writer to get ready to do work
success = [assetReader startReading];
if (!success)
localError = [assetReader error];
if (success)
{
success = [assetWriter startWriting];
if (!success)
localError = [assetWriter error];
}
if (success)
{
dispatch_group_t dispatchGroup = dispatch_group_create();
// Start a sample-writing session
[assetWriter startSessionAtSourceTime:[self timeRange].start];
// Start reading and writing samples
if (audioSampleBufferChannel)
{
// Only set audio delegate for audio-only assets, else let the video channel drive progress
id <RWSampleBufferChannelDelegate> delegate = nil;
if (!videoSampleBufferChannel)
delegate = self;
dispatch_group_enter(dispatchGroup);
[audioSampleBufferChannel startWithDelegate:delegate completionHandler:^{
dispatch_group_leave(dispatchGroup);
}];
}
if (videoSampleBufferChannel)
{
dispatch_group_enter(dispatchGroup);
[videoSampleBufferChannel startWithDelegate:self completionHandler:^{
dispatch_group_leave(dispatchGroup);
}];
}
// Set up a callback for when the sample writing is finished
dispatch_group_notify(dispatchGroup, serializationQueue, ^{
BOOL finalSuccess = YES;
NSError *finalError = nil;
if (cancelled)
{
[assetReader cancelReading];
[assetWriter cancelWriting];
}
else
{
if ([assetReader status] == AVAssetReaderStatusFailed)
{
finalSuccess = NO;
finalError = [assetReader error];
}
if (finalSuccess)
{
finalSuccess = [assetWriter finishWriting];
if (!finalSuccess)
finalError = [assetWriter error];
}
}
[self readingAndWritingDidFinishSuccessfully:finalSuccess withError:finalError];
});
dispatch_release(dispatchGroup);
}
if (outError)
*outError = localError;
return success;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.