AVAssetExportSession exporting too slow
Asked Answered
F

3

8

I am trying to export an AVMutableComposition using AVAssetExportSession.

AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL=url;
    exporter.outputFileType = AVFileTypeQuickTimeMovie;
    exporter.videoComposition = mainCompositionInst;
    exporter.shouldOptimizeForNetworkUse = YES;

    [exporter exportAsynchronouslyWithCompletionHandler:^
     {
         switch (exporter.status)
         {
             case AVAssetExportSessionStatusCompleted:
             {
                 NSLog(@"Video Merge SuccessFullt");
             }
                 break;
             case AVAssetExportSessionStatusFailed:
                 NSLog(@"Failed:%@", exporter.error.description);
                 break;
             case AVAssetExportSessionStatusCancelled:
                 NSLog(@"Canceled:%@", exporter.error);
                 break;
             case AVAssetExportSessionStatusExporting:
                 NSLog(@"Exporting!");
                 break;
             case AVAssetExportSessionStatusWaiting:
                 NSLog(@"Waiting");
                 break;
             default:
                 break;
         }
     }];

But exporting even 1 minute video takes around 30 seconds, which is too much considering iPad inbuilt camera app takes less than 2 seconds.

Also if I remove videoComposition from exporter, time reduces to 7 seconds, which is still bad considering video length to be only 1 minute. So, I want to know how to decrease the export time to minimum?

Also, I want to know, does AVAssetExportSession takes generally this much time or is it just my case?

Update: Merge Code:

AVMutableComposition *mutableComposition = [AVMutableComposition composition];

AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableVideoCompositionLayerInstruction *videoTrackLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];


NSMutableArray *instructions = [NSMutableArray new];
CGSize size = CGSizeZero;

CMTime time = kCMTimeZero;
for (AVURLAsset *asset in assets)
{
    AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVAssetTrack *audioAssetTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;



    NSError *error;
    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetTrack.timeRange.duration )
                                       ofTrack:assetTrack
                                        atTime:time
                                         error:&error];

    [videoTrackLayerInstruction setTransform:assetTrack.preferredTransform atTime:time];

    if (error) {
        NSLog(@"asset url :: %@",assetTrack.asset);
        NSLog(@"Error1 - %@", error.debugDescription);
    }

    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAssetTrack.timeRange.duration)
                                       ofTrack:audioAssetTrack
                                        atTime:time
                                         error:&error];
    if (error) {
        NSLog(@"Error2 - %@", error.debugDescription);
    }

    time = CMTimeAdd(time, assetTrack.timeRange.duration);

    if (CGSizeEqualToSize(size, CGSizeZero)) {
        size = assetTrack.naturalSize;
    }
}

AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, time);
mainInstruction.layerInstructions = [NSArray arrayWithObject:videoTrackLayerInstruction];
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
mainCompositionInst.renderSize = size;
Function answered 24/7, 2015 at 12:6 Comment(0)
P
4

I think the issue here is AVAssetExportPresetHighestQuality this will cause conversion or up sampling, and will slow things WAY down. Try using AVAssetExportPresetPassthrough instead. Took my export times from ~35+ secs down to less than a second

I also disabled optimizing for network use as all of our videos are only used within the app, and never streamed or passed over a network

Plaice answered 3/1, 2020 at 21:5 Comment(3)
I tried it for exporting audio but AVAssetExportPresetPassthrough does not work if i am appending audio to the same file again and again. Any guess ?Willemstad
AVAssetExportPresetPassthrough optimized my export from 24 to 2-3 seconds. But I added effects to my asset. All the effects were gone. So I don't know how to vote this answer. For me it's not workingConvenance
@Convenance true. all effects are gone...Gavan
V
2

I built an app that merged together different video fragments and I can safely say it is your case. My video files have ~10 mb so maybe they are little smaller but it takes less than second to merge them all together, even if there is 10, 20 segments.

