iOS--相簿視訊MOV轉MP4
阿新 • • 發佈:2018-11-11
相簿視訊MOV轉MP4
最新做的一個功能涉及到了視訊的錄製、壓縮及上傳。
根據網上諸多大神的經驗,終於算是調通了,但也發現了一些問題,所以把我的經驗分享一下。
首先,肯定是呼叫一下系統的相機或相簿,
那麼匯入哪幾個庫 就不用我說了吧
開啟相簿獲取視訊PHAsset
TZImagePickerController 這個庫是個好東西
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:20 delegate:self]; imagePickerVc.allowPickingVideo = YES; imagePickerVc.allowPickingImage = NO; [self presentViewController:imagePickerVc animated:YES completion:nil];
從相簿獲取到視訊PHAsset之後
這時的 (PHAsset*)asset其實就是 AVURLAsset型別
-(void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(PHAsset *)asset{ /// 包含該視訊的基礎資訊 PHAssetResource * resource = [[PHAssetResource assetResourcesForAsset: asset] firstObject]; NSString *string1 = [resource.description stringByReplacingOccurrencesOfString:@"{" withString:@""]; NSString *string2 = [string1 stringByReplacingOccurrencesOfString:@"}" withString:@""]; NSString *string3 = [string2 stringByReplacingOccurrencesOfString:@", " withString:@","]; NSMutableArray *resourceArray = [NSMutableArray arrayWithArray:[string3 componentsSeparatedByString:@" "]]; [resourceArray removeObjectAtIndex:0]; [resourceArray removeObjectAtIndex:0]; for (NSInteger index = 0; index<resourceArray.count; index++) { NSString *string = resourceArray[index]; NSString *ret = [string stringByReplacingOccurrencesOfString:@" " withString:@""]; resourceArray[index] = ret; } NSMutableDictionary *videoInfo = [[NSMutableDictionary alloc] init]; for (NSString *string in resourceArray) { NSArray *array = [string componentsSeparatedByString:@"="]; videoInfo[array[0]] = array[1]; } NSLog(@"%@",videoInfo); PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; options.version = PHImageRequestOptionsVersionCurrent; options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; WS(weakSelf); PHImageManager *manager = [PHImageManager defaultManager]; [manager requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { StrongSelf(strongSelf); NSString *sizeString = videoInfo[@"size"]; NSArray *array = [sizeString componentsSeparatedByString:@","]; CGSize size = CGSizeMake([array[0] floatValue], [array[1] floatValue]); [strongSelf choseVedioCompeletWithVedioAsset:(AVURLAsset *)asset andAVAudioMix:audioMix andVedioInfo:info andImageSize:size]; }]; }
為了避免迴圈引用,這裡另寫方法呼叫轉碼
- (void)choseVedioCompeletWithVedioAsset:(AVURLAsset *)urlAsset andAVAudioMix:(AVAudioMix *)audioMix andVedioInfo:(NSDictionary *)vedioInfo andImageSize:(CGSize)size{ //[self showLoadingView:@"處理視訊資料"]; WS(weakSelf); [RecordTools convertMovToMp4FromAVURLAsset:urlAsset andCompeleteHandler:^(NSURL * _Nonnull fileUrl) { StrongSelf(strongSelf); [strongSelf hideLoadingView]; [strongSelf addVideoToTableCompeletWithVedioAsset:urlAsset andAVAudioMix:audioMix andVedioInfo:vedioInfo andImageSize:size andMP4FileUrl:fileUrl]; }]; }
檢查視訊檔案的合規性
//30*1024*1024 B 位元組
#define VideoSizeMax 31457280
- (void)addVideoToTableCompeletWithVedioAsset:(AVURLAsset *)urlAsset
andAVAudioMix:(AVAudioMix *)audioMix
andVedioInfo:(NSDictionary *)vedioInfo
andImageSize:(CGSize)size
andMP4FileUrl:(NSURL *)MP4FileUrl{
if (MP4FileUrl == nil || MP4FileUrl.path == nil) {
showMsg(@"視訊獲取失敗");
return;
}
AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset];
generator.appliesPreferredTrackTransform = YES;
generator.maximumSize = CGSizeMake(size.width, size.height);
NSError *error = nil;
CGImageRef img = [generator copyCGImageAtTime:CMTimeMake(0, 10) actualTime:NULL error:&error];
UIImage *image = [UIImage imageWithCGImage:img];
NSError *mp4Rrror = nil;
// 檢查檔案屬性 檢視檔案大小 是否超標
NSDictionary *infoDict = [[NSFileManager defaultManager]attributesOfItemAtPath:MP4FileUrl.path error:&mp4Rrror];
NSString *fileSizeString = infoDict[@"NSFileSize"];
if (fileSizeString && !error) {
NSInteger fileSize = fileSizeString.integerValue;
if (fileSize>VideoSizeMax) {
showMsg(@"視訊最大不能超過30M");
[[NSFileManager defaultManager] removeItemAtPath:MP4FileUrl.path error:&error];
return;
}
}
else{
showMsg(@"視訊獲取失敗");
[[NSFileManager defaultManager] removeItemAtPath:MP4FileUrl.path error:&error];
return;
}
// 你們不需要
// if (self.lastSelectPath) {
// [self.dataArray replaceObjectAtIndex:self.lastSelectPath.row
// withObject:@{@"type":@"vedio",
// @"value":MP4FileUrl,
// @"image":image}];
// }
// else{
// [self.dataArray addObject:@{@"type":@"vedio",
// @"value":MP4FileUrl,
// @"image":image}];
// }
//
// dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
//
// dispatch_async(dispatch_get_main_queue(), ^{
//
// [self.mainTableView reloadData];
// });
//
// });
}
MOV轉碼MP4
+ (void)convertMovToMp4FromAVURLAsset:(AVURLAsset*)urlAsset andCompeleteHandler:(void(^)(NSURL *fileUrl))fileUrlHandler{
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:urlAsset.URL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
// 在Documents目錄下建立一個名為FileData的資料夾
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"Cache/VideoData"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = FALSE;
BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
if(!(isDirExist && isDir)) {
BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
if(!bCreateDir){
NSLog(@"建立資料夾失敗!%@",path);
}
NSLog(@"建立資料夾成功,檔案路徑%@",path);
}
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
[formatter setDateFormat:@"yyyy_MM_dd_HH_mm_ss"]; //每次啟動後都儲存一個新的日誌檔案中
NSString *dateStr = [formatter stringFromDate:[NSDate date]];
NSString *resultPath = [path stringByAppendingFormat:@"/%@.mp4",dateStr];
NSLog(@"file path:%@",resultPath);
NSLog(@"resultPath = %@",resultPath);
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset
presetName:AVAssetExportPresetMediumQuality];
exportSession.outputURL = [NSURL fileURLWithPath:resultPath];
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
switch (exportSession.status) {
case AVAssetExportSessionStatusUnknown:
NSLog(@"AVAssetExportSessionStatusUnknown");
fileUrlHandler(nil);
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"AVAssetExportSessionStatusWaiting");
fileUrlHandler(nil);
break;
case AVAssetExportSessionStatusExporting:
NSLog(@"AVAssetExportSessionStatusExporting");
fileUrlHandler(nil);
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"AVAssetExportSessionStatusCompleted");
fileUrlHandler(exportSession.outputURL);
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"AVAssetExportSessionStatusFailed");
fileUrlHandler(nil);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"AVAssetExportSessionStatusCancelled");
fileUrlHandler(nil);
break;
}
}];
}
}
請注意
上段程式碼請不要在模擬器上執行,哪怕你模擬器相簿匯入了視訊也不要,因為
[AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
沒反應!!!!
這句話是其他帖子沒寫過的,可能他們沒有在模擬器執行過,模擬器是可以匯入視訊和圖片的,直接拖進去就OK。