使用 AVMutableComposition 组合视频和音频

Posted

技术标签:

【中文标题】使用 AVMutableComposition 组合视频和音频【英文标题】:Composing video and audio using AVMutableComposition 【发布时间】:2013-01-09 22:55:44 【问题描述】:

我有一个奇怪的问题。在我的应用程序中,我使用下面的代码组合了多个音频和视频文件。一旦我将生成的视频从设备下载到计算机并使用 Quick Time 播放,生成的视频似乎工作正常,但每当我尝试使用 UIWebView 或 AVPLayer 播放新合成的视频时,我只能看到合并视频文件的第一部分。

此外,当我尝试使用 MPMoviePlayerController 播放时,它会挂在“正在加载”中。

我可以听到所有乐曲的音频。为了清楚起见,我有两个数组: 1-带有音频文件路径的音频片段[song1,song2,song3]; 2-带有视频文件路径的moviePieces [movie1,movie2,movie3]; 合并这些文件后,我只能看到movie1,但可以听到song1 + song2 + song3。 附言歌曲和电影的长度不同(差异小于 0.2 秒)。 任何帮助将不胜感激。 先感谢您, 亚努斯

-(void)putFilesTogether
AVMutableComposition *mixComposition = [AVMutableComposition composition]; 
AVMutableCompositionTrack *videoCompositionTrack =[[AVMutableCompositionTrack alloc]init];
AVMutableCompositionTrack *audioCompositionTrack =[[AVMutableCompositionTrack alloc]init];

NSLog(@" movie  %@ audio %@ ", moviePieces, audioPieces);


NSError * error;
for(int i=0;i<moviePieces.count;i++)

    NSFileManager * fm = [NSFileManager defaultManager];
    NSString * movieFilePath;
    NSString * audioFilePath;
    movieFilePath = [moviePieces objectAtIndex:i];
    audioFilePath = [audioPieces objectAtIndex:i];


    if(![fm fileExistsAtPath:movieFilePath])
        NSLog(@"Movie doesn't exist %@ ",movieFilePath);
    
    else
        NSLog(@"Movie exist %@ ",movieFilePath);
    

    if(![fm fileExistsAtPath:audioFilePath])
        NSLog(@"Audio doesn't exist %@ ",audioFilePath);
    
    else
        NSLog(@"Audio exists %@ ",audioFilePath);
    


   NSURL *videoUrl = [NSURL fileURLWithPath:movieFilePath];
   NSURL *audioUrl = [NSURL fileURLWithPath:audioFilePath];


    AVURLAsset *videoasset = [[AVURLAsset alloc]initWithURL:videoUrl options:nil];
     AVAssetTrack *videoAssetTrack= [[videoasset tracksWithMediaType:AVMediaTypeVideo] lastObject];

    AVURLAsset *audioasset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
    AVAssetTrack *audioAssetTrack= [[audioasset tracksWithMediaType:AVMediaTypeAudio] lastObject];

    videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    CMTime tempTime = mixComposition.duration;

    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset.duration) ofTrack:audioAssetTrack atTime:tempTime error:&error];

    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoasset.duration) ofTrack:videoAssetTrack atTime:tempTime error:&error];

    if(error)
    
        NSLog(@"Ups. Something went wrong! %@", [error debugDescription]);
    



NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];

float ran = arc4random()%1000;
NSString * pathToSave = [NSString stringWithFormat:@"Output%@%f.mp4",caldate,ran];
pathToSave =[DOCUMENTS_FOLDER stringByAppendingPathComponent:pathToSave];
NSURL *movieUrl = [NSURL fileURLWithPath:pathToSave];

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

exporter.outputFileType=AVFileTypeQuickTimeMovie;
exporter.outputURL=movieUrl;
exporter.shouldOptimizeForNetworkUse=YES;

CMTimeValue val = mixComposition.duration.value;

CMTime start=CMTimeMake(0, 600);
CMTime duration=CMTimeMake(val, 600);
CMTimeRange range=CMTimeRangeMake(start, duration);
exporter.timeRange=range;

[exporter exportAsynchronouslyWithCompletionHandler:^
    switch ([exporter status]) 
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export failed: %@ %@", [[exporter error] localizedDescription],[[exporter error]debugDescription]);
            NSString * message = @"Movie wasn't created. Try again later.";
            [self performSelectorOnMainThread:@selector(dismissMe:) withObject:message waitUntilDone:NO];
            break;
        case AVAssetExportSessionStatusCancelled: NSLog(@"Export canceled");
            NSString * message1 = @"Movie wasn't created. Try again later.";
            [self performSelectorOnMainThread:@selector(dismissMe:) withObject:message1 waitUntilDone:NO];
            break;
        case AVAssetExportSessionStatusCompleted:
        
            NSString * message = @"Movie was successfully created.";
            CMTime duration = mixComposition.duration;

            [self saveData:duration ofPath:pathToSave];
            [self cleanFiles];
            [self performSelectorOnMainThread:@selector(dismissMe:) withObject:message waitUntilDone:NO];
        
    ];

【问题讨论】:

我只合并一个音频/视频文件。问题是,我的视频文件为 40 秒,音频文件为 28 秒。所以剩下的 12 (40-28) 秒 – 我想在音频文件中从 0 秒开始重复它。我该怎么做?有直接的方法吗? 【参考方案1】:

问题出在:

videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

它们需要移到 for 循环体之外。

【讨论】:

以上是关于使用 AVMutableComposition 组合视频和音频的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVPlayer 音频播放 AVMutableComposition 会不同步

使用 AVMutableComposition 组合视频和音频

使用 AVMutableComposition 导出镜像视频会导致调整大小问题

AVFoundation - 视频没有在 AVplayer 的 AVMutablecomposition 中播放

AVMutableComposition - 只播放第一首曲目 (Swift)

AVMutableComposition - 是不是可以有 2 个并行音轨?