Ответ 1
AVFoundation, похоже, не делает различий между локальными и нелокальными файлами, как между типом используемых файлов или протоколов. Существует ОЧЕНЬ четкое различие между использованием mp4/mov и использованием протокола потоковой передачи HTTP Live через m3u8, но различия, использующие локальный или удаленный mp4, немного более размыты.
Чтобы расширить на вышеупомянутое:
а) Если ваш "удаленный" актив - это M3U8 (то есть вы используете потоковую передачу HTTP), то у вас нет никаких шансов. Неважно, находится ли M3U8 в вашей локальной файловой системе или на удаленном сервере, по множеству причин AVAssetReader и все функции, связанные с AVAsset, просто НЕ работают. However, AVPlayer, AVPlayerItem etc would work just fine.
б) Если речь идет о MP4/MOV, требуется дальнейшее расследование. Local MP4/MOV work flawlessly.
Хотя в случае с удаленными MP4/MOV я могу создать (или извлечь из AVPlayerItem, AVPlayer или AVAssetTracks) AVURLAsset, с помощью которого я иногда могу успешно инициализировать AVAssetReader (я остановлюсь на "иногда" ну и в скором времени). ОДНАКО, copyNextSampleBuffer always returns nil in case of remote MP4's
. Так как несколько вещей до момента вызова copyNextSampleBuffer работают, я не уверен на 100%, если:
i) copyNextSampleBuffer не работает для удаленных mp4, после того, как все остальные шаги были успешными, это предполагаемая/ожидаемая функциональность.
ii) что "другие шаги", по-видимому, работают вообще для удаленного MP4, является случайностью реализации Apple, и эта несовместимость просто выходит на первый план, когда мы нажимаем copyNextSampleBuffer.............. что это за "другие шаги", я подробно опишу в ближайшее время.
III) я делаю что-то не так при попытке вызвать copyNextSampleBuffer для удаленных MP4.
@Paula, вы можете попытаться исследовать немного дальше с удаленными MOV/MP4.
Для справки, вот подходы, которые я пытался захватить кадр из видео:
а)
Создайте AVURLAsset прямо из URL видео.
Получить видео дорожку, используя [asset trackWithMediaType: AVMediaTypeVideo]
Подготовьте AVAssetReaderTrackOutput, используя видеодорожку в качестве источника.
Создайте AVAssetReader, используя AVURLAsset.
Добавьте AVAssetReaderTrackOutput в AVAssetReader и начните чтение.
Получить изображения с помощью copyNextSampleBuffer.
б)
Создайте AVPlayerItem из видео URL, а затем AVPlayer из него (или создайте AVPlayer непосредственно из URL).
Извлеките свойство AVPlayer "asset" и загрузите его "дорожки", используя "loadValuesAsynchronouslyForKeys:".
Разделите дорожки типа AVMediaTypeVideo (или просто вызовите trackWithMediaType: для актива после загрузки дорожек) и создайте AVAssetReaderTrackOutput с использованием видеодорожки.
Создайте AVAssetReader, используя AVPlayer 'asset', 'startReading', а затем извлеките изображения, используя copyNextSampleBuffer.
с)
Создайте AVPlayerItem + AVPlayer или AVPlayer непосредственно из URL-адреса видео.
KVO AVPlayerItem свойство "дорожки", и после того, как дорожки загружены, отделите AVAssetTracks типа AVMediaTypeVideo.
Извлеките AVAsset из свойства "asset" AVPlayerItem/AVPlayer/AVAssetTrack.
Остальные шаги аналогичны подходу (б).
г)
Создайте AVPlayerItem + AVPlayer или AVPlayer непосредственно из URL-адреса видео.
KVO AVPlayerItem свойство "дорожки", и после того, как дорожки загружены, отделите их от типа AVMediaTypeVideo.
Создайте AVMutableComposition и инициализируйте связанный AVMutableCompositionTrack типа AVMediaTypeVideo.
Вставьте соответствующий CMTimeRange из видео дорожки, полученной ранее, в этот AVMutableCompositionTrack.
Аналогично (b) и (c), теперь создайте ваши AVAssetReader и AVAssetReaderTrackOutput, но с той разницей, что вы используете AVMutableComposition в качестве базового AVAsset для инициализации AVAssetReader и AVMutableCompositionTrack в качестве базового AVAssetTrack для вашего AVAssetReaderTrackOutput.
'startReading' и использовать copyNextSampleBuffer, чтобы получить кадры из AVAssetReader.
PS: я попробовал подход (d) здесь, чтобы обойти тот факт, что AVAsset, полученный непосредственно из AVPlayerItem или AVPlayer, не вел себя. Поэтому я хотел создать новый AVAsset из уже имеющихся у меня AVAssetTracks. По общему признанию хакерский, и, возможно, бессмысленный (где еще будет в конечном итоге информация о треке, если не исходный AVAsset!), Но это все равно стоило отчаянной попытки.
Вот краткое изложение результатов для разных типов файлов:
1) Местный MOV/MP4 - все 4 подхода работают безупречно.
2) Удаленный MOV/MP4 - актив и дорожки корректно извлекаются в подходах (b) - (d), и AVAssetReader также инициализируется, но copyNextSampleBuffer всегда возвращает nil. В случае (a) создание самого AVAssetReader завершается неудачно с NSOSStatusErrorDomain "Неизвестная ошибка" -12407.
3) Локальный M3U8 (доступ через встроенный/локальный HTTP-сервер) - Подходы (a), (b) и (c) с треском проваливаются, поскольку попытка получить AVURLAsset/AVAsset в любой форме или форме для файлов, передаваемых через M3U8, поручение дураков.
В случае (a) ресурс вообще не создается, и вызов initWithURL: на AVURLAsset завершается неудачно с "неизвестной ошибкой" AVFoundationErrorDomain -11800.
В случае (b) и (c), извлечение AVURLAsset из AVPlayer/AVPlayerItem или AVAssetTracks возвращает объект SOME, но доступ к свойству дорожек для него всегда возвращает пустой массив.
В случае (d) я могу успешно извлекать и изолировать видеодорожки, но при попытке создать AVMutableCompositionTrack происходит сбой при попытке вставить CMTimeRange из исходной дорожки в AVMutableCompositionTrack с "неизвестной ошибкой" NSOSStatusErrorDomain -12780.
4) Удаленные M3U8 ведут себя точно так же, как и локальные M3U8.
Я не совсем осведомлен о том, почему эти различия существуют или не могут быть смягчены Apple. Но вот, пожалуйста.