Как получить доступ к NSData / NSURL замедленного видео с помощью PhotoKit

Работая с новой структурой фотографий, я могу получить доступ к NSData PHAsset, используя requestImageDataForAsset. Я также могу получить доступ к URL-адресу файла, используя PHImageFileURLKey возвращенного info NSDictionary.

[[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {

                //imageData contains the correct data for images and videos
                NSLog(@"info - %@", info);
                NSURL* fileURL = [info objectForKey:@"PHImageFileURLKey"];
}];

Это отлично работает для изображений и обычных видео.

Однако, когда активом является PHAssetMediaSubtypeVideoHighFrameRate (замедленное видео), возвращаемые данные соответствуют файлу JPG, содержащему первый кадр видео (как NSData, так и dataUTI, и информационный словарь указывают на один и тот же файл jpg). Например, это URL-адрес и dataUTI, возвращаемые для замедленного видео:

PHImageFileURLKey = "файл: ///var/mobile/Media/PhotoData/Metadata/DCIM/100APPLE/IMG_0642.JPG"; PHImageFileUTIKey = "public.jpeg";

Почему это происходит? Как я могу получить доступ к NSData / NSURL замедленного видео вместо этого предварительного просмотра JPG?


person GuillermoMP    schedule 01.10.2014    source источник


Ответы (4)


После того, как я сходил с ума и протестировал каждый вариант, я обнаружил проблему.

Ответственность за возврат изображений JPG для замедленного видео - это значение по умолчанию PHImageRequestOptionsVersionCurrent для свойства PHImageRequestOptions.version.

Просто назначьте версию PHImageRequestOptionsVersionUnadjusted или PHImageRequestOptionsVersionOriginal вернет исходное замедленное видео.

PHImageRequestOptions * imageRequestOptions = [[PHImageRequestOptions alloc] init];

imageRequestOptions.version = PHImageRequestOptionsVersionUnadjusted;
// or 
imageRequestOptions.version = PHImageRequestOptionsVersionOriginal;

Я считаю это неожиданным поведением, поскольку не ожидаю, что «текущая» версия замедленного видео будет неподвижным изображением (возможно, видео с примененным эффектом замедленного движения, но не фото).

Надеюсь, это будет кому-то полезно.

person GuillermoMP    schedule 02.10.2014
comment
Вы знаете, как получить NSData замедленного видео? Я пробовал метод requestAVAssetForVideo, но он возвращает AVComposition вместо AVAsset или AVURLAsset. Моя проблема в том, как получить NSData из AVComposition. - person Pratik Mistry; 28.02.2015
comment
Вы можете преобразовать актив в videoAsset as? AVURLAsset и получить данные следующим образом try? Data(contentsOf: videoAsset.url) - person Roman Shinyavski; 18.08.2020

Важно отметить, что замедленное видео относится к типу AVComposition, а не AVURLAsset. Объект AVComposition объединяет мультимедийные данные из нескольких источников вместе.

Экспорт замедленного видео

Чтобы добиться этого, я в основном прошел трехэтапный процесс:

  1. Создайте выходной URL для видео
  2. Настроить сеанс экспорта
  3. Экспортируйте видео и получите URL!

PHVideoRequestOptions *options = [PHVideoRequestOptions new];
        options.networkAccessAllowed = YES;
        [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
            if(([asset isKindOfClass:[AVComposition class]] && ((AVComposition *)asset).tracks.count == 2)){
                //slow motion videos. See Here: https://overflow.buffer.com/2016/02/29/slow-motion-video-ios/

                //Output URL of the slow motion file.
                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                NSString *documentsDirectory = paths.firstObject;
                NSString *myPathDocs =  [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"mergeSlowMoVideo-%d.mov",arc4random() % 1000]];
                NSURL *url = [NSURL fileURLWithPath:myPathDocs];

                //Begin slow mo video export
                AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
                exporter.outputURL = url;
                exporter.outputFileType = AVFileTypeQuickTimeMovie;
                exporter.shouldOptimizeForNetworkUse = YES;

                [exporter exportAsynchronouslyWithCompletionHandler:^{
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (exporter.status == AVAssetExportSessionStatusCompleted) {
                            NSURL *URL = exporter.outputURL;
                            self.filePath=URL.absoluteString;



                            // NSData *videoData = [NSData dataWithContentsOfURL:URL];
                            //
                            //// Upload
                            //[self uploadSelectedVideo:video data:videoData];
                        }
                    });
                }];


            } 
        }];

