Je dois utiliser l'objet AVAsset pour pouvoir le lire avec AVPlayer et AVPlayerLayer. J'ai commencé à utiliser le cadre Photos depuis qu'AssetsLibrary est obsolète. Maintenant, je suis arrivé au point où j'ai un tableau d'objets PHAsset et que je dois les convertir en AVAsset. J'ai essayé d'énumérer via PHFetchResult et d'attribuer un nouvel AVAsset à l'aide de la description localisée de PHAsset, mais il ne semble pas afficher de vidéo lorsque je le lis.
PHAssetCollection *assetColl = [self scaryVideosAlbum];
PHFetchResult *getVideos = [PHAsset fetchAssetsInAssetCollection:assetColl options:nil];
[getVideos enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
NSURL *videoUrl = [NSURL URLWithString:asset.localizedDescription];
AVAsset *avasset = [AVAsset assetWithURL:videoUrl];
[tempArr addObject:avasset];
}];
Je suppose que la description localisée n'est pas l'URL absolue de la vidéo.
Je suis également tombé sur PHImageManager et sur requestAVAssetForVideo; toutefois, le paramètre options en ce qui concerne la vidéo n'a pas de propriété isSynchrounous, ce qui est le cas du paramètre options d'image.
PHVideoRequestOptions *option = [PHVideoRequestOptions new];
[[PHImageManager defaultManager] requestAVAssetForVideo:videoAsset options:option resultHandler:^(AVAsset * _Nullable avasset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
Y a-t-il une manière synchrone de faire ceci?
Merci.
Non, il n'y en a pas. Mais vous pouvez construire une version synchrone:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
PHVideoRequestOptions *option = [PHVideoRequestOptions new];
__block AVAsset *resultAsset;
[[PHImageManager defaultManager] requestAVAssetForVideo:videoAsset options:option resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) {
resultAsset = avasset;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// yay, we synchronously have the asset
[self doSomethingWithAsset:resultAsset];
Toutefois, si vous faites cela sur le thread principal et que requestAVAssetForVideo:
prend trop de temps, vous risquez de verrouiller votre interface utilisateur ou même de vous faire arrêter par le iOS watchdog .
Il est probablement plus sûr de retravailler votre application pour qu'elle fonctionne avec la version de rappel asynchrone. Quelque chose comme ça:
__weak __typeof(self) weakSelf = self;
[[PHImageManager defaultManager] requestAVAssetForVideo:videoAsset options:option resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomethingWithAsset:avasset];
});
}];
Pour Swift 2 , vous pouvez facilement lire la vidéo avec PHAsset
en utilisant la méthode ci-dessous,
import AVKit
static func playVideo (view:UIViewController, asset:PHAsset) {
guard (asset.mediaType == PHAssetMediaType.Video)
else {
print("Not a valid video media type")
return
}
PHCachingImageManager().requestAVAssetForVideo(asset, options: nil, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [NSObject : AnyObject]?) in
let asset = asset as! AVURLAsset
dispatch_async(dispatch_get_main_queue(), {
let player = AVPlayer(URL: asset.URL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
view.presentViewController(playerViewController, animated: true) {
playerViewController.player!.play()
}
})
})
}
Vous pouvez essayer cette astuce, mais elle est pratique lorsque vous souhaitez convertir 3,4 ou 5 phassets au format AVAsset:
[[PHImageManager defaultManager] requestAVAssetForVideo:assetsArray[0] options:option resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) {
//do something with this asset
[[PHImageManager defaultManager] requestAVAssetForVideo:assetsArray[1] options:option resultHandler:^(AVAsset * avasset, AVAudioMix * audioMix, NSDictionary * info) {
//so on...
}
}
En gros, vous pouvez rappeler cette méthode lorsque vous avez converti 1 phasset en AVAsset.Je sais que ce n'est peut-être pas un code efficace, mais il ne devrait pas être interdit pour de petites raisons.
Ce qui suit est une implémentation de Swift 4 qui repose sur un sémaphore pour effectuer la demande de manière synchrone.
Le code est commenté pour expliquer les différentes étapes.
func requestAVAsset(asset: PHAsset) -> AVAsset? {
// We only want videos here
guard asset.mediaType == .video else { return nil }
// Create your semaphore and allow only one thread to access it
let semaphore = DispatchSemaphore.init(value: 1)
let imageManager = PHImageManager()
var avAsset: AVAsset?
// Lock the thread with the wait() command
semaphore.wait()
// Now go fetch the AVAsset for the given PHAsset
imageManager.requestAVAsset(forVideo: asset, options: nil) { (asset, _, _) in
// Save your asset to the earlier place holder
avAsset = asset
// We're done, let the semaphore know it can unlock now
semaphore.signal()
}
return avAsset
}