PHAsset生成NSURL

41

我正在将我们的应用程序转换为使用iOS8的Photos Framework,ALAsset框架在iOS8下显然是个次等公民。

我的问题是我们的架构确实需要一个NSURL来表示介质在“磁盘”上的位置。我们使用它将媒体上传到我们的服务器以进行进一步处理。

这对于ALAsset来说很容易:

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

但是我在PHAsset中没有看到这种功能。我猜我可以调用:

    imageManager.requestImageDataForAsset

然后将其写入文件系统中的临时位置,但这似乎过于笨重和浪费,更不用说潜在的速度缓慢。

有没有一种方法可以实现这一点,还是我需要重构我的应用程序以仅在iOS7中使用NSURL,并在iOS8中使用其他方法?


仔细查看我的代码后,我使用URL的唯一原因是将其提供给AVAssetExportSession和/或AVAssetImageGenerator,所以我想我只需替换这些调用。然而,一旦我将其提供给它们,我仍然需要一个NSURL传递给我们的上传器,所以我敢打赌问题仍然存在。 - Paul Cezanne
1
从您在此处的评论中看来,似乎您已经自己解决了这个问题,但为了让其他人也能看到这个问题: 如果您只需要使用旧方法(如AVAssetExportSession)的URL,则可以使用与PHAsset匹配而不是AVAsset(AVURLAsset)的新版本。例如:PHImageManager.defaultManager()的requestExportSessionForVideo和requestPlayerItemForVideo。 - emem
10个回答

25
如果您使用 [imageManager requestAVAssetForVideo...],它将返回一个AVAsset。该AVAsset实际上是一个AVURLAsset,因此如果对其进行强制转换,则可以访问其-url属性。
我不确定是否可以使用此功能创建新资产,但它确实提供了位置信息。

你又来了!:-) 我已经忘记了这个问题。我走了另一条路,可以看看我的其他问题,但这显然也是正确的。顺便说一下,你80年代没有在柯达工作过吧?当时认识一个jlw... - Paul Cezanne
4
这可能是一个愚蠢的问题,但这也适用于图片吗? - gdbj
1
这对于慢动作视频不起作用,它将返回其超类为AVAsset的AVComposition。AVAsset有子类,如AVURLAsset和AVAsset。 - rishu1992
9
对于慢动作视频,获取AVComposition的AVCompositionTrack(媒体类型为AVMediaTypeVideo),获取其第一个片段(类型为AVCompositionTrackSegment),然后访问其sourceURL属性。 - jlw
@rishu1992 这对于图像不起作用,它会返回一个空的AVAsset。 - Xys

19

SWIFT 2.0版本 此函数从PHAsset(包括图像和视频)返回NSURL。

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

}

我如何读取路径的内容?当我尝试使用NSData(contentsOfFile: "...")获取时,似乎无法获取。有没有一种方法可以从路径中读取此文件,例如“file:///var/mobile/Media/PhotoData/PhotoCloudSharingData/211607360/28D50A9E-57E3-4280-B75D-7DC228A19147/100CLOUD/IMG_1170.JPG”? - Kevin Lieser
变量路径:String = pathURL.path()变量数据:NSData = NSFileManager.defaultManager()。contentsAtPath(path) - Adam Studenic
7
似乎我没有权限或者其他什么问题(已授权访问照片库)。当我尝试使用 NSFileManager.defaultManager().fileExistsAtPath() 时,它返回 false,所以我也无法获取文件的内容。但文件肯定是存在的。 - Kevin Lieser
2
这还没有解决真是太疯狂了。我需要一个可靠的URL,具有永久的读取访问权限,以便用于NSURLSessionUploadTask的工作。由于iPhone的存储空间非常有限,我无法将所有资产复制到临时位置进行上传。用户的错误消息会是什么样子:“很抱歉,您无法将文件上传到我们的服务器,因为您设备上的存储空间太低?”???没有人会理解这个。 - fruitcoder
对于视频部分,它运行得非常好,我只需要将其适应于Objective C。非常感谢! - Alexandre Rozier
1
如果您使用的是 Objective-C 而不是 Swift,请参考 Sahil 的答案。对于普通图像,它对我有效。 - Alyoshak

9
如果您有一个PHAsset,可以通过以下方式获取该资产的URL:
[asset requestContentEditingInputWithOptions:editOptions
                           completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
    NSURL *imageURL = contentEditingInput.fullSizeImageURL;
}];

9
使用PHObject的新localIdentifier属性。(PHAsset继承此属性)。
它提供与ALAsset URL类似的功能,即您可以通过调用方法加载资产。
+[PHAsset fetchAssetsWithLocalIdentifiers:identifiers options:options]

5
所有上述解决方案都无法适用于慢动作视频。我找到的一个解决方案可以处理所有类型的视频资产,具体如下:
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
        }
    }
}

3

请看这个答案这里

还有一个答案在这里

根据我的经验,您需要首先将资产导出到磁盘,以获得完全可访问/可靠的URL。

上面链接的答案描述了如何做到这一点。


2

我想分享来自@jlw评论中的隐藏宝石

@rishu1992 对于慢动作视频,获取AVComposition的AVCompositionTrack(媒体类型为AVMediaTypeVideo),获取其第一个片段(类型为AVCompositionTrackSegment),然后访问其sourceURL属性。– jlw 2015年8月25日11:52


1
这是一个方便的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
在谈到来自PHAsset的url时,我曾经为Swift 2准备了一个实用函数(虽然只能播放来自PHAsset的视频)。在此答案中分享它可能会对某些人有所帮助。
static func playVideo (view:UIViewController, asset:PHAsset)

请检查此 Answer

0

我曾经遇到过视频文件的类似问题,解决方法是:

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

其中 asset 是 PHAsset。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接