10

I would like to cache progressive-download videos using AVPlayer. How can I save an AVPlayer's item to disk? I'm trying to use AVAssetExportSession on the player's currentItem (which is fully loaded). This code is giving me "AVAssetExportSessionStatusFailed (The operation could not be completed)" :

    AVAsset *mediaAsset = self.player.currentItem.asset;

    AVAssetExportSession *es = [[AVAssetExportSession alloc] initWithAsset:mediaAsset presetName:AVAssetExportPresetLowQuality];

    NSString *outPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"out.mp4"];

    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager removeItemAtPath:outPath error:NULL];

    es.outputFileType = @"com.apple.quicktime-movie";
    es.outputURL = [[[NSURL alloc] initFileURLWithPath:outPath] autorelease];
    NSLog(@"exporting to %@",outPath);
    [es exportAsynchronouslyWithCompletionHandler:^{
        NSString *status = @"";

        if( es.status == AVAssetExportSessionStatusUnknown ) status = @"AVAssetExportSessionStatusUnknown";
        else if( es.status == AVAssetExportSessionStatusWaiting ) status = @"AVAssetExportSessionStatusWaiting";
        else if( es.status == AVAssetExportSessionStatusExporting ) status = @"AVAssetExportSessionStatusExporting";
        else if( es.status == AVAssetExportSessionStatusCompleted ) status = @"AVAssetExportSessionStatusCompleted";
        else if( es.status == AVAssetExportSessionStatusFailed ) status = @"AVAssetExportSessionStatusFailed";
        else if( es.status == AVAssetExportSessionStatusCancelled ) status = @"AVAssetExportSessionStatusCancelled";

        NSLog(@"done exporting to %@ status %d = %@ (%@)",outPath,es.status, status,[[es error] localizedDescription]);
    }];

How can I export successfully? I'm looking into copying mediaAsset into an AVMutableComposition, but haven't had much luck with that either.

Thanks!

PS: Here are some questions from people trying to accomplish the same thing (but with MPMoviePlayerController):

Community
  • 1
  • 1
tba
  • 6,229
  • 8
  • 43
  • 63

2 Answers2

9

I'm not using the iOS 4.3 SDK yet, but I'd be curious to know the value of mediaAsset.exportable under 4.3, as described here:

http://developer.apple.com/library/ios/#releasenotes/AudioVideo/RN-AVFoundation/_index.html#//apple_ref/doc/uid/TP40010717-CH1-SW4

I've tried a number of modifications to your code, such as getting the preset name and file type from the list of those available, but I'm getting the same error you are.

So, I decided to try a lower-level framework, since the documentation states that you can connect an AVAssetReader and an AVAssetWriter to get the same effect as an AVAssetExportSession except with more control. However, the following code:

NSError *readerError = nil;
AVAssetReader *reader = 
  [AVAssetReader assetReaderWithAsset:mediaAsset error:&readerError];
if (readerError) NSLog(@"Error instantiating asset reader: %@",
  [readerError localizedDescription]);

Gives the following output:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: '*** -[AVAssetReader initWithAsset:error:] Cannot initialize an instance of 
AVAssetReader with an asset at non-local URL 'http://example.com/test.mp3''

Note that I tested this with a working URL but have replaced it with a fake one above. This looks to me like iOS doesn't support the functionality we're looking for. For all I know AVAssetExportSession uses an AVAssetReader under the hood and just reports a much less descriptive error when it fails. It sure would be nice if they'd just document it as such. The docs for AVAssetExportSession don't mention anything about the asset needing to be local:

http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAssetExportSession_Class/Reference/Reference.html#//apple_ref/occ/cl/AVAssetExportSession

I know this isn't much of an answer, but it moves the investigation down the road a little. I'm still really hoping there's some way to do this, because clearly we are not alone in wanting the feature.

Jesse Crossen
  • 6,945
  • 2
  • 31
  • 32
  • Yes, I ran into the same issue. To make matters worse, mediaAsset.exportable is YES ! But it still throws the "Cannot initialize...at non-local URL" exception. – tba Jun 13 '11 at 17:58
  • 4
    Are you only or mainly interested in audio? Because if so, it's possible to do this by connecting the URL Loading System, Audio File Stream Services, and Audio Queue Services. I'm working on a solution now, but it's quite involved. Any interest? – Jesse Crossen Jun 14 '11 at 01:59
  • Unfortunately, I need to cache the whole video. Thanks though -- I'll mark you as accepted answer in a couple days. – tba Jun 14 '11 at 17:35
  • Jesse, can you say something about your solution for audio or maybe share it? If yes, please contact me via e-mail or comment here. – Roman Temchenko May 25 '12 at 12:30
  • @RomanTemchenko: I'm sorry to say I never actually finished that solution. It seemed straightforward, but then I got hung up on all the details of feeding encoded packets to AQS with the proper metadata, etc. With those low-level A/V frameworks being somewhat of an under-documented black box, it wasn't important enough for me to take the time and figure it all out. – Jesse Crossen May 27 '12 at 00:31
  • @JesseCrossen did you came up with a solution? I'd like to export a portion of the audio from a youtube videoclip. but don't want to download it all...any suggestion? – luca Oct 31 '14 at 16:33
0

For sure it doesn't work on iOS 4.X. Has any one tried make it working on iOS 5 Beta?

It seems to be a missing feture. There isn't stated anywhere in the documentation that it doesn't support data access for networked media. Even error messages and other stuff in API befeviour weird and seems to be incomplete, when trying to run it. Most likely it will be supported soon.