Talha Ahmad Khan
Talha Ahmad Khan

Reputation: 3476

Video duration changes after composing and export using AVAssetExportSession

I am trying to crop a square frame from a video. Following is the process

  1. Get Asset of Video
  2. Get Video Track from that asset
  3. Create AVMutableComposition instance with frame duration (30fps) and renderSize (required rectangle)
  4. Create AVMutableVideoCompositionInstruction instance with timeRange (0-asset.duration)
  5. Create LayerInstruction instance
  6. set its transform to give offset to frame
  7. set LayerInstruction in the Instruction
  8. Set Instruction in mutableComposition instance
  9. Create AVAssetExportSession instance with the asset above and HighestQuality preset
  10. set it's output URL , timeRange and output file type
  11. Export asyncronously

Now what happens is, the video comes out correct but it's duration varies in some cases

  1. If The video has movement in the last, there will be no cutting and the output video has same time as original one
  2. If the video is static, such that there is no movement in the video, or in the last of video, some static frames get removed and the video length becomes small
  3. In some cases where there is a lot of movement in the video, that duration increases.

The change in the duration is from 0.1 to 1 second. It might be a very small change but where I need this process that video duration has to be precise.

I am adding the code if you want to dive deep in it.

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

The things I tested and not work are:

Upvotes: 1

Views: 809

Answers (1)

Talha Ahmad Khan
Talha Ahmad Khan

Reputation: 3476

Found the issue: It's not an issue to be honest, it's kind of system bug. The Exporter was ignoring last static frames for no reason. at the point where I am setting transform at kCMTimeZero, I added new line where I set the same transform at the end of video.

[transformer setTransform:finalTransform atTime:asset.duration];

Now the exporter doesn't ignore the last few frames.

Upvotes: 1

Related Questions