web-dev-qa-db-fra.com

NSURL de PHAsset

Je suis en train de convertir notre application pour utiliser le cadre de photos d'iOS8, le cadre d'ALAsset est clairement un citoyen de seconde classe sous iOS8.

J'ai un problème, c'est que notre architecture veut vraiment un NSURL qui représente l'emplacement du média sur le "disque". Nous l'utilisons pour télécharger le support sur nos serveurs pour un traitement ultérieur.

C'était facile avec ALAsset:

    ALAssetRepresentation *rep = [asset defaultRepresentation];
    self.originalVideo = rep.url;

Mais je ne vois tout simplement pas cette capacité dans PHAsset. Je suppose que je peux appeler:

    imageManager.requestImageDataForAsset

puis écrivez-le sur un emplacement temporaire dans le système de fichiers, mais cela semble terriblement lourd et inutile, sans parler de la lenteur potentielle.

Existe-t-il un moyen d'obtenir ceci ou vais-je avoir plus de refactor de mon application pour utiliser uniquement NSURLs pour iOS7 et une autre méthode pour iOS8?

39
Paul Cezanne

Si vous utilisez [imageManagerrequestAVAssetForVideo...], il retournera une AVAsset. AVAsset est en fait une AVURLAsset, donc si vous le lancez, vous pouvez accéder à la propriété -url

Je ne sais pas si vous pouvez créer un nouvel actif à partir de cela, mais cela vous donne l'emplacement.

24
jlw

Version Swift 2.0 Cette fonction renvoie NSURL à partir de PHAsset (image et vidéo)

func getAssetUrl(mPhasset : PHAsset, completionHandler : ((responseURL : NSURL?) -> Void)){

    if mPhasset.mediaType == .Image {
        let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
        options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
            return true
        }
        mPhasset.requestContentEditingInputWithOptions(options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [NSObject : AnyObject]) -> Void in
            completionHandler(responseURL : contentEditingInput!.fullSizeImageURL)
        })
    } else if mPhasset.mediaType == .Video {
        let options: PHVideoRequestOptions = PHVideoRequestOptions()
        options.version = .Original
        PHImageManager.defaultManager().requestAVAssetForVideo(mPhasset, options: options, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [NSObject : AnyObject]?) -> Void in

            if let urlAsset = asset as? AVURLAsset {
                let localVideoUrl : NSURL = urlAsset.URL
                completionHandler(responseURL : localVideoUrl)
            } else {
                completionHandler(responseURL : nil)
            }
        })
    }

}
17
Adam Studenic

Si vous avez un PHAsset, vous pouvez obtenir l'URL de cet actif de la manière suivante:

[asset requestContentEditingInputWithOptions:editOptions
                           completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
    NSURL *imageURL = contentEditingInput.fullSizeImageURL;
}];
9
Sahil

Utilisez la nouvelle propriété localIdentifier de PHObject. (PHAsset en hérite). 

Il fournit une fonctionnalité similaire à une URL ALAsset, à savoir que vous pouvez charger des actifs en appelant la méthode. 

+[PHAsset fetchAssetsWithLocalIdentifiers:identifiers options:options]
9
bcattle

Toutes les solutions ci-dessus ne fonctionneront pas pour les vidéos au ralenti. Une solution que j'ai trouvée gère tous les types d'actifs vidéo est la suivante:

func createFileURLFromVideoPHAsset(asset: PHAsset, destinationURL: NSURL) {
    PHCachingImageManager().requestAVAssetForVideo(self, options: nil) { avAsset, _, _ in
        let exportSession = AVAssetExportSession(asset: avAsset!, presetName: AVAssetExportPresetHighestQuality)!
        exportSession.outputFileType = AVFileTypeMPEG4
        exportSession.outputURL = destinationURL

        exportSession.exportAsynchronouslyWithCompletionHandler {
            guard exportSession.error == nil else {
                log.error("Error exporting video asset: \(exportSession.error)")
                return
            }

            // It worked! You can find your file at: destinationURL
        }
    }
}
5
desmond

Voir cette réponse ici

Et celui-ci ici .

D'après mon expérience, vous devez d'abord exporter l'actif sur le disque afin d'obtenir une URL entièrement accessible/fiable. 

Les réponses liées à ci-dessus décrivent comment faire cela.

3
Alfie Hanssen

Je veux juste poster le joyau caché d'un commentaire de @jlw 

@ rishu1992 Pour les vidéos au ralenti, récupérez le .Composition de l'AV. AVCompositionTrack (de mediaType AVMediaTypeVideo), récupérez son premier segment (de type AVCompositionTrackSegment), puis accédez à son fichier propriété sourceURL. - Jlw 25 août 15 à 11:52

1
Oliver Hu

En spécifiant l'url de PHAsset, j'avais déjà préparé une fonction util sur Swift 2 (bien que pour la lecture de vidéos de PHAsset). Le partager dans cette réponse pourrait aider quelqu'un.

static func playVideo (view:UIViewController, asset:PHAsset)

Veuillez vérifier ceci Réponse

1
Sazzad Hissain Khan

Voici une catégorie pratique de PHAsset:

@implementation PHAsset (Utils)

- (NSURL *)fileURL {
    __block NSURL *url = nil;

    switch (self.mediaType) {
        case PHAssetMediaTypeImage: {
            PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
            options.synchronous = YES;
            [PHImageManager.defaultManager requestImageDataForAsset:self
                                                            options:options
                                                      resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                                                          url = info[@"PHImageFileURLKey"];
                                                      }];
            break;
        }
        case PHAssetMediaTypeVideo: {
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
            [PHImageManager.defaultManager requestAVAssetForVideo:self
                                                          options:nil
                                                    resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
                                                        if ([asset isKindOfClass:AVURLAsset.class]) {
                                                            url = [(AVURLAsset *)asset URL];
                                                        }
                                                        dispatch_semaphore_signal(semaphore);
                                                    }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            break;
        }
        default:
            break;
    }
    return url;
}

@end
1
Lizhen Hu

J'ai eu un problème similaire avec les fichiers vidéo, ce qui a fonctionné pour moi était:

NSString* assetID = [asset.localIdentifier substringToIndex:(asset.localIdentifier.length - 7)];
NSURL* videoURL = [NSURL URLWithString:[NSString stringWithFormat:@"assets-library://asset/asset.mov?id=%@&ext=mov", assetID]];

Où atout est PHAsset.

0
Gamec