`PHAssetChangeRequest.creationRequestForAssetFromVideo(url:)` не работает для видео с высоким FPS на iPhone SE

Мы получили сообщения о проблемах с записью замедленного видео в нашем приложении. Мы протестировали проблему на iPhone X, iPhone 6 и iPhone SE. И 6, и X работают нормально, но SE терпит неудачу при попытке добавить записанное видео в Фото.


Видеофайл, который нужно добавить в Фото:

  • h.264 с рекомендуемыми настройками
  • Quicktime (.mov)
  • 120/200/240 кадров в секунду
  • Нет пользовательских метаданных
  • Аудио AAC с рекомендуемыми настройками

Наш код, добавляющий видео:

PHPhotoLibrary.shared().performChanges {  
    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url)  
}  

Возвращенная ошибка не предоставляет много полезной информации, что, по-видимому, является повторяющейся проблемой при работе с фотографиями.

Error Domain=NSCocoaErrorDomain Code=-1 "(null)"  

Мы применяем соотношение сторон к видео, используя чистые параметры апертуры настройки кодировщика. Судя по всему, изменение соотношения сторон видео влияет на результат (см. список внизу).


Мы пытались:

  • Поскольку соотношение сторон повлияло на результат, мы подумали, что проблема может быть связана с объемом данных, которые необходимо сохранить. Уменьшение битрейта/размера файла ничего не изменило
  • Возможно, что-то все еще использовало файл? Мы подождали несколько секунд, прежде чем добавить файл, но получили те же ошибки.
  • Изучил документы, форум разработчиков, SO, блоги и общий Google безрезультатно.

Еще раз — все отлично работает на iPhone X и 6.

Сочетания разрешения, частоты кадров и их результатов:

1080p

720p


У вас есть какие-либо идеи, в чем может быть проблема?


person Oyvindkg    schedule 13.01.2018    source источник
comment
Звучит достаточно странно (и достаточно воспроизводимо), чтобы сообщить об этом в Apple?   -  person halfer    schedule 16.01.2018
comment
Я получаю эту проблему для всех экспортированных видеофайлов с высоким FPS. Вы когда-нибудь находили решение для этого?   -  person wsidell    schedule 06.03.2018
comment
Мы все еще изучаем это. Если мы рассмотрим как подтвержденные, так и неподтвержденные отчеты об ошибках, похоже, что проблема присутствует на SE, 6, 6+ и 6S+. Если мы также предположим, что затронут 6S, это происходит на всех моделях старше 7. В настоящее время мы пытаемся выяснить, что изменилось между 6 и 7, чтобы найти потенциальных преступников (например, новое широкое цветовое пространство).   -  person Oyvindkg    schedule 15.03.2018
comment
Я вижу, что эта же функция не может сохранить видео, если вызов createRequestForAssetFromVideo вызывает сообщение авторизации.   -  person drewster    schedule 26.03.2018
comment
Для меня эта проблема возникает на симуляторе iPhone 5s. Я пробовал около 10 различных решений до сих пор. Отправка, настройка экспорта качества видео, продолжительность видео, различное содержимое видео, обертка разрешений вокруг блока. Это же видео работает на других симуляторах или реальных устройствах - но ненадежно. Другие видео не работают на других устройствах.... Обратите внимание, что мое видео создается AVExportSession, так что это добавляет целый уровень сложности в отношении того, что может быть не так с ним.   -  person FranticRock    schedule 17.01.2019
comment
Я знаю, что это прозвучит безумно, но соответствует ли ваше соглашение о пути к локальному ресурсу? Я знаю, что это смешно, но попробуйте добавить .mov к каждому URL-адресу независимо от контейнера. Code=-1 (null) больше не используется, без каких-либо других изменений, кроме форсирования этого расширения.   -  person Ryan Romanchuk    schedule 13.05.2019


Ответы (4)


РЕДАКТИРОВАНИЕ №4

