Кэширование с помощью AVPlayer и AVAssetExportSession
Я хотел бы кэшировать видео с прогрессивной загрузкой, используя AVPlayer. Как я могу сохранить элемент AVPlayer на диск? Я пытаюсь использовать AVAssetExportSession на currentItem игрока (который полностью загружен). Этот код дает мне "AVAssetExportSessionStatusFailed (операция не может быть завершена)":
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]);
}];
Как я могу успешно экспортировать? Я пытаюсь скопировать mediaAsset в AVMutableComposition, но мне тоже не повезло.
Спасибо!
PS: Вот несколько вопросов от людей, пытающихся сделать то же самое (но с MPMoviePlayerController):
2 ответа
Я пока не использую iOS 4.3 SDK, но мне было бы любопытно узнать значение mediaAsset.exportable для 4.3, как описано здесь:
Я пробовал несколько модификаций вашего кода, таких как получение имени предустановки и типа файла из списка доступных, но я получаю ту же ошибку, что и вы.
Итак, я решил попробовать инфраструктуру более низкого уровня, так как в документации говорится, что вы можете подключить AVAssetReader и AVAssetWriter, чтобы получить тот же эффект, что и AVAssetExportSession, но с большим контролем. Тем не менее, следующий код:
NSError *readerError = nil;
AVAssetReader *reader =
[AVAssetReader assetReaderWithAsset:mediaAsset error:&readerError];
if (readerError) NSLog(@"Error instantiating asset reader: %@",
[readerError localizedDescription]);
Дает следующий вывод:
*** 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''
Обратите внимание, что я проверил это с рабочим URL, но заменил его на поддельный выше. Мне кажется, что iOS не поддерживает ту функциональность, которую мы ищем. Насколько я знаю, AVAssetExportSession использует AVAssetReader под капотом и просто сообщает гораздо менее описательную ошибку, когда она терпит неудачу. Было бы неплохо, если бы они просто документировали это как таковое. В документах для AVAssetExportSession ничего не говорится о том, что актив должен быть локальным:
Я знаю, что это не очень хороший ответ, но это немного продвигает расследование. Я все еще очень надеюсь, что есть какой-то способ сделать это, потому что, очевидно, мы не одиноки в желании этой функции.
Конечно, это не работает на iOS 4.X. Кто-нибудь пытался заставить его работать на iOS 5 Beta?
Кажется, пропавший плод. В документации нигде не указано, что он не поддерживает доступ к данным для сетевых носителей. Даже сообщения об ошибках и другие вещи в API выглядят странно и кажется неполным при попытке его запустить. Скорее всего, это будет поддерживаться в ближайшее время.