使用AVAssetExportSession进行合成和导出后,视频时长发生变化

时间:2018-09-26 09:27:04

标签: ios video avasset avassetexportsession avmutablecomposition

我正在尝试从视频中裁剪方形框。以下是过程

  1. 获取视频资产
  2. 从该资产获取视频轨道
  3. 使用帧持续时间(30fps)和renderSize(必需的矩形)创建AVMutableComposition实例
  4. 使用timeRange(0-asset.duration)创建AVMutableVideoCompositionInstruction实例
  5. 创建LayerInstruction实例
  6. 设置其变换以使帧偏移
  7. 在指令中设置LayerInstruction
  8. 在mutableComposition实例中设置指令
  9. 使用上面的资产和预设的HighestQuality创建AVAssetExportSession实例
  10. 设置其输出URL,timeRange和输出文件类型
  11. 异步导出

现在发生的是,视频可以正确显示,但在某些情况下其时长有所不同

  1. 如果视频最后移动一次,则不会有剪切,并且输出视频的时间与原始视频相同。
  2. 如果视频是静态的,则视频或视频的最后部分没有任何运动,则某些静态帧将被删除并且视频长度变小
  3. 在某些情况下,视频中的移动很多,持续时间会增加。

持续时间的变化从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 个答案:

答案 0 :(得分:1)

发现了问题: 老实说,这不是一个问题,它是一种系统错误。导出器无缘无故地忽略了最后的静态帧。 在我要在kCMTimeZero设置转换的那一点上,我添加了新行,在视频末尾设置了相同的转换。

chrome.devtools.panels.sources.onSelectionChanged.addListener(
          function (oChanges) { ... });
});

现在,导出器不会忽略最后几帧。