ios8 - NSURL de PHAsset
alassetslibrary photosframework (10)
Estoy convirtiendo nuestra aplicación para usar Photos Framework de iOS8, el framework ALAsset es claramente un ciudadano de segunda clase bajo iOS8.
Estoy teniendo un problema es que nuestra arquitectura realmente quiere un NSURL que represente la ubicación de los medios en "disco". Usamos esto para cargar los medios a nuestros servidores para su posterior procesamiento.
Esto fue fácil con ALAsset:
ALAssetRepresentation *rep = [asset defaultRepresentation];
self.originalVideo = rep.url;
Pero no estoy viendo esta habilidad en PHAsset. Creo que puedo llamar:
imageManager.requestImageDataForAsset
y luego escribirlo en un punto temporal en el sistema de archivos, pero parece terriblemente pesado y derrochador, por no hablar de potencialmente lento.
¿Hay alguna forma de obtener esto o tendré que refacturar más mi aplicación para que solo use NSURL para iOS7 y algún otro método para iOS8?
Al expresar la URL de PHAsset
, una vez había preparado un programa de utilidad en Swift 2 (aunque solo para reproducir videos de PHAsset
). Compartirlo en esta respuesta, podría ayudar a alguien.
static func playVideo (view:UIViewController, asset:PHAsset)
Por favor revisa esta Answer
Aquí hay una práctica categoría 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
Si tiene un PHAsset, puede obtener la URL de dicho activo de la siguiente manera:
[asset requestContentEditingInputWithOptions:editOptions
completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
NSURL *imageURL = contentEditingInput.fullSizeImageURL;
}];
Si usa [ imageManager
requestAVAssetForVideo
...], devolverá un AVAsset
. Ese AVAsset es realmente un AVURLAsset
, por lo que si lo AVURLAsset
, puedes acceder a su propiedad url
.
No estoy seguro si puede crear un nuevo activo a partir de esto, pero sí le da la ubicación.
Solo quiero publicar la gema oculta de un comentario de @jlw
@ rishu1992 Para videos de cámara lenta, tome AVCompositionTrack de AVComposition (de mediaType AVMediaTypeVideo), tome su primer segmento (de tipo AVCompositionTrackSegment) y luego acceda a su propiedad sourceURL. - jlw 25 de agosto de 15 a 11:52
Tenía un problema similar con los archivos de video, lo que funcionó para mí fue:
NSString* assetID = [asset.localIdentifier substringToIndex:(asset.localIdentifier.length - 7)];
NSURL* videoURL = [NSURL URLWithString:[NSString stringWithFormat:@"assets-library://asset/asset.mov?id=%@&ext=mov", assetID]];
Donde el activo es PHAsset.
Todas las soluciones anteriores no funcionarán para videos de cámara lenta. Una solución que encontré maneja todos los tipos de activos de video es esta:
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
}
}
}
Use la nueva propiedad localIdentifier de PHObject. (PHAs hereda de esto).
Proporciona una funcionalidad similar a una URL ALAsset, es decir, que puede cargar activos llamando al método
+[PHAsset fetchAssetsWithLocalIdentifiers:identifiers options:options]
Vea esta respuesta here .
Y este here .
Según mi experiencia, primero deberá exportar el activo a un disco para obtener una URL confiable y totalmente accesible.
Las respuestas vinculadas a arriba describen cómo hacer esto.
Versión de SWIFT 2.0 Esta función devuelve NSURL de PHAsset (tanto de imagen como de 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)
}
})
}
}