Ottenere video da ALAsset

Utilizzando il nuovo framework di librerie di asset disponibile in iOS 4, vedo che posso ottenere l’url per un determinato video utilizzando UIImagePickerControllerReferenceURL. L’URL restituito è nel seguente formato:

assets-library://asset/asset.M4V?id=1000000004&ext=M4V 

Sto cercando di caricare questo video su un sito Web, quindi come prova rapida del concetto sto provando quanto segue

 NSData *data = [NSData dataWithContentsOfURL:videourl]; [data writeToFile:tmpfile atomically:NO]; 

I dati non vengono mai inizializzati in questo caso. Qualcuno è riuscito ad accedere all’URL direttamente tramite la nuova libreria di risorse? Grazie per l’aiuto.

Ecco una soluzione rapida e pulita per ottenere video come NSData. Utilizza il framework Photos come ALAssetLibrary è deprecato da iOS9:

IMPORTANTE

Il framework della libreria di asset è obsoleto a partire da iOS 9.0. Utilizzare invece il framework Photos, che in iOS 8.0 e versioni successive offre più funzionalità e prestazioni migliori per lavorare con la libreria di foto di un utente. Per ulteriori informazioni, consultare Riferimento framework fotografico.

 import Photos func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { self.dismissViewControllerAnimated(true, completion: nil) if let referenceURL = info[UIImagePickerControllerReferenceURL] as? NSURL { let fetchResult = PHAsset.fetchAssetsWithALAssetURLs([referenceURL], options: nil) if let phAsset = fetchResult.firstObject as? PHAsset { PHImageManager.defaultManager().requestAVAssetForVideo(phAsset, options: PHVideoRequestOptions(), resultHandler: { (asset, audioMix, info) -> Void in if let asset = asset as? AVURLAsset { let videoData = NSData(contentsOfURL: asset.URL) // optionally, write the video to the temp directory let videoPath = NSTemporaryDirectory() + "tmpMovie.MOV" let videoURL = NSURL(fileURLWithPath: videoPath) let writeResult = videoData?.writeToURL(videoURL, atomically: true) if let writeResult = writeResult where writeResult { print("success") } else { print("failure") } } }) } } } 

Io uso la seguente categoria su ALAsset :

 static const NSUInteger BufferSize = 1024*1024; @implementation ALAsset (Export) - (BOOL) exportDataToURL: (NSURL*) fileURL error: (NSError**) error { [[NSFileManager defaultManager] createFileAtPath:[fileURL path] contents:nil attributes:nil]; NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:fileURL error:error]; if (!handle) { return NO; } ALAssetRepresentation *rep = [self defaultRepresentation]; uint8_t *buffer = calloc(BufferSize, sizeof(*buffer)); NSUInteger offset = 0, bytesRead = 0; do { @try { bytesRead = [rep getBytes:buffer fromOffset:offset length:BufferSize error:error]; [handle writeData:[NSData dataWithBytesNoCopy:buffer length:bytesRead freeWhenDone:NO]]; offset += bytesRead; } @catch (NSException *exception) { free(buffer); return NO; } } while (bytesRead > 0); free(buffer); return YES; } @end 

Questo non è il modo migliore per farlo. Sto rispondendo a questa domanda nel caso in cui un altro utente SO incontri lo stesso problema.

Fondamentalmente il mio bisogno era di essere in grado di spoolare il file video in un file tmp in modo da poterlo caricare su un sito web usando ASIHTTPFormDataRequest. Probabilmente esiste un modo per eseguire lo streaming dall’URL della risorsa al caricamento ASIHTTPFormDataRequest, ma non sono riuscito a capirlo. Invece ho scritto la seguente funzione per rilasciare il file in un file tmp da aggiungere a ASIHTTPFormDataRequest.

 +(NSString*) videoAssetURLToTempFile:(NSURL*)url { NSString * surl = [url absoluteString]; NSString * ext = [surl substringFromIndex:[surl rangeOfString:@"ext="].location + 4]; NSTimeInterval ti = [[NSDate date]timeIntervalSinceReferenceDate]; NSString * filename = [NSString stringWithFormat: @"%f.%@",ti,ext]; NSString * tmpfile = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) { ALAssetRepresentation * rep = [myasset defaultRepresentation]; NSUInteger size = [rep size]; const int bufferSize = 8192; NSLog(@"Writing to %@",tmpfile); FILE* f = fopen([tmpfile cStringUsingEncoding:1], "wb+"); if (f == NULL) { NSLog(@"Can not create tmp file."); return; } Byte * buffer = (Byte*)malloc(bufferSize); int read = 0, offset = 0, written = 0; NSError* err; if (size != 0) { do { read = [rep getBytes:buffer fromOffset:offset length:bufferSize error:&err]; written = fwrite(buffer, sizeof(char), read, f); offset += read; } while (read != 0); } fclose(f); }; ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) { NSLog(@"Can not get asset - %@",[myerror localizedDescription]); }; if(url) { ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease]; [assetslibrary assetForURL:url resultBlock:resultblock failureBlock:failureblock]; } return tmpfile; } 

Ecco qua …

 AVAssetExportSession* m_session=nil; -(void)export:(ALAsset*)asset withHandler:(void (^)(NSURL* url, NSError* error))handler { ALAssetRepresentation* representation=asset.defaultRepresentation; m_session=[AVAssetExportSession exportSessionWithAsset:[AVURLAsset URLAssetWithURL:representation.url options:nil] presetName:AVAssetExportPresetPassthrough]; m_session.outputFileType=AVFileTypeQuickTimeMovie; m_session.outputURL=[NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.mov",[NSDate timeIntervalSinceReferenceDate]]]]; [m_session exportAsynchronouslyWithCompletionHandler:^ { if (m_session.status!=AVAssetExportSessionStatusCompleted) { NSError* error=m_session.error; m_session=nil; handler(nil,error); return; } NSURL* url=m_session.outputURL; m_session=nil; handler(url,nil); }]; } 

È ansible utilizzare un tasto di preselezione diverso se si desidera ricodificare il film (ad esempio, AVAssetExportPresetMediumQuality )

Ecco la soluzione dell’objective C di Alonzo answer, Using photos framework

  -(NSURL*)createVideoCopyFromReferenceUrl:(NSURL*)inputUrlFromVideoPicker{ NSURL __block *videoURL; PHFetchResult *phAssetFetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[inputUrlFromVideoPicker ] options:nil]; PHAsset *phAsset = [phAssetFetchResult firstObject]; dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); [[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:nil resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) { if ([asset isKindOfClass:[AVURLAsset class]]) { NSURL *url = [(AVURLAsset *)asset URL]; NSLog(@"Final URL %@",url); NSData *videoData = [NSData dataWithContentsOfURL:url]; // optionally, write the video to the temp directory NSString *videoPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%f.mp4",[NSDate timeIntervalSinceReferenceDate]]]; videoURL = [NSURL fileURLWithPath:videoPath]; BOOL writeResult = [videoData writeToURL:videoURL atomically:true]; if(writeResult) { NSLog(@"video success"); } else { NSLog(@"video failure"); } dispatch_group_leave(group); // use URL to get file content } }]; dispatch_group_wait(group, DISPATCH_TIME_FOREVER); return videoURL; } 

questo dalla risposta di Zoul grazie

 Similar Code in Xamarin C# 

Equivalente Xamarin C #

 IntPtr buffer = CFAllocator.Malloc.Allocate(representation.Size); NSError error; nuint buffered = representation.GetBytes(buffer, Convert.ToInt64(0.0),Convert.ToUInt32(representation.Size),out error); NSData sourceData = NSData.FromBytesNoCopy(buffer,buffered,true); NSFileManager fileManager = NSFileManager.DefaultManager; NSFileAttributes attr = NSFileAttributes.FromDictionary(NSDictionary.FromFile(outputPath)); fileManager.CreateFile(outputPath, sourceData,attr);