AVFoundation Programming Guide - Editing

Editing  

AVFoundation框架提供了一组功能丰富的类,以便于编辑音频可视化资源。AVFoundation中编辑的API的核心是组合。组合仅仅是一个或多个不同媒体资产的轨道集合。AVMutableComposition类提供了一个接口,用于插入和删除轨道,并管理它们的时间顺序。图3-1展示了如何从现有资源组合中拼凑出一个新的组合,从而形成新的资源。如果您只想将多个资源按顺序合并到一个文件中,则可以根据需要进行更详细的说明。如果您想要在合成中的轨道上执行任何自定义音频或视频处理,则需要分别合并 音频混合 或 视频合成。

Figure 3-1  AVMutableComposition assembles assets together(AVMutableComposition将资源组装在一起

补充知识点:

AVAsset:素材库里的素材;
AVAssetTrack:素材的轨道;
AVMutableComposition :一个用来合成视频的工程文件;
AVMutableCompositionTrack :工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材;


使用AVMutableAudioMix类,您可以在您的组合的音频轨迹上执行自定义音频处理,如图3-2所示。目前,您可以指定一个音频轨道的最大音量或设置音量。

Figure 3-2  AVMutableAudioMix performs audio mixing( AVMutableAudioMix执行音频混合)

补充知识点

AVMutableComposition :一个用来合成视频的工程文件;

AVMutableCompositionTrack :工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材;

AVMutableVideoComposition:用来生成video的组合指令,包含多段instruction。可以决定最终视频的尺寸,裁剪需要在这里进行;
AVMutableVideoCompositionInstruction:一个指令,决定一个timeRange内每个轨道的状态,包含多个layerInstruction;
AVMutableVideoCompositionLayerInstruction:在一个指令的时间范围内,某个轨道的状态;

AVAssetExportSession:对象转码以及输出,对一个AVAsset对象进行操作,用来做视频处理输出。


您可以使用AVMutableVideoComposition类直接处理组合中的视频轨道以进行编辑,如图3-3所示。使用单个视频合成,您可以为输出的视频指定所需的渲染大小和比例以及帧持续时间。通过视频合成的指令(由AVMutableVideoCompositionInstruction类表示),您可以修改视频的背景颜色并应用层指令。这些图层指令(由AVMutableVideoCompositionLayerInstruction类表示)可用于应用变换,将渐变,不透明度和不透明度渐变应用于组合中的视频轨道。视频组合类还使您可以使用animationTool属性将Core Animation framework的效果引入到视频中。


要将您的组合与 音频组合和视频组合 相结合,可以使用AVAssetExportSession对象,如图3-4所示。您使用组合初始化 导出会话,然后分别将 音频组合 和 视频组合 分配给audioMix和videoComposition属性。

Figure 3-4  Use AVAssetExportSession to combine media elements into an output file(使用AVAssetExportSession将媒体元素组合到输出文件中


Creating a Composition(创建一个组合

要创建自己的组合,可以使用AVMutableComposition类。将媒体数据添加到你的组合中,您必须添加一个或多个合成轨道,由AVMutableCompositionTrack类表示。最简单的情况是创建一个可变的组合,其中有一个视频轨道一个音频轨道:

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];

Options for Initializing a Composition Track(初始化合成轨道的选项

在添加新轨道时,您必须同时提供媒体类型和轨道ID。虽然音频和视频是最常用的媒体类型,但您也可以指定其他媒体类型,如AVMediaTypeSubtitle或AVMediaTypeText。每个与某些视听数据相关的轨道都有一个唯一的标识符,称为轨道ID。如果您将kCMPersistentTrackID_Invalid指定为首选轨道ID,则会为您自动生成与轨道相关联的唯一标识符。

Adding Audiovisual Data to a Composition(将视听数据添加到合成中

一旦您有了一个或多个轨道的组合,您就可以开始将您的媒体数据添加到适当的轨道上。要将媒体数据添加到合成轨道上,您需要访问媒体数据所在的AVAsset对象。您可以。使用可变组合轨道接口将多个具有相同底层媒体类型的音轨放在同一轨道上以下示例说明如何将两个不同的视频资源轨道按顺序添加到相同的组合轨道中

// You can retrieve AVAssets from a number of places, like the camera roll for example.您可以从多个位置检索AVAssets,例如相机胶卷

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];

Retrieving Compatible Composition Tracks(检索兼容的组合轨道

在可能的情况下,每种媒体类型只能有一个轨道组合。兼容资产轨道的这种统一导致最少的资源使用量。当连续显示媒体数据时,您应该将相同类型的任何媒体数据放置在相同的合成轨道上您可以查询一个可变组合,以确定是否有与您所需的资源轨道相兼容的组合轨道

AVMutableCompositionTrack *compatibleCompositionTrack = [mutableComposition mutableTrackCompatibleWithTrack:<#the AVAssetTrack you want to insert#>];

if (compatibleCompositionTrack) {

    // Implementation continues.继续执行

}
注意:将多个视频片段放置在相同的组合轨迹上,可能会导致在视频片段(尤其是嵌入式设备)的转换过程中可能会导致播放时丢帧为您的视频片段选择组合轨道的数量完全取决于您的应用和其预期平台的设计。

Generating a Volume Ramp(生成一个音量坡道

一个AVMutableAudioMix对象可以单独对组合中的所有音轨执行自定义音频处理。您可以使用audioMix类方法创建音频混合,并使用AVMutableAudioMixInputParameters类的实例将音频混合与组合中的特定音轨相关联。音频混合可以用来改变音轨的音量。下面的示例展示了如何在特定的音频轨道上设置音量渐变,以便在组合的持续时间内逐渐淡出音频。

AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix];音频混合

// Create the audio mix input parameters object.创建音频混合输入参数对象

AVMutableAudioMixInputParameters *mixParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:mutableCompositionAudioTrack];

// Set the volume ramp to slowly fade the audio out over the duration of the composition.设置音量渐变以在合成持续时间内缓慢淡出音频。

[mixParameters setVolumeRampFromStartVolume:1.f toEndVolume:0.f timeRange:CMTimeRangeMake(kCMTimeZero, mutableComposition.duration)];

// Attach the input parameters to the audio mix.将输入参数连接到音频混合

mutableAudioMix.inputParameters = @[mixParameters];

Performing Custom Video Processing(执行自定义视频处理

与音频混合一样,您只需要一个AVMutableVideoComposition对象就可以对组合的视频轨道执行所有自定义视频处理。使用视频合成,您可以直接为 合成的视频轨道 设置适当的渲染大小,比例和帧速率。有关为 这些属性设置适当值的 详细示例,请参阅Setting the Render Size and Frame Duration

Changing the Composition’s Background Color(改变合成的背景颜色

所有视频合成都必须有一个至少包含一个视频轨道指令的一组AVVideoCompositionInstruction对象。您可以使用AVMutableVideoCompositionInstruction类创建您自己的视频合成指令。使用视频合成指令,您可以修改合成的背景颜色,指定是否需要后期处理或应用图层指令。

AVMutableVideoCompositionInstruction *mutableVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

mutableVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, mutableComposition.duration);

mutableVideoCompositionInstruction.backgroundColor = [[UIColor redColor] CGColor];

Applying Opacity Ramps(应用不透明度坡道

视频合成指令也可用于应用视频合成层指令。AVMutableVideoCompositionLayerInstruction对象可以应用变换,变换斜坡,不透明度和不透明度渐变 到一个合成的特定的视频轨道。 在视频合成指令的layerInstructions数组中,层指令的顺序决定了如何在该合成指令的持续时间内对来自源轨道的视频帧进行分层和合成。以下代码片段显示了如何设置 第一个视频转换第二个视频之前的不透明度渐变,使其缓慢淡出合成中的第一个视频:

//AVAssetTrack表示组合中播放的第一个视频片段
AVAsset *firstVideoAssetTrack = <#AVAssetTrack representing the first video segment played in the composition#>;

//AVAssetTrack表示组合中播放的第二个视频片段
AVAsset *secondVideoAssetTrack = <#AVAssetTrack representing the second video segment played in the composition#>;

// Create the first video composition instruction.创建第一个视频合成指令。
AVMutableVideoCompositionInstruction *firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

// Set its time range to span the duration of the first video track.
设置其时间范围以跨越第一个视频轨道的持续时间
firstVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration);

// Create the layer instruction and associate it with the composition video track.
//创建图层指令并将其与合成视频轨道相关联。
AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack];

// Create the opacity ramp to fade out the first video track over its entire duration.
//创建不透明度渐变以在整个持续时间内淡出第一个视频轨道。
[firstVideoLayerInstruction setOpacityRampFromStartOpacity:1.f toEndOpacity:0.f timeRange:CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration)];

// Create the second video composition instruction so that the second video track isn't transparent.
//创建第二个视频合成指令,以便第二个视频轨道不透明。
AVMutableVideoCompositionInstruction *secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

// Set its time range to span the duration of the second video track.
//设置其时间范围以跨越第二个视频轨道的持续时间。
secondVideoCompositionInstruction.timeRange = CMTimeRangeMake(firstVideoAssetTrack.timeRange.duration, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration));

// Create the second layer instruction and associate it with the composition video track.
//创建第二层指令并将其与合成视频轨道相关联。
AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack];

// Attach the first layer instruction to the first video composition instruction.
//将第一层指令附加到第一个视频合成指令。
firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction];

