Getting video from ALAsset

前端 未结 6 1639
野趣味
野趣味 2020-12-01 03:06

Using the new asset library framework available in iOS 4 i see that I can get the url for a given video using the UIImagePickerControllerReferenceURL. The url returned is in

相关标签:
6条回答
  • 2020-12-01 03:37

    This is not the best way to do this. I am answering this question in case another SO user comes across the same issue.

    Basically my need was to be able to spool the video file to a tmp file so I can upload it to a website using ASIHTTPFormDataRequest. There is probably a way of streaming from the asset url to the ASIHTTPFormDataRequest upload but I could not figure it out. Instead I wrote the following function to drop the file to a tmp file to add to 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 讨论(0)
  • Here is the Objective C solution of 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;
        }
    
    0 讨论(0)
  • 2020-12-01 03:38

    There you go...

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

    You can use a different preset key if you wish to re-encode the movie (AVAssetExportPresetMediumQuality for example)

    0 讨论(0)
  • 2020-12-01 03:52

    Here is a clean swift solution to get videos as NSData. It uses the Photos framework as ALAssetLibrary is deprecated as of iOS9:

    IMPORTANT

    The Assets Library framework is deprecated as of iOS 9.0. Instead, use the Photos framework instead, which in iOS 8.0 and later provides more features and better performance for working with a user’s photo library. For more information, see Photos Framework Reference.

    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")
                        }
                    }
                })
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 04:02

    this from Zoul's Answer thanks

    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);
    
    0 讨论(0)
  • 2020-12-01 04:04

    I use the following category on 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)
提交回复
热议问题