iOS視訊拍攝與壓縮
最近在學習使用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
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;
}此方法可以獲取視訊檔案的時長。