使用iCloud PHAsset请求AVAsset返回不带视频跟踪的AVAsset [英] Request AVAsset using iCloud PHAsset returns an AVAsset with no VideoTracks

查看:0
本文介绍了使用iCloud PHAsset请求AVAsset返回不带视频跟踪的AVAsset的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,开始注意到从图片库导入某些资源时未显示这些资源。有问题的资产存储在iCloud中,而不是缓存在设备上。 我认为这是iOS 14的问题,因为我从来没有在iOS 13上遇到过这个问题。(我不能100%确定,因为我无法将我的个人设备推出到iOS 13)。

以下是我在iOS 14中所做的事情:

  1. 使用新的选取器视图控制器导入视频资源
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = PHPickerFilter.videos
let videoPickerController = PHPickerViewController(configuration: configuration)
videoPickerController.delegate = self
present(videoPickerController, animated: true, completion: nil)
  1. 我从[PHPickerResult](委托方法)中提取PHAsset
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
  picker.dismiss(animated: true, completion: nil)
  guard results.count > 0 else {
    return
  }
  guard let firstPHAssetIdentifier = results.first?.assetIdentifier else {
    fatalError("No asset identifier")
  }
  let fetchOptions = PHFetchOptions()
  guard let phAsset = PHAsset.fetchAssets(withLocalIdentifiers: [firstPHAssetIdentifier], options: fetchOptions).firstObject else {
    fatalError("No matching PHAsset")
  }
  guard phAsset.mediaType == .video else {
    fatalError("Asset not of the video type")
  }
}
  1. 然后,我为匹配的PHAsset请求AVAsset
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
options.progressHandler = { progress, _, _, _ in
  print("Progress: (progress)")
}

PHCachingImageManager.default().requestAVAsset(forVideo: phAsset, options: options) { [weak self] avAsset, _, info in
  guard info?[PHImageCancelledKey] == nil && info?[PHImageErrorKey] == nil else {
    print("Error or cancelled. Info: (String(describing: info))")
    return
  }
  guard let avAsset = avAsset else {
    print("Asset is nil. Info: (String(describing: info))")
    return
  }
  guard let videoTrack = avAsset.tracks(withMediaType: .video).first else {
    print("Cound not extract video track from AvAsset") // <- My issue
    return
  }
}

问题:当资产来自iCloud时,我通常不会有视频跟踪。AvAsset.time也将是0.0

我将看到下载进度,但我将讨论最后一条Guard语句。 有时,一旦下载了资源并且无法加载VideoTrack,重试就会立即失败(它不会再次尝试加载资源,似乎它已损坏)。它将落入最后一条Guard语句。

我注意到在PHVideoRequestOptions上使用deliveryMode=.HighQualityFormat可以正常工作,但我宁愿只下载720p的视频,而不是高质量的视频。

我想我在这里做错了什么。我应该这样从PHPickerResult中获取phAsset吗?任何指示器/帮助都将不胜感激。 我创建此回购是为了重现https://github.com/SwiftRabbit/RequestAVAssetIssues/tree/main/RequestAVAssetIssues。不会100%再现,并且必须是不再在设备上的iCloud视频。

其他备注/尝试:

  • 我在PHCachingImageManager和PHImageManager上也遇到过同样的问题
  • 一些流行的应用程序似乎对某些资产(如Instagram、TikTok...)也存在同样的问题
  • PHCachingImageManager.default().requestPlayerItem也不起作用。它返回不包含任何曲目的AVPlayerItem。
  • iPhone XS,企业托管设备

推荐答案

我在我的ipad上录制了一段视频,直到它同步到iCloud,然后在我的iPhone SE 2016上请求AVAsset,从而能够重现该问题。我已经在GitHub上创建了一个回购来说明这一点。这是一个客观C项目,但对SWIFT来说,结论应该是相同的。回购的关键部分在https://github.com/Jan-E/ikyle.me-code-examples/blob/master/Photo%20Picker%20ObjC/Photo%20Picker%20ObjC/PHPickerController.m

这是我使用的代码:

for (PHAsset *phAsset in assetResults) {
    float recordingDuration = phAsset.duration;
    NSLog(@"recordingDuration %f", recordingDuration);
    NSDate *PHAssetCreationDate = phAsset.creationDate;
    NSLog(@"PHAssetCreationDate %@", PHAssetCreationDate);
    PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
    options.networkAccessAllowed = NO;
    [[PHImageManager defaultManager] requestAVAssetForVideo:phAsset
                                                            options:options
                                                      resultHandler:^(AVAsset *avAsset, AVAudioMix *audioMix, NSDictionary *info) {
        NSURL *videoURL = (NSURL *)[[(AVURLAsset *)avAsset URL] fileReferenceURL];
        NSLog(@"videoURL absoluteString = %@", [videoURL absoluteString]);
        NSLog(@"videoURL relativePath   = %@", [videoURL relativePath]);
        AVURLAsset *avUrl = [AVURLAsset assetWithURL:videoURL];
        CMTime time = [avUrl duration];
        float recordingDuration;
        recordingDuration = time.value/time.timescale;
        NSArray *tracks = [avUrl tracksWithMediaType:AVMediaTypeVideo];
        NSLog(@"duration %f, tracks %lu", recordingDuration, (unsigned long)tracks.count);
    }];
}

当视频仍然只在iCloud上时,以下是NSLog返回的结果:

  1. phAsset.time返回正确的值
  2. phAsset.creationDate返回正确的值
  3. avAsset URL返回(空)
  4. avAsset的持续时间为0.0秒
  5. avAsset的磁道数为0

使用result.itemProvider loadFileRepresentationForTypeIdentifier可以强制将视频从iCloud下载到设备。结果如下:

  1. phAsset.time返回正确的值
  2. phAsset.creationDate返回正确的值
  3. avAsset URL返回正确的路径
  4. avAsset的持续时间是正确的值
  5. avAsset的磁道数为1

完整的NSLog输出位于两个成功提交中最后一个提交下面的两个注释中:https://github.com/Jan-E/ikyle.me-code-examples/commit/2d0174c2766abf742b6d76d053abc0a46199358f

编辑:请注意,在开始的示例中,设备上没有视频,从iCloud下载1.2 GB的视频花了4分23分(2020-12-24 15:45:13.669505+0100-2020-12-24 15:49:36.224240+0100)。并非所有情况下都需要下载。PhAsset.Duration的值为680.044983秒的信息可能就是您的应用程序中需要的所有信息,因为它意味着视频至少有一首曲目。

编辑2:通过使用options:nil,我使用的是隐式networkAccessAllowed = NO。在编辑时,我把它说得很清楚。它还可能给出持续时间为0.0和轨道为0的解释。如果允许网络访问,但网络连接失败,该怎么办?然后,您仍将获得phAsset.time的有意义的值(来自较早的iCloud同步),但不会获得avAsset的实时值。

这篇关于使用iCloud PHAsset请求AVAsset返回不带视频跟踪的AVAsset的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