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

问题描述 投票:5回答:1

这是我的目标:我想将.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];

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

// 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

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

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

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

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

objective-c cocoa-touch avfoundation
1个回答
3
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.