Как получить доступ к 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 объединяет мультимедийные данные из нескольких источников.
экспорт замедленного видео
чтобы достичь этого, я в основном прошел трехэтапный процесс:
- создать выходной URL для видео
- настройка сеанса экспорта
- экспорт видео и захватить 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)
}