// Attach the second layer instruction to the second video composition instruction.
//将第二层指令附加到第二个视频合成指令。
secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction];

// Attach both of the video composition instructions to the video composition.
//将两个视频合成指令都附加到视频合成中。
AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];

mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction];
Incorporating Core Animation Effects(合并的动画效果

视频合成可以通过animationTool属性将核心动画的力量添加到您的组合中。通过这个动画工具,您可以完成诸如水印视频、添加标题或动画覆盖等任务。核心动画可以用两种不同的方式使用视频组合:你可以添加一个核心动画层作为它自己的单独的组合轨迹,或者你可以直接将核心动画效果(使用一个核心动画层)渲染到你的作品中的视频帧中。下面的代码通过在视频的中心添加一个水印来显示后一个选项:

//CALayer代表你想要的水印图像。
CALayer *watermarkLayer = <#CALayer representing your desired watermark image#>;

CALayer *parentLayer = [CALayer layer];

CALayer *videoLayer = [CALayer layer];

parentLayer.frame = CGRectMake(0, 0, mutableVideoComposition.renderSize.width, mutableVideoComposition.renderSize.height);

videoLayer.frame = CGRectMake(0, 0, mutableVideoComposition.renderSize.width, mutableVideoComposition.renderSize.height);

[parentLayer addSublayer:videoLayer];

watermarkLayer.position = CGPointMake(mutableVideoComposition.renderSize.width/2, mutableVideoComposition.renderSize.height/4);

[parentLayer addSublayer:watermarkLayer];

mutableVideoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

Putting It All Together: Combining Multiple Assets and Saving the Result to the Camera Roll(把它放在一起:合并多个资产并将结果保存到相机胶卷

这个简短的代码示例说明了如何将两个视频资源轨道和一个音频资源轨道结合起来创建一个视频文件。它显示了如何:

1>.创建一个AVMutableComposition对象并添加多个AVMutableCompositionTrack对象

2>.将AVAssetTrack对象的时间范围添加到兼容的合成轨道

3>.检查视频资源轨道的preferredTransform属性以确定视频的方向

4>.使用AVMutableVideoCompositionLayerInstruction对象将transforms(变换、变形)应用于合成内的视频轨道。

5>.为视频合成的renderSize和frameDuration属性设置适当的值

6>.导出到视频文件时,将合成与视频合成结合使用

7>.将视频文件保存到相机胶卷

注意:要关注最相关的代码,这个例子省略了一个完整应用程序的几个方面,比如内存管理和错误处理。要使用AVFoundation,您需要有足够的Cocoa经验来推断缺失的部分

Creating the Composition

将不同资源的轨道拼凑在一起,您使用AVMutableComposition对象,创建合成并添加一个音频和一个视频轨道

AVMutableComposition *mutableComposition = [AVMutableComposition composition];

//视频轨道
AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

//音频轨道
AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
Adding the Assets

空的合成对你没有好处。添加两个视频资源轨道和音频资源轨道到合成中。

//第一个视频资源轨道
AVAssetTrack *firstVideoAssetTrack = [[firstVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

//第二个视频资源轨道
AVAssetTrack *secondVideoAssetTrack = [[secondVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

//将它们添加到合成中
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration) ofTrack:firstVideoAssetTrack atTime:kCMTimeZero error:nil];

[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, secondVideoAssetTrack.timeRange.duration) ofTrack:secondVideoAssetTrack atTime:firstVideoAssetTrack.timeRange.duration error:nil];

[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration)) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];

注意:这假定您有两个资产每个至少包含一个视频轨道,第三个资产至少包含一个音轨。 这些视频可以从相机卷中取出,音轨也可以从音乐库或视频中获取。

 Checking the Video Orientations(检查视频方向

一旦将视频和音轨添加到合成中,您需要确保两个视频轨道的方向都是正确的。默认情况下,所有视频轨道都假定处于横向模式。如果您的视频轨道是以纵向模式拍摄的,则视频在导出时将无法正确定向。同样,如果您尝试将以纵向模式拍摄的视频与以横向模式拍摄的视频合并,导出会话将无法完成。

BOOL isFirstVideoPortrait = NO;//第一个视频是否是纵向 竖屏模式

CGAffineTransform firstTransform = firstVideoAssetTrack.preferredTransform;

// Check the first video track's preferred transform to determine if it was recorded in portrait mode.
//检查第一个视频轨道的首选变换,以确定它是否以纵向模式录制。
if (firstTransform.a == 0 && firstTransform.d == 0 && (firstTransform.b == 1.0 || firstTransform.b == -1.0) && (firstTransform.c == 1.0 || firstTransform.c == -1.0)) {

    isFirstVideoPortrait = YES;

}

BOOL isSecondVideoPortrait = NO;//第二个视频是否是纵向 竖屏模式

CGAffineTransform secondTransform = secondVideoAssetTrack.preferredTransform;

// Check the second video track's preferred transform to determine if it was recorded in portrait mode.

//检查第二个视频轨道的首选变换,以确定它是否以纵向模式录制
if (secondTransform.a == 0 && secondTransform.d == 0 && (secondTransform.b == 1.0 || secondTransform.b == -1.0) && (secondTransform.c == 1.0 || secondTransform.c == -1.0)) { isSecondVideoPortrait = YES;}

//判断二个视频轨道的录制的方向是否一致,不一致就警告提醒,因为二个视频的录制方向不一致是没办法合成的
if ((isFirstVideoAssetPortrait && !isSecondVideoAssetPortrait) || (!isFirstVideoAssetPortrait && isSecondVideoAssetPortrait))
 { 
      UIAlertView *incompatibleVideoOrientationAlert = [[UIAlertView alloc] initWithTitle:@"Error!" message:@"Cannot combine a video shot in portrait mode with a video shot in landscape mode." delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil]; 
      [incompatibleVideoOrientationAlert show]; 
       return;
 }
Applying the Video Composition Layer Instructions(应用视频合成层指令

一旦您知道视频片段具有兼容的方向,您可以将必要的图层指令应用到每个视频片段,并将这些图层指令添加到视频合成中。

//第一个视频合成指令对象
AVMutableVideoCompositionInstruction *firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

// Set the time range of the first instruction to span the duration of the first video track.
//设置第一个指令的时间范围,以持续到第一个视频轨道的持续时间。
firstVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration);

//第二个视频合成指令对象

AVMutableVideoCompositionInstruction * secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

// Set the time range of the second instruction to span the duration of the second video track.

//设置第二个指令的时间范围,以持续到第一个视频轨道的持续时间。

secondVideoCompositionInstruction.timeRange = CMTimeRangeMake(firstVideoAssetTrack.timeRange.duration, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration));

//第一个视频合成图层指令对象

AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];