Now as for it is actually happening, I have checked my configuration against yours and the difference is following:

  • I use export.outputFileType = AVFileTypeMPEG4
  • I have network optimization disabled, and if you are not planning to stream the video from your device, you should disable it too

Other than that, it should be the same, I can't really compare it as you would have to provide code about how you actually create the composition. There are some things to check though:

  • if you are using AVURLAssetPreferPreciseDurationAndTimingKey when creating AVURLAsset and you don't have enough keyframes, it can actually take quite some time to seek through to find the keys and so it slows it down
  • Consider if you really need highest quality for the video
  • Consider resolution of the video and possibly lower it down

I should be able to help you more if you provide more information, but maybe some of this stuff will work. Give it a try and then report back.

Hope it helps a little!

Edit 1: I forgot to mention that if you are out of options, you should try to use FFmpeg library as it is very high performance, though due to licencing might not be suitable for you.

Vitkun answered 30/7, 2015 at 7:0 Comment(9)
I tried all the things you mentioned but didn't notice any change in export time(not significant at least). I posted my merging code also. As I said export time goes very high if I add instructions through AVVideoComposition. So just wanted you to check that part specially.Function
If your code does not contain AVVideoComposition then please can you add one with empty instructions and check if that makes any difference.Function
remove any trace of instructions unless you use it (AVMutableVideoCompositionInstruction) - because it seems that you are not; it should help immensely, I think transform and other stuff make it work slow. Also, remove frame duration and render size, one of those also will make difference. Just for test :) Because composition does not require any of those, it is all optional.Vitkun
I need instructions to preserve the orientation of videos. Thats why I need to apply these frame duration and render size.Function
So your merged videos are different sizes? if so, then I suspect you should look into FFmpeg, as this operation will be very costly and it is build for thisVitkun
That's not an appropriate option for me. Does adding instructions increase export time in your project?Function
You should start removing things and test after each one ; it really is the best option to know what is the problem in this case. Once you have problem pinned down, we can come up with solution :)Vitkun
Hey @Jiri Trecak, I am having a similar problem, do you mind glancing over at https://mcmap.net/q/683684/-only-first-track-playing-of-avmutablecomposition. I am trying to avoid AVAssetExportSession as it takes around 1 minute to combine what I am trying to do, but if I avoid it, it is instantaneous but I face other issues. I have tried both ways, so all advice is appreciated! ThanksRufescent
Hey @Jiri Trecak, I am in need of some help! Feel free to come look over at it and possibly get a bounty! #39088813Rufescent
W
1

Keep in my that maybe the asset you're trying to export is not stored locally and first is downloading the content and then exporting your assets.

if you don't want to download any content

let videoRequestOptions: PHVideoRequestOptions = PHVideoRequestOptions()
videoRequestOptions.isNetworkAccessAllowed = true

you also going to receive a message within requestExportSession completion handler with a couple of useful info values. https://developer.apple.com/documentation/photokit/phimagemanager/image_result_info_keys

otherwise, if you want to download your asset from iCloud and make it as fast as possible you could play with the following parameters

let videoRequestOptions: PHVideoRequestOptions = PHVideoRequestOptions()
// highQualityFormat, highQualityFormat, fastFormat, automatic
videoRequestOptions.deliveryMode = .fastFormat 
videoRequestOptions.isNetworkAccessAllowed = true

another important property is the export preset, there's a bunch of available preset

let lowQualityPreset1 = AVAssetExportPresetLowQuality
let lowQualityPreset2 = AVAssetExportPreset640x480
let lowQualityPreset3 = AVAssetExportPreset960x540
let lowQualityPreset4 = AVAssetExportPreset1280x720

let manager = PHImageManager()
manager.requestExportSession(forVideo: asset, 
                              options: videoRequestOptions, 
                         exportPreset: lowQualityPreset1) { (session, info) in
  session?.outputURL = outputUrl
  session?.outputFileType = .mp4
  session?.shouldOptimizeForNetworkUse = true

  session?.exportAsynchronously {

  }
}
Whittling answered 3/4, 2020 at 14:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.