【问题标题】:How to merge Audio and video using AVMutableCompositionTrack如何使用 AVMutableCompositionTrack 合并音频和视频
【发布时间】:2013-03-01 04:37:48
【问题描述】:

在我的应用程序中,我需要合并音频和视频,然后我需要在 Mediaplayer 中播放音频文件。如何在IOS中合并音频和视频。是否有任何源代码。请给我一些建议

提前致谢

【问题讨论】:

  • 做一些研究 - 例如查看 WWDC 视频 + 示例代码。

标签: ios ios4 avmutablecomposition


【解决方案1】:

使用这个

AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:videoUrl options:nil];

AVMutableComposition* mixComposition = [AVMutableComposition composition];

AVMutableCompositionTrack *compositionCommentaryTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio 
                                                                                    preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration) 
                                    ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] 
                                     atTime:kCMTimeZero error:nil];

AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo 
                                                                                    preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) 
                               ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] 
                                atTime:kCMTimeZero error:nil];

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

NSString* videoName = @"export.mov";

NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL    *exportUrl = [NSURL fileURLWithPath:exportPath];

if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) 
{
    [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}

_assetExport.outputFileType = @"com.apple.quicktime-movie";
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;

[_assetExport exportAsynchronouslyWithCompletionHandler:
 ^(void ) {      
            // your completion code here
     }       
 }
 ];

【讨论】:

  • 我试过这段代码。它不起作用,并且上述编码中也存在一个错误。将 initWithURL 替换为 URLAssetWithURL
  • 我将此代码用于 1s 音频文件和 3s 视频文件。结果是一个视频有 1 秒的音频黑屏,然后是 2 秒的黑屏,然后是 3 秒的视频。你知道什么可能导致这个问题吗?我只想将音频添加到视频的开头。
  • 我只合并一个音频/视频文件。问题是,我的视频文件为 40 秒,音频文件为 28 秒。所以剩下的 12 (40-28) 秒——我想在音频文件中从 0 秒开始重复。我该怎么做?有直接的方法吗?
  • @BrandonA : NSString *videoPath = [[NSBundle mainBundle] pathForResource:@"资源名称" ofType:@"MOV"]; NSURL *videoURl = [NSURL fileURLWithPath:videoPath];
【解决方案2】:

您可以通过创建可变组合来合并视频。

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

NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],@"MyAudio.m4a",nil];

  NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
AVAsset *audioAsset = [AVAsset assetWithURL:outputFileURL];

//Create mutable composition of audio type
 AVMutableCompositionTrack *audioTrack = [composition    addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

[audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,video1.duration)
ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];

  AVMutableCompositionTrack* composedTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

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


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

[exporter exportAsynchronouslyWithCompletionHandler:^{
           case AVAssetExportSessionStatusFailed:
                 NSLog(@"Failed to export video");
                 break;
           case AVAssetExportSessionStatusCancelled:
                 NSLog(@"export cancelled");
                 break;

}

对于视频合并,请访问本教程。 http://iosbucket.blogspot.in/2015/04/mp4-conversion-and-video-merging-in-ios.html

您还可以找到合并视频的示例项目。

【讨论】:

    【解决方案3】:

    【讨论】:

    • 请注意 link-only answers 是不鼓励的,所以答案应该是寻找解决方案的终点(与另一个中途停留的参考相比,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的概要,并保留链接作为参考。
    【解决方案4】:

    现在回答有点晚,但它可以帮助将来的人。如果视频时长大于音频,则重复音频。

    + (void)mergeVideoWithAudio:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl success:(void (^)(NSURL *url))success failure:(void (^)(NSError *error))failure {
        AVMutableComposition *mixComposition = [AVMutableComposition new];
        NSMutableArray<AVMutableCompositionTrack *> *mutableCompositionVideoTrack = [NSMutableArray new];
        NSMutableArray<AVMutableCompositionTrack *> *mutableCompositionAudioTrack = [NSMutableArray new];
        AVMutableVideoCompositionInstruction *totalVideoCompositionInstruction = [AVMutableVideoCompositionInstruction new];
        
        AVAsset *aVideoAsset = [AVAsset assetWithURL:videoUrl];
        AVAsset *aAudioAsset = [AVAsset assetWithURL:audioUrl];
        
        AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
        AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
        if (videoTrack && audioTrack) {
            [mutableCompositionVideoTrack addObject:videoTrack];
            [mutableCompositionAudioTrack addObject:audioTrack];
            
            AVAssetTrack *aVideoAssetTrack = [aVideoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject;
            AVAssetTrack *aAudioAssetTrack = [aAudioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject;
            
            if (aVideoAssetTrack && aAudioAssetTrack) {
                [mutableCompositionVideoTrack.firstObject insertTimeRange:CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration) ofTrack:aVideoAssetTrack atTime:kCMTimeZero error:nil];
                
                CMTime videoDuration = aVideoAsset.duration;
                if (CMTimeCompare(videoDuration, aAudioAsset.duration) == -1) {
                    [mutableCompositionAudioTrack.firstObject insertTimeRange:CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration) ofTrack:aAudioAssetTrack atTime:kCMTimeZero error:nil];
                } else if (CMTimeCompare(videoDuration, aAudioAsset.duration) == 1) {
                    CMTime currentDuration = kCMTimeZero;
                    while (CMTimeCompare(currentDuration, videoDuration) == -1) {
                        // repeats audio
                        CMTime restTime = CMTimeSubtract(videoDuration, currentDuration);
                        CMTime maxTime = CMTimeMinimum(aAudioAsset.duration, restTime);
                        [mutableCompositionAudioTrack.firstObject insertTimeRange:CMTimeRangeMake(kCMTimeZero, maxTime) ofTrack:aAudioAssetTrack atTime:currentDuration error:nil];
                        currentDuration = CMTimeAdd(currentDuration, aAudioAsset.duration);
                    }
                }
                videoTrack.preferredTransform = aVideoAssetTrack.preferredTransform;
                totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration);
            }
        }
        
        NSString *outputPath = [NSHomeDirectory() stringByAppendingPathComponent:@"tmp/screenCapture.mp4"];
        if ([[NSFileManager defaultManager] fileExistsAtPath:outputPath]) {
            [[NSFileManager defaultManager] removeItemAtPath:outputPath error:nil];
        }
        NSURL *outputURL = [NSURL fileURLWithPath:outputPath];
        
        AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
        exportSession.outputURL = outputURL;
        exportSession.outputFileType = AVFileTypeMPEG4;
        exportSession.shouldOptimizeForNetworkUse = YES;
        
        // try to export the file and handle the status cases
        [exportSession exportAsynchronouslyWithCompletionHandler:^{
            switch (exportSession.status) {
                case AVAssetExportSessionStatusFailed:
                    failure(exportSession.error);
                    break;
                case AVAssetExportSessionStatusCancelled:
                    failure(exportSession.error);
                    break;
                default:
                    success(outputURL);
                    break;
            }
        }];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-10
      • 2012-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多