【问题标题】:Getting video from ALAsset从 ALAsset 获取视频
【发布时间】:2011-05-31 13:35:16
【问题描述】:

使用 iOS 4 中可用的新资产库框架,我发现我可以使用 UIImagePickerControllerReferenceURL 获取给定视频的 url。返回的url格式如下:

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

我正在尝试将此视频上传到网站,以便快速验证概念,我正在尝试以下操作

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

在这种情况下,数据永远不会被初始化。有没有人设法通过新的资产库直接访问 url?感谢您的帮助。

【问题讨论】:

  • 我尝试了 Rich 提出的选项,但不起作用。我使用 iPhone 库中存储的相同视频进行测试,有时返回的信息字典仅包含 UIImagePickerControllerReferenceURL。我尝试使用该 URL 作为 videoAssetURLToTempFile 的输入,但是在执行该方法时没有输入代码来更新结果块。我无法确定 UIImagePickerController didFinishPickingMediaWithInfo 委托方法在哪些情况下可以正常工作。请帮忙?提前致谢!
  • 这可能是iOS版本的问题吗? UIImagePickerControllerReferenceURL 是旧的返回数据的方法。

标签: iphone alassetslibrary alasset


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是 Alonzo 答案的 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;
        }
    

    【讨论】:

      【解决方案3】:

      这是一个干净的快速解决方案,可以将视频作为 NSData 获取。 它使用 Photos 框架,因为 ALAssetLibrary 自 iOS9 起已弃用:

      重要

      自 iOS 9.0 起,Assets Library 框架已被弃用。相反,请改用 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")
                          }
                      }
                  })
              }
          }
      }
      

      【讨论】:

      • 谢谢你!被这个问题困扰了很久。
      【解决方案4】:

      你去...

      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

      【讨论】:

      • 我不明白您是如何获得资产本身的?
      • 这里可能为时已晚,但您可以使用 -[ALAssetLibraryassetForURL:resultBlock:failureBlock:] 方法从引用 URL 实例化 ALAsset 对象。
      • 应该被接受的答案。但是不要忘记在主线程中调度 exportAsynchronouslyWithCompletionHandler:^,因为它默认在后台运行。
      • 有没有办法用 PHAsset 做到这一点? ALAsset api 在 iOS9 中已弃用
      【解决方案5】:

      我在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
      

      【讨论】:

      • 这就是我要找的......谢谢@zoul
      【解决方案6】:

      这不是最好的方法。我正在回答这个问题,以防其他 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;
      }
      

      【讨论】:

      • 仅供参考:您正在泄漏“缓冲区”。
      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多