iOS 视频旋转及平移详解
来源:互联网 发布:java中的mvc模式 编辑:程序博客网 时间:2024/06/06 04:51
//必须是fileURL//截取将会是视频的中间部分//这里假设拍摄出来的视频总是高大于宽的/*! @method mergeAndExportVideosAtFileURLs: @param fileURLArray 包含所有视频分段的文件URL数组,必须是[NSURL fileURLWithString:...]得到的 @discussion 将所有分段视频合成为一段完整视频,并且裁剪为正方形 */#if 1- (void)mergeAndExportVideosAtFileURLs:(NSArray *)fileURLArray{ // NSLog(@"the getVideoCount is %lu", (unsigned long)[self getVideoCount]); // if (self.getVideoCount != fileURLArray.count) {// NSLog(@"必定崩溃-------");// NSLog(@"必定崩溃-------");// NSLog(@"必定崩溃-------");// } NSLog(@"the fileURLArray is %@", fileURLArray); if (fileURLArray.count <= 0) { #warning 小片段视频还未成功生成就开始 合并 视频 NSLog(@"严重错误!!!!!!!!!!!!!!!!!!!!!"); return; }else{ for (NSURL *fileURL in fileURLArray) { NSString *path = fileURL.resourceSpecifier; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { JFLog(DBGUI, @"mergeAndExportVideosAtFileURLs theVideoPath is %@", path); NSUInteger size; NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; size = [attr[NSFileSize] unsignedIntegerValue]; JFLog(DBGUI, @"mergeAndExportVideosAtFileURLs fileSize is %lu", size/(1024*1024)); } } } dispatch_async(_serialQueue, ^{ // dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSError *error = nil; CGSize renderSize = CGSizeMake(0, 0); NSMutableArray *layerInstructionArray = [[NSMutableArray alloc] init]; AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; CMTime totalDuration = kCMTimeZero; //先去assetTrack 也为了取renderSize NSMutableArray *assetTrackArray = [[NSMutableArray alloc] init]; NSMutableArray *assetAudioTrackArray = [NSMutableArray arrayWithCapacity:0]; NSMutableArray *assetArray = [[NSMutableArray alloc] init]; for (NSURL *fileURL in fileURLArray) { AVAsset *asset = [AVAsset assetWithURL:fileURL]; // AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; // NSString *tracksKey = @"tracks"; NSString *tracksKey = @"AVMediaTypeAudio"; if (!asset) { continue; } [assetArray addObject:asset]; AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; [assetTrackArray addObject:assetTrack]; // AVAssetTrack *assetAudioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; // [assetAudioTrackArray addObject:assetAudioTrack]; renderSize.width = MAX(renderSize.width, assetTrack.naturalSize.height); renderSize.height = MAX(renderSize.height, assetTrack.naturalSize.width); } NSLog(@"the assetAudioTrackArray is %@", assetAudioTrackArray); CGFloat renderW = MIN(renderSize.width, renderSize.height); NSLog(@"the renderW is %f", renderW); NSLog(@"the assetArray cout is %lu", (unsigned long)[assetArray count]); NSLog(@"the assetTrackArray cout is %lu", (unsigned long)[assetTrackArray count]); for (int i = 0; i < [assetArray count] && i < [assetTrackArray count]; i++) { AVAsset *asset = [assetArray objectAtIndex:i]; AVAssetTrack *assetTrack = [assetTrackArray objectAtIndex:i]; // AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; // [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) // ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] // atTime:totalDuration // error:nil]; #warning 这里加一个判断 //[asset tracksWithMediaType:AVMediaTypeAudio]取出的数组可能为空 这段视频没有音频 NSArray *arr = [asset tracksWithMediaType:AVMediaTypeAudio]; JFLog(DBGUI, @"the audioTrackArr is %@", arr); if (arr.count <= 0) { NSLog(@"没有视频!!!!!!!!!!!!!!!!!!!!!"); NSLog(@"没有视频!!!!!!!!!!!!!!!!!!!!!"); } if (arr.count > 0) { AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:[arr objectAtIndex:0] atTime:totalDuration error:nil]; } // [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:([arr count]>0)?[arr objectAtIndex:0]:nil atTime:totalDuration error:nil]; AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; NSLog(@"the assetduration is %lld", asset.duration.value/asset.duration.timescale); [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:assetTrack atTime:totalDuration error:&error]; //fix orientationissue AVMutableVideoCompositionLayerInstruction *layerInstruciton = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; totalDuration = CMTimeAdd(totalDuration, asset.duration); CGFloat rate; NSLog(@"the renderW is %f", renderW); NSLog(@"assetTrack.naturalSize.width is %f", assetTrack.naturalSize.width); NSLog(@"assetTrack.naturalSize.height is %f", assetTrack.naturalSize.height); rate = renderW / MIN(assetTrack.naturalSize.width, assetTrack.naturalSize.height); NSLog(@"the rate is %f", rate); NSLog(@" preferredTransform.a is %f", assetTrack.preferredTransform.a); NSLog(@" preferredTransform.b is %f", assetTrack.preferredTransform.b); NSLog(@" preferredTransform.c is %f", assetTrack.preferredTransform.c); NSLog(@" preferredTransform.d is %f", assetTrack.preferredTransform.d); NSLog(@" preferredTransform.tx is %f", assetTrack.preferredTransform.tx); NSLog(@" preferredTransform.ty is %f", assetTrack.preferredTransform.ty); CGAffineTransform translateToCenter; CGAffineTransform mixedTransform; // AVMutableVideoComposition *waterMarkVideoComposition = [AVMutableVideoComposition videoComposition];// waterMarkVideoComposition.frameDuration = CMTimeMake(1, 30); int degrees = [self degressFromVideoFileWithURL:assetTrack]; // degrees = 180; if (degrees == 0) { // AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality];// session.outputURL = outputURL;// session.outputFileType = AVFileTypeQuickTimeMovie; }else{ if(degrees == 90){ //顺时针旋转90° NSLog(@"视频旋转90度,home按键在左"); translateToCenter = CGAffineTransformMakeTranslation(assetTrack.naturalSize.height, 0.0);// mixedTransform = CGAffineTransformRotate(translateToCenter,0); mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);// videoTrack.renderSize = CGSizeMake(assetTrack.naturalSize.height,assetTrack.naturalSize.width); }else if(degrees == 180){ //顺时针旋转180° NSLog(@"视频旋转180度,home按键在上"); translateToCenter = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, assetTrack.naturalSize.height); mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);// waterMarkVideoComposition.renderSize = CGSizeMake(assetTrack.naturalSize.width,assetTrack.naturalSize.height); }else if(degrees == 270){ //顺时针旋转270° NSLog(@"视频旋转270度,home按键在右"); translateToCenter = CGAffineTransformMakeTranslation(0.0, assetTrack.naturalSize.width); mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);// waterMarkVideoComposition.renderSize = CGSizeMake(assetTrack.naturalSize.height,assetTrack.naturalSize.width); } } CGAffineTransform preferredTransform = assetTrack.preferredTransform; CGAffineTransform trans = CGAffineTransformTranslate(preferredTransform, 0.0, -assetTrack.naturalSize.height); CGAffineTransform transNew = CGAffineTransformRotate(preferredTransform,M_PI_2*3); transNew = CGAffineTransformTranslate(transNew, 0, -(assetTrack.naturalSize.width - assetTrack.naturalSize.height) / 2.0); transNew = CGAffineTransformConcat(trans, transNew); transNew = CGAffineTransformScale(transNew, rate, rate);//放缩,解决前后摄像结果大小不对称 // CGAffineTransform layerTransform = CGAffineTransformMake(assetTrack.preferredTransform.a, assetTrack.preferredTransform.b, assetTrack.preferredTransform.c, assetTrack.preferredTransform.d, assetTrack.preferredTransform.tx * rate, assetTrack.preferredTransform.ty * rate); // layerTransform = (a = 0, b = 1, c = -1, d = 0, tx = 1080, ty = 0) CGAffineTransform layerTransform = CGAffineTransformMake(assetTrack.preferredTransform.a, assetTrack.preferredTransform.b, assetTrack.preferredTransform.c, assetTrack.preferredTransform.d, assetTrack.naturalSize.height * rate, assetTrack.preferredTransform.ty * rate);//// layerTransform = CGAffineTransformConcat(layerTransform, CGAffineTransformMake(1, 0, 0, 1, 0, -(assetTrack.naturalSize.width - assetTrack.naturalSize.height) / 2.0));//向上移动取中部影响////// layerTransform = CGAffineTransformScale(layerTransform, rate, rate);//放缩,解决前后摄像结果大小不对称 // [layerInstruciton setTransform:layerTransform atTime:kCMTimeZero];// [layerInstruciton setOpacity:0.0 atTime:totalDuration]; [layerInstruciton setTransform:transNew atTime:kCMTimeZero]; // [layerInstruciton setTransform:mixedTransform atTime:kCMTimeZero]; // [layerInstruciton setTransform:assetTrack.preferredTransform atTime:kCMTimeZero]; //data [layerInstructionArray addObject:layerInstruciton]; } //get save path NSURL *mergeFileURL = [NSURL fileURLWithPath:[[self class] getVideoMergeFilePathString]]; //export AVMutableVideoCompositionInstruction *mainInstruciton = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; mainInstruciton.timeRange = CMTimeRangeMake(kCMTimeZero, totalDuration); mainInstruciton.layerInstructions = layerInstructionArray; AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition]; mainCompositionInst.instructions = @[mainInstruciton]; mainCompositionInst.frameDuration = CMTimeMake(1, 30); // mainCompositionInst.frameDuration = CMTimeMake(1, 24); NSLog(@"the renderSize is %@", NSStringFromCGSize(CGSizeMake(renderW, renderW))); mainCompositionInst.renderSize = CGSizeMake(renderW, renderW); AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality]; exporter.videoComposition = mainCompositionInst; exporter.outputURL = mergeFileURL; exporter.outputFileType = AVFileTypeMPEG4; exporter.shouldOptimizeForNetworkUse = YES; [exporter exportAsynchronouslyWithCompletionHandler:^{ if ([exporter status] != AVAssetExportSessionStatusCompleted) { NSLog(@"the status is %ld", (long)[exporter status]); NSLog(@"the outPutPath is %@", [exporter.outputURL absoluteString]); NSLog(@"the error is %@", [exporter error].userInfo); NSLog(@"the error is %@", [exporter error]); } if ([exporter status] == AVAssetExportSessionStatusFailed) { if (DEBUG) { NSLog(@"error "); } } NSString *path = mergeFileURL.resourceSpecifier; // NSString *pa1 = outputFileURL.absoluteString; // NSString *pa2 = outputFileURL.resourceSpecifier; // NSString *pa3 = outputFileURL.scheme; // NSString *pa4 = outputFileURL.relativePath; NSLog(@"theVideoPath is %@", path); NSLog(@"outputFileURL is %@", mergeFileURL); if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { NSLog(@"theVideoPath is %@", path); NSUInteger size; NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil]; size = [attr[NSFileSize] unsignedIntegerValue]; NSLog(@"didFinishRecordingToOutputFileAtURL fileSize is %lu", size/(1024*1024)); } NSLog(@"the outputFile is %@", mergeFileURL); dispatch_async(dispatch_get_main_queue(), ^{ MSPreViewController *VC = [MSPreViewController new]; VC.videoURL = mergeFileURL; NSLog(@"navi is %@", self.navigationController); [self.navigationController pushViewController:VC animated:YES]; }); // return; // dispatch_async(dispatch_get_main_queue(), ^{// if ([_delegate respondsToSelector:@selector(videoRecorder:didFinishMergingVideosToOutPutFileAtURL:)]) {// [_delegate videoRecorder:self didFinishMergingVideosToOutPutFileAtURL:mergeFileURL];// }// }); }]; });}#endif
0 0
- iOS 视频旋转及平移详解
- iOS开发:旋转、缩放、平移
- IOS学习 Core-Animation旋转和平移
- IOS CGAffineTransform视图平移,放缩,旋转
- IOS UIImageView的旋转平移缩放
- ios如何旋转,缩放,平移控件
- IOS CGAffineTransform 用于视图平移,缩放,旋转
- ios-矩阵旋转缩放平移操作
- iOS transform(平移、旋转、缩放)
- IOS 改变图形上下文中的形状:平移、缩放、旋转
- IOS 改变图形上下文中的形状:平移、缩放、旋转
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- ios中的各中动画(旋转,平移)
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- IOS CGAffineTransform 用于视图平移,放缩,旋转
- Android JNI作用及其详解
- 适用于网站的谷歌分析(analytics.js)
- PDF解密器下载和使用
- mysql自增ID默认时间
- oracle
- iOS 视频旋转及平移详解
- 实例讲解js中的预编译
- 在Mac下配置:Apache+php+MySql
- IOS中消息传递的8种方式
- 合并流
- java String字符串
- 数据结构和算法系列 - 八大排序算法
- 可以滑动的视频播放器(VideoView)
- 接入httpDNS