2011-05-18 25 views
5

这是我的目标:我想将一个.3gp电影文件加载到AVURLAsset。然后,我想拍摄视频轨道,并将输出帧抽成OpenGL ES纹理。这将是视频播放。然后我想继续利用AVFoundation播放音频。这个框架非常庞大,所以我希望在这个框架上提供一些经验丰富的帮助。如何独立处理AVURLAsset的单独轨道?

我实际上有两个部分单独工作,但是当我尝试同时执行两个操作时总会出错。这是我当前的尝试,简而言之(此不再赘述所有错误处理):

我加载名为.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]; 

这工作,因为我可以听到想要的声音。不幸的是创建这个播放器保证了AVAssetReaderTrackOutput用于视频通话组成时-copyNextSampleBuffer失败,一个神秘的错误:

AVAssetReaderStatusFailed

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

我感到困惑它们如何相互干扰,但无论如何,这种做法似乎是一个死胡同。

我认为音频播放的另一种选择是AVAudioPlayer类,但我无法让它与AVAsset一起工作。我试图使用它的-initWithData:error:方法,通过聚合CMSampleBufferRefs的内容构建NSData,并采用与我在视频轨道上使用的方法相同的方法,但它似乎没有正确格式化。

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

回答

3

为每个轨道创建AVMutableCompositions(基本上是新的AVAssets)似乎对我来说很简单,我只是在音轨上使用AVAssetReader。另外,你的videoComposition似乎并没有在任何地方使用,所以为什么要创建它?

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

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

+0

我省略了使用视频合成的代码,因为它的工作原理并且会增加已经很长的问题的大小。无论如何,在音频会话中设置这些属性确定了问题。谢谢你为我节省了几个小时的挫折。我从来没有听说过AVAudioSession ... – 2011-05-18 16:44:33

+0

不客气。解决方案绝对不明显。 – 2011-05-18 16:55:32