1. 程式人生 > >iOS視訊拍攝與壓縮

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

", [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;
}此方法可以獲取視訊檔案的時長。