http://blog.csdn.net/xiaolinyeyi/article/details/50878996
裁剪视频是很久之前所做的项目中用到的,现在又看到了,整理一下。
与之相关的这些类有些抽象,所以我这里重点将它们具体化。用代码将视频合成其实与绘声绘影/vegas等软件将视频合成的过程类似,首先了解下这类软件一些相关知识:一个工程文件中有很多轨道,如音频轨道1,音频轨道2,音频轨道3,视频轨道1,视频轨道2等等,每个轨道里有许多素材,对于每个视频素材,它可以进行缩放、旋转等操作,素材库中的视频拖到轨道中会分为视频轨和音频轨两个轨道。这里用这些软件里的一些术语类来比这些类:
AVAsset:素材库里的素材;
AVAssetTrack:素材的轨道;
AVMutableComposition :一个用来合成视频的工程文件;
AVMutableCompositionTrack :工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材;
AVMutableVideoComposition:用来生成video的组合指令,包含多段instruction。可以决定最终视频的尺寸,裁剪需要在这里进行;
AVMutableVideoCompositionInstruction:一个指令,决定一个timeRange内每个轨道的状态,包含多个layerInstruction;
AVMutableVideoCompositionLayerInstruction:在一个指令的时间范围内,某个轨道的状态;
AVAssetExportSession:配置渲染参数并渲染。
接下来就用这种类比的方式裁剪一个视频:
1.将素材拖入到素材库中
<code class="hljs perl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">AVAsset <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*asset</span> = [AVAsset assetWithURL:outputFileURL]; AVAssetTrack <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*videoAssetTrack</span> = [[asset tracksWithMediaType:AVMediaTypeVideo]objectAtIndex:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>素材的视频轨 AVAssetTrack <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">*audioAssertTrack</span> = [[asset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>素材的音频轨</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
2.将素材的视频插入视频轨,音频插入音频轨
<code class="hljs ruby has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-constant" style="box-sizing: border-box;">AVMutableComposition</span> *composition = [<span class="hljs-constant" style="box-sizing: border-box;">AVMutableComposition</span> composition];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>这是工程文件 <span class="hljs-constant" style="box-sizing: border-box;">AVMutableCompositionTrack</span> *videoCompositionTrack = [composition <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">addMutableTrackWithMediaType:</span><span class="hljs-constant" style="box-sizing: border-box;">AVMediaTypeVideo</span> <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">preferredTrackID:</span>kCMPersistentTrackID_Invalid];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>视频轨道 [videoCompositionTrack <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">insertTimeRange:</span><span class="hljs-constant" style="box-sizing: border-box;">CMTimeRangeMake</span>(kCMTimeZero, videoAssetTrack.timeRange.duration) <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">ofTrack:</span>videoAssetTrack <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">atTime:</span>kCMTimeZero <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">error:</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">nil</span>];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>在视频轨道插入一个时间段的视频 <span class="hljs-constant" style="box-sizing: border-box;">AVMutableCompositionTrack</span> *audioCompositionTrack = [composition <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">addMutableTrackWithMediaType:</span><span class="hljs-constant" style="box-sizing: border-box;">AVMediaTypeAudio</span> <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">preferredTrackID:</span>kCMPersistentTrackID_Invalid];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>音频轨道 [audioCompositionTrack <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">insertTimeRange:</span> <span class="hljs-constant" style="box-sizing: border-box;">CMTimeRangeMake</span>(kCMTimeZero, videoAssetTrack.timeRange.duration) <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">ofTrack:</span>audioAssertTrack <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">atTime:</span>kCMTimeZero <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">error:</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">nil</span>];<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span>插入音频数据,否则没有声音 </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
3.裁剪视频,就是要将所有视频轨进行裁剪,就需要得到所有的视频轨,而得到一个视频轨就需要得到它上面所有的视频素材
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">AVMutableVideoCompositionLayerInstruction *videoCompositionLayerIns = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoAssetTrack]; [videoCompositionLayerIns setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];//得到视频素材(这个例子中只有一个视频) AVMutableVideoCompositionInstruction *videoCompositionIns = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; [videoCompositionIns setTimeRange:CMTimeRangeMake(kCMTimeZero, videoAssetTrack.timeRange.duration)];//得到视频轨道(这个例子中只有一个轨道) AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.instructions = @[videoCompositionIns]; videoComposition.renderSize = CGSizeMake(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>);//裁剪出对应的大小 videoComposition.frameDuration = CMTimeMake(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
4.导出
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetMediumQuality]; exporter.videoComposition = videoComposition; exporter.outputURL = [NSURL fileURLWithPath:_outputFilePath isDirectory:YES]; exporter.outputFileType = AVFileTypeMPEG4; exporter.shouldOptimizeForNetworkUse = YES; [exporter exportAsynchronouslyWithCompletionHandler:^{ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (exporter.error) { //<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>{ //<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> } }];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
总结:学习这些类和方法最大的难度在于其抽象性。我的理解未必完全正确,但希望这种类比的方式能够帮助学习