2010-12-28 7 views
12

Mit dem neuen Asset-Bibliothek-Framework in iOS 4 sehe ich, dass ich die URL für ein bestimmtes Video mit dem UIImagePickerControllerReferenceURL erhalten kann. Die URL zurückgegeben wird in folgendem Format:Video von ALAsset erhalten

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

Ich versuche, das Video auf eine Website hochladen, um ein schnell Proof of Concept ich versuche die folgenden

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

Daten wird nie in initialisiert dieser Fall. Hat jemand es geschafft, direkt über die neue Asset-Bibliothek auf die URL zuzugreifen? Danke für Ihre Hilfe.

+0

Ich versuchte mit der Option von Rich vorgeschlagen, aber funktioniert nicht. Ich verwende das gleiche Video in der iPhone-Bibliothek für meinen Test gespeichert und manchmal das zurückgegebene Info-Wörterbuch enthält nur UIImagePickerControllerReferenceURL. Ich habe versucht, diese URL als Eingabe für videoAssetURLToTempFile zu verwenden, aber beim Ausführen dieser Methode wird der Code nicht eingegeben, um den Ergebnisblock zu aktualisieren. Ich kann nicht identifizieren, unter welchen Umständen die UIImagePickerController didFinishPickingMediaWithInfo-Delegate-Methode ordnungsgemäß funktioniert. Einige helfen bitte? Vielen Dank im Voraus! –

+0

Ist es möglich, dass es sich um ein Problem mit der iOS-Version handelt? UIImagePickerControllerReferenceURL ist die alte Methode zum Zurückgeben der Daten. –

Antwort

9

Hier ist eine saubere schnelle Lösung, um Videos zu erhalten s NSDaten. Es verwendet die Fotos Rahmen als ALAssetLibrary ab iOS9 veraltet:

WICHTIG

Die Assets Bibliothek Rahmen ab iOS 9.0 ist veraltet. Verwenden Sie stattdessen das Photos-Framework, das in iOS 8.0 und höher mehr Funktionen und eine bessere Leistung für die Arbeit mit der Fotobibliothek eines Benutzers bietet. Weitere Informationen finden Sie unter Referenz zum Fotosatz.

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

Dies ist nicht der beste Weg, dies zu tun. Ich beantworte diese Frage für den Fall, dass ein anderer SO-Nutzer auf dasselbe Problem stößt.

Im Grunde musste ich die Videodatei in eine tmp-Datei spoolen, damit ich sie mit ASIHTTPFormDataRequest auf eine Website hochladen kann. Es gibt wahrscheinlich eine Möglichkeit, von der Asset-URL zum ASIHTTPFormDataRequest-Upload zu streamen, aber ich konnte es nicht herausfinden. Stattdessen habe ich die folgende Funktion geschrieben, um die Datei in eine tmp-Datei zu legen, um sie zu ASIHTTPFormDataRequest hinzuzufügen.

+(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

FYI: Sie lecken "Puffer". – randallmeadows

+0

Sie haben Recht, danke. –

+0

@RichDominelli, super Schnipsel! Vielen Dank!!! – Suran

22

Ich verwende die folgende Kategorie auf 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

Vielen Dank dafür! –

+0

Das ist was ich suche .. Danke @Zoul – fyasar

10

Dort gehen Sie ...

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

Sie können eine andere Preset-Taste verwenden, wenn Sie die neu zu encodieren Film (AVAssetExportPresetMediumQuality zum Beispiel)

+1

Ich habe nicht verstanden, wie hast du das Asset selbst bekommen? – Dejell

+0

Wahrscheinlich zu spät hier, aber Sie können ein ALAsset-Objekt von einer Referenz-URL instanziieren, indem Sie die Methode - [ALAssetLibrary assetForURL: resultBlock: failureBlock:] verwenden. – jpm

+0

Sollte akzeptiert werden antworten. Aber vergessen Sie nicht, exportAsynchronChromeWithCompletionHandler:^im Hauptthread zu versenden, da es standardmäßig im Hintergrund läuft. – faviomob

1

Hier ist die Objective C Lösung von Alonzo Antwort, Rahmen Fotos Mit

-(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

dieses von Zoul Antwort- dank

Similar Code in Xamarin C# 

Xamarin C# Equivalent

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