问题
I'm using AVQueuePlayer
to do playback of a list of videos in our app. I'm trying to cache the videos that are played by AVQueuePlayer
so that the video doesn't have to be downloaded each time.
So, after the video finishes playing, I attempt to save the AVPlayerItem into disk so next time it's initialized with a local URL.
I've tried to achieve this through two approaches:
- Use AVAssetExportSession
- Use AVAssetReader and AVAssetWriter.
1) AVAssetExportSession approach
This approach works like this:
- Observe when an
AVPlayerItem
finishes playing usingAVPlayerItemDidPlayToEndTimeNotification
. - When the above notification is received (a video finished playing, so it's fully downloaded), use
AVAssetExportSession
to export that video into a file in disk.
The code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(videoDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
then
- (void)videoDidFinishPlaying:(NSNotification*)note
{
AVPlayerItem *itemToSave = [note object];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:itemToSave.asset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.outputURL = [NSURL fileURLWithPath:@"/path/to/Documents/video.mp4"];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch(exportSession.status){
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting...");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"Export completed, wohooo!!");
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"Waiting...");
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Failed with error: %@", exportSession.error);
break;
}
}
The result in console of that code is:
Failed with error: Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x98916a0 {NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x99ddd10 "The operation couldn’t be completed. (OSStatus error -12109.)", NSLocalizedFailureReason=An unknown error occurred (-12109)}
2) AVAssetReader, AVAssetWriter approach
The code:
- (void)savePlayerItem:(AVPlayerItem*)item
{
NSError *assetReaderError = nil;
AVAssetReader *assetReader = [[AVAssetReader alloc] initWithAsset:assetToCache error:&assetReaderError];
//(algorithm continues)
}
That code throws an exception when trying to alloc/init the AVAssetReader
with the following information:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetReader initWithAsset:error:] Cannot initialize an instance of AVAssetReader with an asset at non-local URL 'https://someserver.com/video1.mp4''
***
Any help is much appreciated.
回答1:
How I ended up manage to do this is to create the usually array of AVPlayer > AVPlayerItem > AVURLAsset. But also at the same time create an AVExportSession right away before AVPlayer have completely loaded the video from the remote URL.
The AVExportSession actually will export slowly as the AVPlayer tries to pre-buffer the URL. This is irregardless of whether the user starts playing the AVPlayer or not. However the output file will not actually complete until the entire URL is pre-buffered. At that point AVExportSession will callback with the completion. This is also completely independent of whether the user is playing, or have completed playing the video or not.
As such by creating the AVPlayer/AVExportSession combo early, it became my pre-buffer mechanism
-- Update 2018-01-10 --
Want to add that after having deployed the above mechanism. We have encountered 1 big caveat that I think deserves some mention.
You cannot have too many video pipelines in memory (AVPlayer with AVPlayerItem/AVAsset hooked up). AVFoundation will refusing to play. So do use the above mechanism to pre-buffer. But once the video is downloaded to a file, if the user is not viewing the video, dealloc the AVPlayer/AVAsset. Reallocate an AVPlayer when the user decides to play the video again, this time with the AVURLAsset pointed to your local buffered copy of the video.
来源:https://stackoverflow.com/questions/22822643/unable-to-export-avplayeritem