Посетите этот замечательный блог, чтобы узнать о замедленных видео в iOS.

person Utsav Dusad    schedule 08.09.2016
comment
Да, это было здорово. Действительно ценю это! Избавило меня от многих разочарований. - person Ibdakine; 11.06.2017
comment
Это для случая, когда вы выбираете из библиотеки фотографий. Что, если я запишу замедленное видео, а затем захочу его загрузить? stackoverflow.com/questions/47514282 / - person nr5; 11.12.2017

Следующий фрагмент кода для Swift 3/4

PHImageManager.default().requestAVAsset(forVideo: asset, 
                                         options: nil, 
                                         resultHandler: { (asset, _, _) in

            // AVAsset has two sub classes: AVComposition and AVAssetURL
            // AVComposition for slow mo vid
            // AVAssetURL for normal videos

            // For slow motion video checking for AVCompostion
            // Creating an exporter to write the video into local file path and using the same to play/upload

            if asset!.isKind(of: AVComposition.self){

                let avCompositionAsset = asset as! AVComposition

                if avCompositionAsset.tracks.count > 1{

                    let exporter = AVAssetExportSession(asset: avCompositionAsset, presetName: AVAssetExportPresetHighestQuality)
                    exporter!.outputURL = self.fetchOutputURL()
                    exporter!.outputFileType = AVFileTypeMPEG4
                    exporter!.shouldOptimizeForNetworkUse = true

                    exporter!.exportAsynchronously {
                        DispatchQueue.main.sync {
                          // Use this url for uploading or playing a video
                           let url = exporter!.outputURL
                        }
                    }
                }
            }else{

                // Normal video, are stored as AVAssetURL

                let url = (asset as! AVURLAsset).url
            }
        })

// Fetch local path

 func fetchOutputURL() -> URL{
     let documentDirectory = getDocumentsDirectory() as NSString
     let path = documentDirectory.appendingPathComponent("test.mp4")
     return URL(fileURLWithPath:path)
 }
person sahiljain    schedule 04.10.2017
comment
Можно использовать следующие коды для создания выходного URL: let exportPath = NSTemporaryDirectory().appendingFormat("\(fileName).mov") let exportUrl = NSURL.fileURL(withPath: exportPath) - person Shan; 05.11.2020

// замедленное видео

PHVideoRequestOptions *options=[[PHVideoRequestOptions alloc]init];
options.version=PHVideoRequestOptionsVersionOriginal;

Запросить AVAsset из PHImageManager

[[PHImageManager defaultManager] requestAVAssetForVideo:videoAsset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info)
 {         
     if ([asset isKindOfClass:[AVURLAsset class]])
     {
         // use URL to get file content

         NSURL *URL = [(AVURLAsset *)asset URL];
         NSData *videoData=[NSData dataWithContentsOfURL:URL];
         NSNumber *fileSizeValue = nil;
         [URL getResourceValue:&fileSizeValue forKey:NSURLFileSizeKey error:nil];
      }
}
person guhan0    schedule 03.11.2015
comment
Это не даст URL-адрес для замедленного видео, потому что замедленное видео представляет собой комбинацию 2 или более файлов. - person Utsav Dusad; 08.09.2016
comment
Нам нужно экспортировать замедленное видео. Более того, вышеупомянутый метод предоставит URL-адрес для объектов типа AVURLAsset, но замедленное видео относится к типу AVComposition. - person Utsav Dusad; 08.09.2016