Хорошо, этот снова вернулся, чтобы укусить меня, и я, вероятно, потратил еще два часа, пытаясь понять, как он регрессировал, поскольку код не трогали и ранее подтвердили, что он работает. Сначала я подумал, что это должно быть связано с устройством или кодировкой. Я закончил тем, что «исправил» это, но для меня это не имеет никакого смысла. Проблема была решена после того, как я добавил .mov к локальному файлу, который использовался для хранения удаленного видео после загрузки. Почему добавление произвольного расширения к пути к файлу имеет значение, я не понимаю.

let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let temporaryFilename = "\(ProcessInfo().globallyUniqueString).mov"
let fileURL = documentsURL.appendingPathComponent(temporaryFilename)
person Ryan Romanchuk    schedule 13.11.2018
comment
Это было оно! Спасибо ❤️ - person Iulian Onofrei; 23.07.2019
comment
Вы только что спасли мой день! Я бы никогда не узнал, что проблема в расширении файла. - person Kimi Chiu; 18.09.2020

У меня тоже была эта проблема. Я решил это, поместив запрос в блок авторизации. Как только пользователь ответит на приглашение, ваш блок PerformChanges будет вызван, и он должен завершиться успешно:

PHPhotoLibrary.requestAuthorization { (status) in 
  PHPhotoLibrary.shared().performChanges {  
    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url)  
  }
}
person dbn    schedule 19.04.2018

Я некоторое время боролся с этой неясной ошибкой и только что нашел решение.

Что было исправлено: мне нужно было убедиться, что ширина x высота экспортированного изображения, которое я использовал для компоновки видео через: AVAssetExportSession, соответствовали используемой настройке качества. Мой код изменял размер изображений до 1200 x 1920 (что является неправильным разрешением для моих целей). Размеры создаваемого видео были 1080 x 1920. Таким образом, AVAssetExportSession смог экспортировать изображения с неправильным разрешением, но это видео нельзя было сохранить в галерее, что привело к этой общей ошибке. Как только я использовал изображения с правильным разрешением (1080 x 1920), экспорт с использованием PHPhotoLibrary.shared().performChanges отлично работает на iPhone 5s и других телефонах.

person FranticRock    schedule 17.01.2019

Недавно я боролся с этой ошибкой, и мне удалось ее решить, экспортировав файл не с заданным именем AVAssetExportPresetPassthrough, а с AVAssetExportPresetHighestQuality.

Таким образом, файл будет экспортирован с наивысшим качеством, которое может поддерживать текущее устройство (без большого ущерба для исходного файла), поэтому импорт в Cameraroll не завершится ошибкой.

private func encodeVideo(at videoURL: URL, completion: ((Swift.Result<URL, Error>) -> Void)?) {

    let avAsset = AVURLAsset(url: videoURL, options: nil)

    // Create Export session BUT WITH AVAssetExportPresetHighestQuality 
    guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetHighestQuality) else {
        completion?(.failure(VideoEncodingError
            .invalidAVAssetSession))
        return
    }

    // Creating temp path to save the converted video
    let documentsDirectory = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL)
    let fileName = "\(UUID().uuidString).\(MCConstants.BGDownload.mp4Extension)"
    let filePath = documentsDirectory.appendingPathComponent(fileName)

    exportSession.outputURL = filePath
    exportSession.outputFileType = AVFileType.mp4
    exportSession.shouldOptimizeForNetworkUse = true
    let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
    let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
    exportSession.timeRange = range

    exportSession.exportAsynchronously {
        switch exportSession.status {
        case .failed: completion?(.failure(exportSession.error ?? VideoEncodingError.unknown))
        case .cancelled: completion?(.failure(VideoEncodingError.cancelled))
        case .completed:

            if let _url = exportSession.outputURL {
                completion?(.success(_url))
            } else {
                completion?(.failure(VideoEncodingError.encodedURLUnavailable))
            }

        default: completion?(.failure(VideoEncodingError.unknown))
        }
    }
}
person mtet88    schedule 13.10.2020