使用 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 - 如何从视频持续时间中修剪毫秒

AVAssetExportSession始终无法导出

AVAssetExportSession 总是无法导出

AVAssetExportSession 错误 -11820

无法使用 AVAssetExportSession 修剪音频文件