iOS AVFoundation 导出会话缺少音频

Posted

技术标签:

【中文标题】iOS AVFoundation 导出会话缺少音频【英文标题】:iOS AVFoundation Export Session is missing audio 【发布时间】:2012-12-24 23:55:37 【问题描述】:

我正在使用 ios AVFoundation 框架,并且能够成功地合并视频轨道、图像叠加层和文本叠加层。但是,我的输出文件不会保留原始源视频中的音频。

如何确保我的一个视频的音频源与我创建的新视频保持一致?

编辑

*使用此代码有一个很好的示例,说明如何创建视频(带有原始音频)。对我来说,在使用 AVFoundation 处理视频时需要单独包含音轨并不明显。希望这对其他人有帮助。

    AVAssetTrack *videoTrack = nil;
    AVAssetTrack *audioTrack = nil;
    CMTime insertionPoint = kCMTimeZero;

    if([[url tracksWithMediaType:AVMediaTypeVideo] count] != 0) 
        videoTrack = [url tracksWithMediaType:AVMediaTypeVideo][0];
    

    if([[url tracksWithMediaType:AVMediaTypeAudio] count] != 0) 
        audioTrack = [url tracksWithMediaType:AVMediaTypeAudio][0];
    

    // Insert the video and audio tracks from AVAsset
    if (videoTrack != nil) 
        AVMutableCompositionTrack *compositionVideoTrack = [videoComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
        [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [url duration]) ofTrack:videoTrack atTime:insertionPoint error:&error];
    
    if (audioTrack != nil) 
        AVMutableCompositionTrack *compositionAudioTrack = [videoComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
        [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [url duration]) ofTrack:audioTrack atTime:insertionPoint error:&error];
    

【问题讨论】:

谢谢哥们!你救了我几天的痛苦 @ajs35 回答您自己的问题也是公认的做法!不要害怕这样做:-) 在我升级到 iOS9 SDK 之前,上述示例似乎运行良好。其他人在 iOS 9 中有同样的问题吗? 【参考方案1】:

这是解决这个问题的完整代码,它有两个视频,它们与他们的音频相结合:-

AVURLAsset* video1 = [[AVURLAsset alloc]initWithURL:[NSURL fileURLWithPath:path1] options:nil];

AVURLAsset* video2 = [[AVURLAsset alloc]initWithURL:[NSURL fileURLWithPath:path2] options:nil];

if (video1 !=nil && video2!=nil) 

    // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
    // 2 - Video track

    AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *firstTrackAudio = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];

    [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, video1.duration)
                        ofTrack:[[video1 tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
    [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, video2.duration)
                        ofTrack:[[video2 tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:video1.duration error:nil];

// 它有一个音轨

    if ([[video1 tracksWithMediaType:AVMediaTypeAudio] count] > 0)
    
        AVAssetTrack *clipAudioTrack = [[video1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
        [firstTrackAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, video1.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];
    

// 它有一个音轨

    if ([[video2 tracksWithMediaType:AVMediaTypeAudio] count] > 0)
    
        AVAssetTrack *clipAudioTrack = [[video2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
        [firstTrackAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, video2.duration) ofTrack:clipAudioTrack atTime:video1.duration error:nil];
    

// 导出会话

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                      presetName:AVAssetExportPresetHighestQuality];

    //Creates the path to export to  - Saving to temporary directory
    NSString* filename = [NSString stringWithFormat:@"Video_%d.mov",arc4random() % 1000];
    NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];

    //Checks if there is already a file at the output URL.  
    if ([[NSFileManager defaultManager] fileExistsAtPath:path])
    
        NSLog(@"Removing item at path: %@", path);
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    

    exporter.outputURL = [NSURL fileURLWithPath:path];
    //Set the output file type
    exporter.outputFileType = AVFileTypeQuickTimeMovie;


    path3=path;
    [arr_StoredDocumentoryUrls addObject:path3];

    //Exports!
    [exporter exportAsynchronouslyWithCompletionHandler:^
        switch (exporter.status) 
            case AVAssetExportSessionStatusCompleted:
                NSLog(@"Export Complete");

                break;
            
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export Error: %@", [exporter.error description]);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export Cancelled");
                break;
            default:
                break;
        
    ];


【讨论】:

非常感谢。这也为我节省了大量时间。【参考方案2】:

Swift 4 版本基于@Ashish 的回答

let video1 = AVURLAsset(url: videoURL1)
let video2 = AVURLAsset(url: videoURL2)

// Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
let mixComposition = AVMutableComposition()

guard let firstTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else return

guard let firstAudioTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio,preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else return
do 
  try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video1.duration),
                                 of: video1.tracks(withMediaType: AVMediaType.video)[0],
                                 at: kCMTimeZero)
 catch 
  print("error handling video1")


do 
  try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video2.duration),
                                 of: video2.tracks(withMediaType: AVMediaType.video)[0],
                                 at: kCMTimeZero)
 catch 
  print("error handling video2")


// if video 1 has an audio track
if video1.tracks.count > 0 
  let clipAudioTrack = video1.tracks[0]
  do 
    try firstAudioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video1.duration), of: clipAudioTrack, at: kCMTimeZero)
   catch 
    print("error inserting audio track 1")
  



// if video 2 has an audio track
if video2.tracks.count > 0 
  let clipAudioTrack = video2.tracks[0]
  do 
    try firstAudioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video2.duration), of: clipAudioTrack, at: video1.duration)
   catch 
    print("error inserting audio track 2")
  



// Checks if there is already a file at the output URL.
if FileManager.default.fileExists(atPath: "path") 
  try? FileManager.default.removeItem(atPath: "path")


// Create Exporter
guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else return

// Get path
guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else return
let documentUrl = documentDirectory.appendingPathComponent("mergeVideo.mov")

// Set the output file type
exporter.outputURL = documentUrl
exporter.outputFileType = AVFileType.mov

// Exports!
exporter.exportAsynchronously 
  switch exporter.status 
  case .completed:
    print("export completed")

  case .failed:
    print("export failed")

  case .cancelled:
    print("export candelled")

  default:
    break
  

【讨论】:

【参考方案3】:

尝试添加 MobileCoreServices 并执行。

【讨论】:

以上是关于iOS AVFoundation 导出会话缺少音频的主要内容,如果未能解决你的问题,请参考以下文章

OpenTok 在音频/视频会议会话中缺少音频

带有 Core Audio AudioQueue 的 AVFoundation 会话

谷歌移动广告 SDK Ios7 缺少音频框架

Swift实现iOS录音与播放音频功能

iOS 8 和 AVFoundation:如何调暗背景音频?

使用 AVFoundation 在 iOS 上录制音频样本