欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

媒体合成和编辑

程序员文章站 2022-07-14 18:46:25
...

媒体合成和编辑

组合媒体

媒体合成和编辑

AVFoundation有关资源组合的功能源于AVAsset的子类AVComposition。一个组合就是将其他几种媒体资源组合成一个自定义的临时排列,再将这个临时排列视为一个可以呈现或处理的独立媒体项目。就比如AVAsset对象,组合相当于包含了一个或多个给定类型的媒体轨道的容器。AVComposition中轨道都是AVAssetTrack的子类AVCompositionTrack。一个组合轨道本身由一个或多个媒体片段组成,由AVCompositionTrackSegment类定义,代表这个组合中的实际媒体区域。

AVCompositionAVCompositionTrack都是不可变对象,提供对资源的只读操作。这些对象提供了一个合适的接口让应用程序的一部分可以进行播放或处理。不过,当创建自己的组合时,就需要使用AVMutableCompositionAVMutableCompositionTrack所提供的可变子类。这些对象提供的接口需要操作轨道和轨道分段,这样就可以创建所需的临时排列了。

要创建自定义组合,需指定在将要添加到组合的源媒体的时间范围,还要指定要添加片段的每个轨道的位置。

AVMutableComposition和AVMutableCompositionTrack

AVMutableComposition

AVMutableComposition可以添加或删除tracks,和添加、删除、缩放time range
AVMutableCompositionassets集合在一起,如下所示:

媒体合成和编辑

创建Composition
使用AVMutableComposition类创建Composition,为把媒体数据添加到composition中,需添加一个或多个由AVMutableCompositionTrack类表示的composition tracks
最简单的例子是使用一个video track和一个audio track创建一个可变的composition,如下:

AVMutableComposition *mutableComposition = [AVMutableComposition composition];
// Create the video composition track.
AVMutableCompositionTrack *mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
// Create the audio composition track.
AVMutableCompositionTrack *mutableCompositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

当把一个tracks添加到一个composition中时,需提供一个media type和一个track ID

  • media type 最常用的 media type的是AVMediaTypeVideoAVMediaTypeAudio,不过也可使用AVMediaTypeSubtitleAVMediaTypeText
  • 与视听数据相关联的每个轨道都具有一个称为track ID的唯一标识符。可使用kCMPersistentTrackID_Invalid来表示AVFoundation应该自动生成一个正确的轨道ID。

addMutableTrackWithMediaType:preferredTrackID:方法添加一个空的trackcomposition

添加数据到Composition

创建好composition后,就需要把媒体数据添加到对应的track中,需通过AVAsset对象。如下的例子,把添加2个不同的的video asset tracks到同一个composition track

// You can retrieve AVAssets from a number of places, like the camera roll for example.
AVAsset *videoAsset = <#AVAsset with at least one video track#>;
AVAsset *anotherVideoAsset = <#another AVAsset with at least one video track#>;
// Get the first video track from each asset.
AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *anotherVideoAssetTrack = [[anotherVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
// Add them both to the composition.
[mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAssetTrack.timeRange.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];
[mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,anotherVideoAssetTrack.timeRange.duration) ofTrack:anotherVideoAssetTrack atTime:videoAssetTrack.timeRange.duration error:nil];

insertTimeRange:ofTrack:atTime:error:方法添加一个时间范围的track

导出组合

使用AVAssetExportSession对象导出组合,设置其输出的URL,并设置其输出文件类型

// Create the export session with the composition and set the preset to the highest quality.

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

// Set the desired output URL for the file created by the export process.

exporter.outputURL = [[[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:@YES error:nil] URLByAppendingPathComponent:[kDateFormatter stringFromDate:[NSDate date]]] URLByAppendingPathExtension:CFBridgingRelease(UTTypeCopyPreferredTagWithClass((CFStringRef)AVFileTypeQuickTimeMovie, kUTTagClassFilenameExtension))];

// Set the output file type to be a QuickTime movie.

exporter.outputFileType = AVFileTypeQuickTimeMovie;

调用其exportAsynchronouslyWithCompletionHandler:方法开始导出过程,如下
首先在在主队列检查导出会话状态,如果导出成功完成,则将导出的视频文件写入AssetsLibrary

    [self.exportSession exportAsynchronouslyWithCompletionHandler:^{       

        dispatch_async(dispatch_get_main_queue(), ^{                   
            AVAssetExportSessionStatus status = self.exportSession.status;
            if (status == AVAssetExportSessionStatusCompleted) {
                [self writeExportedVideoToAssetsLibrary];
            } else {
                [UIAlertView showAlertWithTitle:@"Export Failed"
                                        message:@"The request export failed."];
            }
        });
    }];

......
    - (void)writeExportedVideoToAssetsLibrary {
        NSURL *exportURL = self.exportSession.outputURL;
        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:exportURL]) {  

            [library writeVideoAtPathToSavedPhotosAlbum:exportURL              
                                        completionBlock:^(NSURL *assetURL,
                                                          NSError *error) {

                if (error) {                                                    
                    NSString *message = @"Unable to write to Photos library.";
                    [UIAlertView showAlertWithTitle:@"Write Failed"
                                            message:message];
                }

                [[NSFileManager defaultManager] removeItemAtURL:exportURL       
                                                          error:nil];
            }];
        } else {
            NSLog(@"Video could not be exported to assets library.");
        }
        self.exportSession = nil;
    }

例子

合成的例子,可参考Merging Audio and Video in Native iOS,一个简单的音频和视频合成的例子:

媒体合成和编辑

另外在《AV Foundation开发秘籍》中也有介绍

资源