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

работая с новой фоторамкой, я могу получить доступ к NSData из PHAssets используя 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, так и info dictionary point в тот же файл jpg). Например, это URL-адрес и dataUTI, возвращенные для замедленного видео:

PHImageFileURLKey = "файл:///var/mobile/Media/PhotoData/Metadata / DCIM / 100APPLE / IMG_0642.ФОРМАТ JPG"; PHImageFileUTIKey = " public.в формате JPEG";

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

4 ответов


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

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

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

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

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

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

надеюсь, что это полезно для кого-то.


важно отметить, что замедленное видео имеет тип 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.


/ / видео slo-mo

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];
      }
}

следующий фрагмент кода для 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)
 }