相簿視訊轉碼MP4格式 iOS
阿新 • • 發佈:2021-09-06
本地已轉碼時,直接上傳;本地無轉碼時,先轉碼再上傳
/// 視訊處理通過本地沙盒檔案路徑判斷此視訊檔案是否已經轉碼 /// @param asset 視訊資源 /// @param callBack 回撥 - (void)dealWithVidioAsset:(PHAsset *)asset callBack:(void (^)(NSString *))callBack { /// 轉碼操作 PHImageManager *manager = [PHImageManager defaultManager]; [manager requestAVAssetForVideo:asset options:nil resultHandler:^(AVAsset * _Nullable aVsset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { ///判斷此視訊是否已經轉碼 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingFormat:@"/VideoCacheData/%@.mp4",[((AVURLAsset*)aVsset).URL.path MD5String]]; NSFileManager*fileManager = [NSFileManager defaultManager]; BOOL isDirExist = [fileManager fileExistsAtPath:path]; if (isDirExist) { // 已經轉碼成功 直接上傳 [self uploadMpa4WithUrl:[NSURL URLWithString:path] callBack:^(NSString *str) { if (callBack) { callBack(str); } }];return; } [self convertMovToMp4FromAVURLAsset:(AVURLAsset*)aVsset andCompeleteHandler:^(NSURL *fileUrl) { if (!fileUrl) { [HUDManager hideHUDView]; [self.view showMessageWithText:@"上傳錯誤請重試!"]; self.navigationItem.rightBarButtonItem.enabled = YES; }else { [self uploadMpa4WithUrl:fileUrl callBack:^(NSString *str) { if (callBack) { callBack(str); } }]; } }]; }]; }
轉碼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:@"VideoCacheData"]; 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); } /// 檔名為本地相簿路徑的Md5 NSString *resultPath = [path stringByAppendingFormat:@"/%@.mp4",[urlAsset.URL.path MD5String]]; 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.videoComposition = [self getVideoComposition:avAsset]; //修正某些播放器不識別視訊Rotation的問題 [exportSession exportAsynchronouslyWithCompletionHandler:^(void) { dispatch_async(dispatch_get_main_queue(), ^{ 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; } }); }]; } }
修正視訊位置
/// 修正位置資訊 - (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset { AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; AVMutableComposition *composition = [AVMutableComposition composition]; AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; CGSize videoSize = videoTrack.naturalSize; BOOL isPortrait_ = [self isVideoPortrait:asset]; if(isPortrait_) { videoSize = CGSizeMake(videoSize.height, videoSize.width); } composition.naturalSize = videoSize; videoComposition.renderSize = videoSize; videoComposition.frameDuration = CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600); AVMutableCompositionTrack *compositionVideoTrack; compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil]; AVMutableVideoCompositionLayerInstruction *layerInst; layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; [layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero]; AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); inst.layerInstructions = [NSArray arrayWithObject:layerInst]; videoComposition.instructions = [NSArray arrayWithObject:inst]; return videoComposition; } - (BOOL) isVideoPortrait:(AVAsset *)asset { BOOL isPortrait = NO; NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; if([tracks count] > 0) { AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; CGAffineTransform t = videoTrack.preferredTransform; // Portrait if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0) { isPortrait = YES; } // PortraitUpsideDown if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0) { isPortrait = YES; } // LandscapeRight if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0) { isPortrait = NO; } // LandscapeLeft if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0) { isPortrait = NO; } } return isPortrait; }在北京的燈中,有一盞是我家的。這個夢何時可以實現?哪怕微微亮。北京就像魔鬼訓練營,有能力的留,沒能力的走……