2010-12-28 23 views
12

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

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

Sto cercando di caricare il video su un sito web in modo come una rapida prova di concetto sto cercando il seguente

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

dati non viene mai inizializzato in questo caso. Qualcuno è riuscito ad accedere all'URL direttamente tramite la nuova libreria di risorse? Grazie per l'aiuto.

+0

Ho provato con l'opzione proposta da Rich ma non funziona. Sto utilizzando lo stesso video memorizzato nella libreria iPhone per il mio test e talvolta il dizionario delle informazioni restituito contiene solo UIImagePickerControllerReferenceURL. Ho provato a utilizzare quell'URL come input per videoAssetURLToTempFile ma quando eseguo quel metodo non si accede al codice per aggiornare il blocco dei risultati. Non riesco a identificare in quali circostanze UIImagePickerController ha fatto funzionare correttamente il metodo delegato di FinishPickingMediaWithInfo. Qualche aiuto per favore? Grazie in anticipo! –

+0

È possibile che si tratti di un problema di versione iOS? UIImagePickerControllerReferenceURL è il vecchio metodo di restituzione dei dati. –

risposta

9

Ecco una soluzione rapida per ottenere video a s NSData. Esso utilizza il framework foto come ALAssetLibrary è deprecato come di iOS9:

IMPORTANTE

Il quadro elementi di una libreria è deprecato 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") 
        } 
       } 
      }) 
     } 
    } 
} 
17

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 eseguire lo spool del 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; 
} 
+0

A proposito: stai perdendo 'buffer'. – randallmeadows

+0

Hai ragione, grazie. –

+0

@RichDominelli, magnifico frammento! Grazie!!! – Suran

22

Io uso della 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 
+0

Grazie per questo! –

+0

Questo è quello che sto cercando .. Grazie @zoul – fyasar

10

ci si va ...

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

è possibile utilizzare una chiave di preset diverso se si desidera ricodificare il film (AVAssetExportPresetMediumQuality per esempio)

+1

Non ho capito come hai ottenuto il bene stesso? – Dejell

+0

Probabilmente è troppo tardi, ma è possibile creare un'istanza di un oggetto ALAsset da un URL di riferimento utilizzando il metodo [ALAssetLibrary assetForURL: resultBlock: failureBlock:]. – jpm

+0

Dovrebbe essere accettata risposta. Ma non dimenticare di inviare exportAsynchronouslyWithCompletionHandler:^nel thread principale, perché viene eseguito in background per impostazione predefinita. – faviomob

1

Ecco la Objective C soluzione del Alonzo risposta, Usare il foto quadro

-(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; 
    } 
0

questo dalla risposta di Zoul grazie

Similar Code in Xamarin C# 

Xamarin C# Equivalente

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); 
Problemi correlati