我试图解决这个问题,但无法找到任何有用的信息。 我才发现这个:
PHAssetResourceManager.defaultManager().writeDataForAssetResource(assetRes,
toFile: fileURL, options: nil, completionHandler:
{
// Video file has been written to path specified via fileURL
}
但我很惭愧地说我不知道如何发挥它。 我创建了一个UIImagePickerController,并从相机胶卷中加载了一个图像。
答案 0 :(得分:5)
使用此代码从实时照片中获取视频:
- (void)videoUrlForLivePhotoAsset:(PHAsset*)asset withCompletionBlock:(void (^)(NSURL* url))completionBlock{
if([asset isKindOfClass:[PHAsset class]]){
NSString* identifier = [(PHAsset*)asset localIdentifier];
NSString* filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov",[NSString stringWithFormat:@"%.0f",[[NSDate date] timeIntervalSince1970]]]];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
PHLivePhotoRequestOptions* options = [PHLivePhotoRequestOptions new];
options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestLivePhotoForAsset:asset targetSize:[UIScreen mainScreen].bounds.size contentMode:PHImageContentModeDefault options:options resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
if(livePhoto){
NSArray* assetResources = [PHAssetResource assetResourcesForLivePhoto:livePhoto];
PHAssetResource* videoResource = nil;
for(PHAssetResource* resource in assetResources){
if (resource.type == PHAssetResourceTypePairedVideo) {
videoResource = resource;
break;
}
}
if(videoResource){
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:fileUrl options:nil completionHandler:^(NSError * _Nullable error) {
if(!error){
completionBlock(fileUrl);
}else{
completionBlock(nil);
}
}];
}else{
completionBlock(nil);
}
}else{
completionBlock(nil);
}
}];
}else{
completionBlock(nil);
}
}
基本上您需要做的是首先需要从PHLivePhoto
获取PHAsset
对象。之后,您必须遍历实时照片中的所有资源资源,并检查其是否为PHAssetResourceTypePairedVideo
类型。
如果是的话,你收到了你的视频。现在,您需要将其保存到某个临时目录中,就像我在此处所做的那样,并将此文件用于您可能拥有的任何目的。
要播放此视频,您可以使用以下代码:
NSURL *videoURL = [NSURL fileURLWithPath:fileUrl];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerViewController *playerViewController = [AVPlayerViewController new];
playerViewController.player = player;
[self presentViewController:playerViewController animated:YES completion:nil];
随意询问您是否需要澄清。
PS - 我在此方法中做了一些更改,以删除我的应用程序代码的依赖性,因此上面的代码未经测试,但我觉得它应该按预期工作。
答案 1 :(得分:2)
问题有点令人困惑
首先,如果你想选择实时照片并播放实时照片。我建议你使用Photos Framework而不是UIImagePickerController。这样您就可以获取资产并获得更多控制权。然后,您可以将startPlayback(with:)
设置为hint
或full
,将实时照片设为mov或使用PHLivePhotoView播放静音版本。
您可以在此处参考代码:
其次,如果您想将实时照片转换为mov,您粘贴的代码将起作用,如果您想直接播放mov,则可能需要使用AVPlayer
另外,WWDC提供Example app using Photos framework
答案 2 :(得分:2)
import Photos
import MobileCoreServices
// <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@IBAction func showImagePicker(sender: UIButton) {
let picker = UIImagePickerController()
picker.delegate = self;
picker.allowsEditing = false;
picker.sourceType = .photoLibrary;
picker.mediaTypes = [kUTTypeLivePhoto as String, kUTTypeImage as String];
present(picker, animated: true, completion: nil);
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard
let livePhoto = info[UIImagePickerControllerLivePhoto] as? PHLivePhoto,
let photoDir = generateFolderForLivePhotoResources()
else {
return;
}
let assetResources = PHAssetResource.assetResources(for: livePhoto)
for resource in assetResources {
// SAVE FROM BUFFER
// let buffer = NSMutableData()
// PHAssetResourceManager.default().requestData(for: resource, options: nil, dataReceivedHandler: { (chunk) in
// buffer.append(chunk)
// }, completionHandler: {[weak self] error in
// self?.saveAssetResource(resource: resource, inDirectory: photoDir, buffer: buffer, maybeError: error)
// })
// SAVE DIRECTLY
saveAssetResource(resource: resource, inDirectory: photoDir, buffer: nil, maybeError: nil)
}
picker.dismiss(animated: true) {}
}
func saveAssetResource(
resource: PHAssetResource,
inDirectory: NSURL,
buffer: NSMutableData?, maybeError: Error?
) -> Void {
guard maybeError == nil else {
print("Could not request data for resource: \(resource), error: \(String(describing: maybeError))")
return
}
let maybeExt = UTTypeCopyPreferredTagWithClass(
resource.uniformTypeIdentifier as CFString,
kUTTagClassFilenameExtension
)?.takeRetainedValue()
guard let ext = maybeExt else {
return
}
guard var fileUrl = inDirectory.appendingPathComponent(NSUUID().uuidString) else {
print("file url error")
return
}
fileUrl = fileUrl.appendingPathExtension(ext as String)
if let buffer = buffer, buffer.write(to: fileUrl, atomically: true) {
print("Saved resource form buffer \(resource) to filepath \(String(describing: fileUrl))")
} else {
PHAssetResourceManager.default().writeData(for: resource, toFile: fileUrl, options: nil) { (error) in
print("Saved resource directly \(resource) to filepath \(String(describing: fileUrl))")
}
}
}
func generateFolderForLivePhotoResources() -> NSURL? {
let photoDir = NSURL(
// NB: Files in NSTemporaryDirectory() are automatically cleaned up by the OS
fileURLWithPath: NSTemporaryDirectory(),
isDirectory: true
).appendingPathComponent(NSUUID().uuidString)
let fileManager = FileManager()
// we need to specify type as ()? as otherwise the compiler generates a warning
let success : ()? = try? fileManager.createDirectory(
at: photoDir!,
withIntermediateDirectories: true,
attributes: nil
)
return success != nil ? photoDir! as NSURL : nil
}
答案 3 :(得分:0)
Swift 5
func videoUrlForLivePhotoAsset(asset: PHAsset, completionHandler: @escaping (_ result: URL?) -> Void) {
print("videoUrlForLivePhotoAsset: \(asset)")
let options : PHLivePhotoRequestOptions = PHLivePhotoRequestOptions.init()
options.deliveryMode = .fastFormat
options.isNetworkAccessAllowed = true
PHImageManager.default().requestLivePhoto(for: asset, targetSize: UIScreen.main.bounds.size, contentMode: .default, options: options) { (livePhoto, info) in
if livePhoto != nil {
let assetResources : [PHAssetResource] = PHAssetResource.assetResources(for: livePhoto!)
var videoResource : PHAssetResource?
for resource in assetResources {
if resource.type == .pairedVideo {
videoResource = resource
break
}
}
guard let photoDir = self.generateFolderForLivePhotoResources() else {
return
}
print("videoResource: \(videoResource)")
if videoResource != nil {
self.saveAssetResource(resource: videoResource!, inDirectory: photoDir, buffer: nil, maybeError: nil) { (fileUrl) in
completionHandler(fileUrl)
}
}
} else {
completionHandler(nil)
}
}
}
func saveAssetResource(
resource: PHAssetResource,
inDirectory: NSURL,
buffer: NSMutableData?, maybeError: Error?, completionHandler: @escaping (_ result: URL?) -> Void) {
guard maybeError == nil else {
print("Could not request data for resource: \(resource), error: \(String(describing: maybeError))")
return
}
let maybeExt = UTTypeCopyPreferredTagWithClass(
resource.uniformTypeIdentifier as CFString,
kUTTagClassFilenameExtension
)?.takeRetainedValue()
guard let ext = maybeExt else {
return
}
guard var fileUrl = inDirectory.appendingPathComponent(NSUUID().uuidString) else {
print("file url error")
return
}
fileUrl = fileUrl.appendingPathExtension(ext as String)
if let buffer = buffer, buffer.write(to: fileUrl, atomically: true) {
print("Saved resource form buffer \(resource) to filepath \(String(describing: fileUrl))")
completionHandler(fileUrl)
} else {
PHAssetResourceManager.default().writeData(for: resource, toFile: fileUrl, options: nil) { (error) in
print("Saved resource directly \(resource) to filepath \(String(describing: fileUrl))")
if error == nil {
completionHandler(fileUrl)
} else {
completionHandler(nil)
}
}
}
}
func generateFolderForLivePhotoResources() -> NSURL? {
let photoDir = NSURL(
// NB: Files in NSTemporaryDirectory() are automatically cleaned up by the OS
fileURLWithPath: NSTemporaryDirectory(),
isDirectory: true
).appendingPathComponent(NSUUID().uuidString)
let fileManager = FileManager()
// we need to specify type as ()? as otherwise the compiler generates a warning
let success : ()? = try? fileManager.createDirectory(
at: photoDir!,
withIntermediateDirectories: true,
attributes: nil
)
return success != nil ? photoDir! as NSURL : nil
}
使用以下内容调用:
let asset = PHAsset.init()
self.videoUrlForLivePhotoAsset(asset: asset!) { (url) in
print("url: \(url)")
}
注意:您需要清理 Temp 和 Documents 目录,并删除文件。