首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用iCloud PHAsset请求PHAsset返回没有VideoTracks的AVAsset

使用iCloud PHAsset请求PHAsset返回没有VideoTracks的AVAsset
EN

Stack Overflow用户
提问于 2020-09-27 15:27:57
回答 1查看 2K关注 0票数 7

最近,开始注意到一些资产在从照片库导入时没有显示。问题中的资产存储在iCloud中,没有缓存在设备上。我相信这是一个iOS 14问题,因为我从未在iOS 13上经历过这个问题。(我不能100%肯定,因为我无法在iOS 13上推出我的个人设备)。

以下是我在iOS 14所做的工作

  1. 使用新的选择器视图控制器导入视频资产

代码语言:javascript
复制
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = PHPickerFilter.videos
let videoPickerController = PHPickerViewController(configuration: configuration)
videoPickerController.delegate = self
present(videoPickerController, animated: true, completion: nil)

PHPickerResult中提取PHAsset

代码语言:javascript
复制
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")
  }
}

然后,我为匹配的

请求一个AVAsset。

代码语言:javascript
复制
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
  }
}

Problem:通常,当资产来自iCloud时,我将不会有videoTrack。avAsset.duration也将是0.0。

我会看到下载的进展,但我将落在最后的警卫声明。有时,一旦该资产被下载并无法加载videoTrack,重试就会立即失败(它不会再次尝试加载该资产,似乎它已损坏)。这将落在最后的守卫声明中。

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

我想我在这里做错了什么。我应该从phAsset那里得到PHPickerResult吗?任何指针/帮助都将不胜感激。我创建了这个回购程序来复制https://github.com/SwiftRabbit/RequestAVAssetIssues/tree/main/RequestAVAssetIssues。不复制100%,必须是iCloud视频,不再在设备上。

补充说明/尝试:

PHImageManager

  • Some和的流行应用程序似乎也有同样的问题(比如Instagram,TikTok...)
  • PHCachingImageManager.default().requestPlayerItem也不起作用)。它返回一个不包含任何track.
  • iPhone XS、公司托管设备

的AVPlayerItem。

EN

回答 1

Stack Overflow用户

发布于 2020-12-24 16:56:49

我在我的iPad上录制了一段视频,等待它与iCloud同步,然后在2016年的iPhone SE上请求AVAsset。为了说明这一点,我在github上创建了一个回购程序。这是一个客观的C项目,但结论应该是相同的Swift。回购的主要部分是在https://github.com/Jan-E/ikyle.me-code-examples/blob/master/Photo%20Picker%20ObjC/Photo%20Picker%20ObjC/PHPickerController.m上。

这是我正在使用的代码:

代码语言:javascript
复制
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.duration返回正确的值
  2. phAsset.creationDate返回正确的值
  3. avAsset URL返回(Null)
  4. avAsset的持续时间为0.0秒

H 111 avAsset的曲目数为0H 212G 213

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

  1. phAsset.duration返回正确的值
  2. phAsset.creationDate返回正确的值
  3. avAsset URL返回正确的路径
  4. avAsset的持续时间是正确的值

H 124 avAsset的音轨数是1H 225G 226

完整的NSLog输出在2次提交的最后一次提交下面的2条注释中完成了:https://github.com/Jan-E/ikyle.me-code-examples/commit/2d0174c2766abf742b6d76d053abc0a46199358f

编辑:注意,在没有设备视频的示例中,从iCloud下载1.2GB视频需要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.duration获得有意义的值(来自早期的iCloud同步),但对于avAsset却没有活动值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64090158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档