Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does AVAssetExportSession produce an empty file?

I'm trying to export a .mov file from a source video created by UIImagePickerController. The problem is that the output file AVAssetExportSession creates is only 668 bytes. Why is it failing? my code:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSURL *imagePickerVideoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSString *filename = @"vid1.mov";

    AVAsset *video = [AVAsset assetWithURL:imagePickerVideoURL];
    AVAssetExportSession *exportSession
      = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
    exportSession.shouldOptimizeForNetworkUse = YES;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    exportSession.outputURL = [pathToSavedVideosDirectory URLByAppendingPathComponent:filename];
    NSLog(@"processing video...: %@", exportSession);
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
                       NSLog(@"done processing video!");
                   }];
}
like image 354
zakdances Avatar asked Aug 01 '12 07:08

zakdances


2 Answers

I'm going to guess it's because exportSession was not retained in memory, thus gets killed after the didFinishPickingMediaWithInfo completes (before the export session completion handler runs).

Store exportSession to a @property or change your completion handler to copy a reference to exportSession like so:

[exportSession exportAsynchronouslyWithCompletionHandler:^{
       if (AVAssetExportSessionStatusCompleted == exportSession.status)
       {
           NSLog(@"done processing video!");
       }
}];
like image 193
John Estropia Avatar answered Sep 28 '22 01:09

John Estropia


you need to write down steps for video file with AVAssetExportSession..

Start with Asset Put your fileURL

AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:fileURL options:nil];

Create AVMutableComposition

AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo  preferredTrackID:kCMPersistentTrackID_Invalid];

AVAssetTrack *clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)    ofTrack:clipVideoTrack  atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];

    AVAssetTrack *clipAudioTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];

Create AVMutableVideoComposition with Aniamtion layer if you want

AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain];
    videoComp.renderSize = CGSizeMake(videoSize.width, videoSize.height);
    videoComp.frameDuration = CMTimeMake(1, 30);
    videoComp.renderScale = 1.0;
    videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

Animation layer are here if you need otherwise pass nil.

CGSize videoSize = [videoAsset naturalSize];

//layer mixing
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];

Add aniamtion to your selected layer which you need to add as sublayer in parentLayer

Add instruction in video composition with mention animation layer and time duration.

AVMutableVideoCompositionInstruction

AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
AVAssetTrack *videoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];

Now creating AVAssetExportSession with use of AVMutableComposition and AVMutableVideoComposition

_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
_assetExport.videoComposition = videoComp;

//Create tmepory path for exported video file. .m4a would be preferred extension for AVFoundation.

NSString *videoName = @"demo.m4a";
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) 
{
    [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}

Add url in Export session and some required property.

_assetExport.outputFileType = AVFileTypeQuickTimeMovie; 
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;

Start Export session and perform action when you will get complete message.

[_assetExport exportAsynchronouslyWithCompletionHandler:
 ^(void ) {
     switch (_assetExport.status)
     {
         case AVAssetExportSessionStatusUnknown:
             NSLog(@"Unknown");
         case AVAssetExportSessionStatusExporting:
             NSLog(@"Exporting");
         case AVAssetExportSessionStatusFailed:
             NSLog(@"exporting failed");
             break;
         case AVAssetExportSessionStatusCompleted:
             NSLog(@"exporting completed");
             [self performSelectorOnMainThread:@selector(completeVideoExport) withObject:nil waitUntilDone:YES];
             break;
         case AVAssetExportSessionStatusCancelled:
             NSLog(@"export cancelled");
             break;
     }
     _assetExport = nil;
     [_assetExport release];
 }       
 ];   

if you need any more let me know..

like image 41
Solid Soft Avatar answered Sep 28 '22 00:09

Solid Soft