NSURL from PHAsset

巧了我就是萌 提交于 2019-11-27 03:49:31

If you use [imageManager requestAVAssetForVideo...], it'll return an AVAsset. That AVAsset is actually an AVURLAsset, so if you cast it, you can access it's -url property.

I'm not sure if you can create a new asset out of this, but it does give you the location.

SWIFT 2.0 version This function returns NSURL from PHAsset (both image and video)

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)
            }
        })
    }

}

If you have a PHAsset, you can get the url for said asset like this:

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

Use the new localIdentifier property of PHObject. (PHAsset inherits from this).

It provides similar functionality to an ALAsset URL, namely that you can load assets by calling the method

+[PHAsset fetchAssetsWithLocalIdentifiers:identifiers options:options]

All the above solutions won't work for slow-motion videos. A solution that I found handles all video asset types is this:

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
        }
    }
}
Alfie Hanssen

See this answer here.

And this one here.

In my experience you'll need to first export the asset to disk in order to get a fully accessible / reliable URL.

The answers linked to above describe how to do this.

Sazzad Hissain Khan

In speking of url from PHAsset, I had once prepared a util func on Swift 2 (although only for playing videos from PHAsset). Sharing it in this answer, might help someone.

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

Please check this Answer

Just want to post the hidden gem from a comment from @jlw

@rishu1992 For slo-mo videos, grab the AVComposition's AVCompositionTrack (of mediaType AVMediaTypeVideo), grab its first segment (of type AVCompositionTrackSegment), and then access its sourceURL property. – jlw Aug 25 '15 at 11:52

Here's a handy PHAsset category:

@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

I had similiar problem with video files, what worked for me was:

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

Where asset is PHAsset.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!