使用 AVAssetExportSession 合成和导出后视频时长发生变化
Posted
技术标签:
【中文标题】使用 AVAssetExportSession 合成和导出后视频时长发生变化【英文标题】:Video duration changes after composing and export using AVAssetExportSession 【发布时间】:2019-03-02 00:48:15 【问题描述】:我正在尝试从视频中裁剪一个方形框架。以下是流程
-
获取视频资产
从该资产中获取视频轨道
创建具有帧持续时间 (30fps) 和 renderSize(必需矩形)的 AVMutableComposition 实例
使用 timeRange (0-asset.duration) 创建 AVMutableVideoCompositionInstruction 实例
创建 LayerInstruction 实例
设置它的变换来给帧偏移
在指令中设置 LayerInstruction
在 mutableComposition 实例中设置指令
使用上述资产和 HighestQuality 预设创建 AVAssetExportSession 实例
设置它的输出地址、时间范围和输出文件类型
异步导出
现在发生的情况是,视频显示正确,但在某些情况下持续时间会有所不同
-
如果视频最后有运动,则不进行剪切,输出视频与原始视频时间一致
如果视频是静态的,例如视频中没有移动,或者视频的最后,一些静态帧会被移除,视频长度会变小
在某些情况下,如果视频中有大量移动,则持续时间会增加。
持续时间的变化是从 0.1 秒到 1 秒。这可能是一个非常小的变化,但我需要这个过程,视频时长必须是精确的。
如果您想深入了解,我将添加代码。
AVAsset *asset ;
asset = [AVAsset assetWithURL:customURL];
//create an avassetrack with our asset
AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CMTime originalVideoDur = asset.duration;
float orgDurFloat = (float)originalVideoDur.value / (float)originalVideoDur.timescale;
//create a video composition and preset some settings
AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);
//here we are setting its render size to its height x height (Square)
CGFloat outputWidth = UIScreen.mainScreen.bounds.size.width * UIScreen.mainScreen.scale;
videoComposition.renderSize = CGSizeMake(outputWidth, outputWidth);
//create a video instruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
CGAffineTransform finalTransform = [self getOutputTransformOfAsset:asset track:clipVideoTrack];
[transformer setTransform:finalTransform atTime:kCMTimeZero];
//add the transformer layer instructions, then add to video composition
instruction.layerInstructions = [NSArray arrayWithObject:transformer];
videoComposition.instructions = [NSArray arrayWithObject: instruction];
//Create an Export Path to store the cropped video
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *exportPath = [documentsPath stringByAppendingFormat:@"/CroppedVideo2.mp4"];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
//Remove any prevouis videos at that path
[[NSFileManager defaultManager] removeItemAtURL:exportUrl error:nil];
//Export
exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = videoComposition;
exporter.outputURL = exportUrl;
exporter.outputFileType = AVFileTypeMPEG4;
exporter.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
[exporter exportAsynchronouslyWithCompletionHandler:^
dispatch_async(dispatch_get_main_queue(), ^
//Call when finished
);
];
我测试但不起作用的东西是:
更改 AVAssetExportSession 预设。 (没有效果,除了低质量产生的持续时间差异较小但仍然有很大差异) 帧持续时间(较短的帧持续时间较小的持续时间差异,1 帧持续时间可提供最佳持续时间结果,但输出视频不可用)【问题讨论】:
【参考方案1】:发现问题: 老实说,这不是问题,这是一种系统错误。导出器无缘无故地忽略了最后的静态帧。 在我将变换设置为 kCMTimeZero 时,我添加了新行,在视频末尾设置了相同的变换。
[transformer setTransform:finalTransform atTime:asset.duration];
现在导出器不会忽略最后几帧。
【讨论】:
以上是关于使用 AVAssetExportSession 合成和导出后视频时长发生变化的主要内容,如果未能解决你的问题,请参考以下文章
使用 AVAssetExportSession 导出 MP3
AVAssetExportSession - 如何从视频持续时间中修剪毫秒