2010-12-28 3 views
12

Использование новой инфраструктуры библиотеки ресурсов, доступной в iOS 4, я вижу, что я могу получить URL для данного видео с помощью UIImagePickerControllerReferenceURL. URL вернулся в следующем формате:Получение видео от ALAsset

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

Я пытаюсь загрузить видео на сайт, так как быстрое доказательство концепции я пытаюсь следующий

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

данных никогда не инициализируется в Это дело. Кто-нибудь смог получить доступ к URL прямо через новую библиотеку активов? Спасибо за вашу помощь.

+0

Я попробовал вариант, предложенный Rich, но не работает. Я использую то же видео, которое хранится в библиотеке iPhone для моего теста, а иногда возвращаемый словарь информации содержит только UIImagePickerControllerReferenceURL. Я попытался использовать этот URL как вход для videoAssetURLToTempFile, но при выполнении этого метода не вводится код для обновления блока результатов. Невозможно определить, при каких обстоятельствах метод делегата UIImagePickerController didFinishPickingMediaWithInfo работает правильно. Помогите пожалуйста? Заранее благодарен! –

+0

Возможно ли, что это проблема с версией iOS? UIImagePickerControllerReferenceURL - это старый метод возврата данных. –

ответ

9

Вот чистое быстрое решение для получения видеороликов s NSData. Он использует фото рамка, как ALAssetLibrary нежелательна из iOS9:

ВАЖЕН

Структуры активов Библиотеки нежелательна из прошивки 9.0. Вместо этого вместо этого используйте структуру Photos, которая в iOS 8.0 и более поздних версиях предоставляет больше возможностей и лучшую производительность для работы с библиотекой фотографий пользователя. Дополнительные сведения см. В разделе «Справочник по фотографиям».

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

Это не лучший способ сделать это. Я отвечаю на этот вопрос, если другой пользователь SO сталкивается с той же проблемой.

В основном моя потребность состояла в том, чтобы иметь возможность подключать видеофайл к файлу tmp, чтобы я мог загрузить его на сайт с помощью ASIHTTPFormDataRequest. Вероятно, есть способ потоковой передачи от URL-адреса актива к загрузке ASIHTTPFormDataRequest, но я не мог понять это. Вместо этого я написал следующую функцию, чтобы отбросить файл в файл tmp для добавления в 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

FYI: Вы пропускаете «буфер». – randallmeadows

+0

Вы правы, спасибо. –

+0

@RichDominelli, потрясающий сниппет! Спасибо!!! – Suran

22

Я использую следующую категорию на 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

Спасибо за это! –

+0

Это то, что я ищу .. Спасибо @zoul – fyasar

10

Там вы идете ...

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

Вы можете использовать другой предустановленный ключ, если вы хотите, чтобы повторно закодировать фильм (AVAssetExportPresetMediumQuality например)

+1

Я не понимал, как вы получили свой актив? – Dejell

+0

Возможно, слишком поздно здесь, но вы можете создать объект ALAsset из ссылочного URL-адреса, используя метод [ALAssetLibrary assetForURL: resultBlock: failureBlock:]. – jpm

+0

Должен быть принят ответ. Но не забудьте отправить exportAsynchronouslyWithCompletionHandler:^в основном потоке, потому что он работает в фоновом режиме по умолчанию. – faviomob

1

Вот Objective C решения Алонзо ответа, используя фотографии Рамочного

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

это от Ответа Zoul в благодаря

Similar Code in Xamarin C# 

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