// Set the transform of the first layer instruction to the preferred transform of the first video track.
//将第一层指令的变换 设置为 第一个视频轨道的首选变换。
[firstVideoLayerInstruction setTransform:firstTransform atTime:kCMTimeZero];

//第二个视频合成图层指令对象

AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];

// Set the transform of the second layer instruction to the preferred transform of the second video track.

//将第二层指令的变换 设置为 第二个视频轨道的首选变换。

[secondVideoLayerInstruction setTransform:secondTransform atTime:firstVideoAssetTrack.timeRange.duration];

//将第一层指令附加到第一个视频合成指令。

firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction];

//将第二层指令附加到第二个视频组合指令。

secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction];

//将两个视频合成指令都附加到视频合成指令中。

AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction];

所有AVAssetTrack对象都有一个preferredTransform属性,其中包含该资源轨道的方向信息。只要资源轨道显示在屏幕上,就会应用此转换。在前面的代码中,图层指令的变换设置为资产轨道的变换,以便在您调整渲染大小后,新合成中的视频正确显示。

Setting the Render Size and Frame Duration(设置渲染大小和帧持续时间

要完成视频方向修复,您必须相应地调整renderSize属性。您还应该为frameDuration属性选择合适的值,例如1/30秒(或每秒30帧)。默认情况下,renderScale属性设置为1.0,这适用于此合成

CGSize naturalSizeFirst, naturalSizeSecond;//第一个自然大小,第二个自然大小

// If the first video asset was shot in portrait mode, then so was the second one if we made it here.
//如果第一个视频资产是在竖屏(纵向)模式中拍摄的,那么第二个视频资产也应该是这样的。
if (isFirstVideoAssetPortrait) {

// Invert the width and height for the video tracks to ensure that they display properly.
 //反转视频轨道的宽度和高度,以确保它们正确显示。
    naturalSizeFirst = CGSizeMake(firstVideoAssetTrack.naturalSize.height, firstVideoAssetTrack.naturalSize.width);

    naturalSizeSecond = CGSizeMake(secondVideoAssetTrack.naturalSize.height, secondVideoAssetTrack.naturalSize.width);

}

else {

// If the videos weren't shot in portrait mode, we can just use their natural sizes.
//如果视频不是在竖屏模式下拍摄的,我们可以使用它们的自然尺寸。
    naturalSizeFirst = firstVideoAssetTrack.naturalSize;

    naturalSizeSecond = secondVideoAssetTrack.naturalSize;

}

float renderWidth, renderHeight;

// Set the renderWidth and renderHeight to the max of the two videos widths and heights.
//将renderWidth和renderHeight设置为两个视频宽度和高度的最大值。

if (naturalSizeFirst.width > naturalSizeSecond.width) {

    renderWidth = naturalSizeFirst.width;

}

else {

    renderWidth = naturalSizeSecond.width;

}

if (naturalSizeFirst.height > naturalSizeSecond.height) {

    renderHeight = naturalSizeFirst.height;

}

else {

    renderHeight = naturalSizeSecond.height;

}

mutableVideoComposition.renderSize = CGSizeMake(renderWidth, renderHeight);

// Set the frame duration to an appropriate value (i.e. 30 frames per second for video).
//将帧持续时间设置为适当的值(即视频每秒30帧)。
mutableVideoComposition.frameDuration = CMTimeMake(1,30);

Exporting the Composition and Saving it to the Camera Roll(导出合成文件和保存在相机胶卷

这个过程的最后一步是将整个合成导出到一个视频文件中,并将该视频保存到相机胶卷中。您使用AVAssetExportSession对象来创建新的视频文件,并将其传递给输出文件所需的URL。然后,您可以使用ALAssetsLibrary类将生成的视频文件保存到相机胶卷

// Create a static date formatter so we only have to initialize it once.

static NSDateFormatter *kDateFormatter;

if (!kDateFormatter) {

    kDateFormatter = [[NSDateFormatter alloc] init];

    kDateFormatter.dateStyle = NSDateFormatterMediumStyle;

    kDateFormatter.timeStyle = NSDateFormatterShortStyle;

}

// Create the export session with the composition and set the preset to the highest quality.
使用 export session 创建导出会话并将预设设置为最高质量
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];

// Set the desired output URL for the file created by the export process.
//为导出过程创建的文件设置所需的输出URL。
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.
//将输出文件类型 设置为QuickTime movie。
exporter.outputFileType = AVFileTypeQuickTimeMovie;

exporter.shouldOptimizeForNetworkUse = YES;

exporter.videoComposition = mutableVideoComposition;

// Asynchronously export the composition to a video file and save this file to the camera roll once export completes.
//将合成的视频 异步导出到视频文件,并在导出完成后将该文件保存到相机胶卷。
[exporter exportAsynchronouslyWithCompletionHandler:^{

    dispatch_async(dispatch_get_main_queue(), ^{

        if (exporter.status == AVAssetExportSessionStatusCompleted) {

            ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];

            if ([assetsLibrary videoAtPathIsCompatibleWithSavedPhotosAlbum:exporter.outputURL]) {

                [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:exporter.outputURL completionBlock:NULL];

            }

        }

    });

}];


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值