最近在学习使用iOS自带的API进行视频压缩,所以就从视频拍摄开始学起,因为曾经想直接对已有视频进行压缩,无奈总是失败,经研究发现不可以直接调用PC中的视频文件进行压缩,否则直接AVAssetExportSessionStatusFailed。所以只可以用真机测试并调用不iPhone中的视频。废话不多说,上代码:

使用UIImagePickerController即可完成视频的拍摄,并存入自定义的目录中

方法如下

- (IBAction)start:(id)sender
 {
     UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
     ipc.sourceType = UIImagePickerControllerSourceTypeCamera;//sourcetype有三种分别是camera,photoLibrary和photoAlbum
     NSArray *availableMedia = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];//Camera所支持的Media格式都有哪些,共有两个分别是@"public.image",@"public.movie"
     ipc.mediaTypes = [NSArray arrayWithObject:availableMedia[1]];//设置媒体类型为public.movie
     [self presentViewController:ipc animated:YES completion:nil];
     ipc.videoMaximumDuration = 30.0f;//30秒
     ipc.delegate = self;//设置委托
     [ipc release];
 }

关于上面提到的ipc.sourceType的三种取值,camera指的是调用相机进行拍摄,而photoLibrary指的是手机中的所有图片,photoAlbum指的是单纯指的是相册中的图片。其余的不做过多解释。

然后在如下委托方法中进行拍摄完毕的一些处理

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
 {
     sourceURL = [[info objectForKey:UIImagePickerControllerMediaURL] retain];
     
     fileLenLabel.text = [NSString stringWithFormat:@"%f s", [self getVideoLength:sourceURL]];//这个url为什么可以呢,因为这里必须这样
     fileSizeLabel.text = [NSString stringWithFormat:@"%f kb", [self getFileSize:[[sourceURL absoluteString] substringFromIndex:16]]];//文件并没有存储在sourceURL所指的地方,因为这里自己加上了所以要将这段字符串去掉,这个Label是测试时工程中用到的显示所拍摄文件大小的标签
     NSLog([[sourceURL absoluteString] substringFromIndex:16]);
     [self dismissViewControllerAnimated:YES completion:nil];
 }

好了,到这里就已经将拍摄好的视频存储在了sourceURL中。下面进行压缩处理

- (IBAction)convert:(id)sender
 {//转换时文件不能已存在,否则出错
     AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:sourceURL options:nil];
     NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
     if ([compatiblePresets containsObject:resultQuality]) {
         AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:resultQuality];
         NSDateFormatter *formater = [[NSDateFormatter alloc] init];//用时间给文件全名,以免重复,在测试的时候其实可以判断文件是否存在若存在,则删除,重新生成文件即可
         [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss"];
         resultPath = [[NSHomeDirectory() stringByAppendingFormat:@"/Documents/output-%@.mp4", [formater stringFromDate:[NSDate date]]] retain];
         NSLog(resultPath);
         [formater release];
         exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
         exportSession.outputFileType = AVFileTypeMPEG4;
         [exportSession exportAsynchronouslyWithCompletionHandler:^(void)
         {
             switch (exportSession.status) {
                 case AVAssetExportSessionStatusUnknown:
                     NSLog(@"AVAssetExportSessionStatusUnknown");
                     break;
                 case AVAssetExportSessionStatusWaiting:
                     NSLog(@"AVAssetExportSessionStatusWaiting");
                     break;
                 case AVAssetExportSessionStatusExporting:
                     NSLog(@"AVAssetExportSessionStatusExporting");
                     break;
                 case AVAssetExportSessionStatusCompleted:
                     NSLog(@"AVAssetExportSessionStatusCompleted");                     break;
                 case AVAssetExportSessionStatusFailed:
                     NSLog(@"AVAssetExportSessionStatusFailed");
                     break;
             }
             [exportSession release];
         }];
     }
 }

做几点说明,在视频拍摄的时候有个参数是来设置拍摄质量的,三种取值UIImagePickerControllerQualityTypeHigh,Medium,Low,但是经过测试发现这三个参数对拍摄效果并无多大影响,压缩的时候也有一个参数三个取值(针对iPhone的只有三个,还有针对其它设备的不同分辨率如640*480等,但是他们并不适用于iPhone,还有一些针对PC的)这三个取值分别是AVAssetExportPresetMediumQuality,Highest,Low,其中Highest与Medium自我感觉并多大差异,清晰度相当,压缩后的文件大小也几乎一样,但是Low要小的多,一分中的视频如果用Medium(或Highest)大小是5M多点,如果是Low则为600KB左右,但是Low要相对模糊许多。一般选取Medium即可。

这里再对如何获取文件的大小以及视频的时长做一点小解释

- (CGFloat) getFileSize:(NSString *)path
 {
     NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
     float filesize = -1.0;
     if ([fileManager fileExistsAtPath:path]) {
         NSDictionary *fileDic = [fileManager attributesOfItemAtPath:path error:nil];//获取文件的属性
         unsigned long long size = [[fileDic objectForKey:NSFileSize] longLongValue];
         filesize = 1.0*size/1024;
     }
     return filesize;
 }此方法可以获取文件的大小,返回的是单位是KB。 - (CGFloat) getVideoLength:(NSURL *)URL
 {
     NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
                                                      forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
     AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:URL options:opts];
     float second = 0;
     second = urlAsset.duration.value/urlAsset.duration.timescale;
     return second;
 }此方法可以获取视频文件的时长。