如何独立处理AVURLAsset的单独轨道?

时间:2011-05-18 01:29:49

标签: objective-c cocoa-touch avfoundation

这是我的目标:我想将.3gp电影文件加载到AVURLAsset。然后我想拍摄视频轨道并将输出帧泵入OpenGL ES纹理。这将是视频播放。然后我想继续利用AVFoundation播放音频。这个框架非常庞大,所以我希望能有一些老练的帮助。

我实际上让两个部分分开工作,但是当我尝试同时做两件事时总会出错。这是我目前的尝试,简而言之(为简洁起见,省略了所有错误处理):

我将.3gp文件加载到AVURLAsset并加载曲目:

NSURL* fileURL = [[NSBundle mainBundle] URLForResource:someName withExtension:someExtension];
AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
[asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler:^ {/* More Code */}];

在完成处理程序中,我获得了对音频和视频轨道的引用:

// Tracks loaded, grab the audio and video tracks.
AVAssetTrack* videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack* audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];

接下来,我创建了仅包含音轨和视频轨道的单独AVMutableComposition。我不确定这是否完全必要,但它似乎是一个好主意,它似乎也有效:

// Make a composition with the video track.
AVMutableComposition* videoComposition = [AVMutableComposition composition];
AVMutableCompositionTrack* videoCompositionTrack = [videoComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[videoCompositionTrack insertTimeRange:[videoTrack timeRange] ofTrack:videoTrack atTime:CMTimeMake(0, 1) error:nil];

// Make a composition with the audio track.
AVMutableComposition* audioComposition = [AVMutableComposition composition];
AVMutableCompositionTrack* audioCompositionTrack = [audioComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[audioCompositionTrack insertTimeRange:[audioTrack timeRange] ofTrack:audioTrack atTime:CMTimeMake(0, 1) error:nil];

现在我详细介绍如何处理每个音轨。我相信我拥有处理视频轨道的唯一方式,即为视频合成创建AVAssetReader,并添加使用视频创建的AVAssetTrackReaderOutput作曲轨道。通过保持对该轨道输出的引用,我可以调用其-copyNextSampleBuffer方法来获取将视频输出泵入OpenGL ES纹理所需的信息。这本身就足够好了:

// Create Asset Reader and Output for the video track.
NSDictionary* settings = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString *)kCVPixelBufferPixelFormatTypeKey];
_assetReader = [[AVAssetReader assetReaderWithAsset:vComposition error:nil] retain];
_videoTrackOutput = [[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:vCompositionTrack outputSettings:settings] retain];
[_assetReader addOutput:_videoTrackOutput];
[_assetReader startReading];

似乎破坏整个事情的是试图以任何方式播放音频。我不确定采用哪种方法来保留剩余的音轨。只是坚持AVFoundation的领域,我看到两种可能的方法。第一种是使用AVPlayer播放音频合成:

// Create a player for the audio.
AVPlayerItem* audioPlayerItem = [AVPlayerItem playerItemWithAsset:aComposition];
AVPlayer* audioPlayer = [[AVPlayer playerWithPlayerItem:audioPlayerItem] retain];
[audioPlayer play];

这很有效,因为我可以听到所需的音频。不幸的是,在调用-copyNextSampleBuffer时,创建此播放器可确保视频合成的AVAssetReaderTrackOutput失败并出现神秘错误:

  

AVAssetReaderStatusFailed

     

错误Domain = AVFoundationErrorDomain   代码= -11800“操作不能   完成“UserInfo = 0x456e50   {NSLocalizedFailureReason =未知   发生错误(-12785),   NSUnderlyingError = 0x486570“The   操作无法完成。   (OSStatus错误-12785。)“,   NSLocalizedDescription =操作   无法完成}

我对他们如何互相干扰感到困惑,但无论如何,这种方法似乎都是死路一条。

我考虑用于音频播放的另一个选项是AVAudioPlayer类,但我无法使用AVAsset作为起点。我尝试将其-initWithData:error:方法与通过聚合CMSampleBufferRefs的内容而构建的NSData一起使用,其方法与我在视频轨道上使用的方法相同,但似乎没有正确格式化。

此时,我觉得我在盲目地挥舞着,如果有人能告诉我这种方法是否可行,我会非常喜欢它。如果不是,我当然会欣赏一个可行的。

1 个答案:

答案 0 :(得分:3)

为每个轨道创建AVMutableCompositions(基本上是新的AVAssets)似乎是围绕着我,我只是在音轨上使用AVAssetReader。此外,您的videoComposition似乎没有在任何地方使用,所以为什么要创建它呢?

在任何情况下,要使任一解决方案正常工作,请将您的音频会话类别设置为kAudioSessionCategory_MediaPlayback并启用kAudioSessionProperty_OverrideCategoryMixWithOthers

我从来没有找到任何解释为什么这是必要的文档。