CGAffineTransform 视频旋转(转)
记录下视频旋转
//////////////////////////////////////////////
- (void)test:(NSURL *)url transformUrl:(NSURL *)exportUrl {
[self rotateVideoAssetWithFileURL:url dstFileURL:exportUrl];
} - (void)rotateVideoAssetWithFileURL:(NSURL *)fileURL dstFileURL:(NSURL *)dstFileURL { NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], AVURLAssetPreferPreciseDurationAndTimingKey, nil];
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:fileURL options:options]; AVAssetTrack *videoAssetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:];
AVAssetTrack *audioAssetTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:];
if (videoAssetTrack == nil || audioAssetTrack == nil) {
NSLog(@"error is %@", @"video or audio assetTrack is nil");
return;
} AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = videoAssetTrack.minFrameDuration;
CGSize renderSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width);
videoComposition.renderSize = renderSize; //create a video instruction
AVMutableVideoCompositionInstruction *videoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); AVMutableVideoCompositionLayerInstruction *videoCompositionLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoAssetTrack]; //仿射变换的坐标为iOS的屏幕坐标x向右为正y向下为正
CGAffineTransform transform = [self videoAssetTrackTransform:videoAssetTrack];
[videoCompositionLayerInstruction setTransform:transform atTime:kCMTimeZero]; //add the transformer layer instructions, then add to video composition
videoCompositionInstruction.layerInstructions = [NSArray arrayWithObject:videoCompositionLayerInstruction];
videoComposition.instructions = [NSArray arrayWithObject: videoCompositionInstruction]; AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
#warning when use (not AVAssetExportPresetPassthrough) AVAssetExportSession export video which is contain video and audio must add video track first,
#warning when add audio track frist error is -11841.
AVMutableCompositionTrack *videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error];
if (error) {
NSLog(@"error is %@", error);
return;
}
error = nil;
AVMutableCompositionTrack *audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:&error];
if (error) {
NSLog(@"error is %@", error);
return;
}
NSLog(@"the assetDuration is %lld", asset.duration.value/asset.duration.timescale); AVAssetExportSession *assetExportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality] ;
assetExportSession.shouldOptimizeForNetworkUse = YES;
assetExportSession.videoComposition = videoComposition;
assetExportSession.outputURL = dstFileURL;
assetExportSession.outputFileType = AVFileTypeMPEG4; __weak AVAssetExportSession *weakAssetExportSession = assetExportSession;
__weak typeof(self)weakSelf = self;
[assetExportSession exportAsynchronouslyWithCompletionHandler:^
{
if ([weakAssetExportSession status] != AVAssetExportSessionStatusCompleted) {
NSLog(@"the error is %@", [weakAssetExportSession error]);
NSLog(@"the status is %ld", (long)[weakAssetExportSession status]);
NSLog(@"the outPutPath is %@", [weakAssetExportSession.outputURL absoluteString]);
NSLog(@"the error is %@", [weakAssetExportSession error].userInfo);
}
dispatch_async(dispatch_get_main_queue(), ^{
#warning here can not use weakAssetExportSession.outputURL weakAssetExportSession.outputURL some time is null but video is exit.
[weakSelf exportDidFinish:dstFileURL];
});
}];
} - (CGAffineTransform)videoAssetTrackTransform:(AVAssetTrack *)videoAssetTrack {
int degrees = -;//[self degressFromVideoFileWithVideoAssetTrack:videoAssetTrack];
CGAffineTransform transform = CGAffineTransformIdentity;
if (degrees != ) {
CGAffineTransform translateToCenter = CGAffineTransformIdentity;
if (degrees == ) {
// 顺时针旋转90°
translateToCenter = CGAffineTransformMakeTranslation(videoAssetTrack.naturalSize.height, 0.0);
transform = CGAffineTransformRotate(translateToCenter, M_PI_2);
} else if(degrees == ){
// 顺时针旋转180°
translateToCenter = CGAffineTransformMakeTranslation(videoAssetTrack.naturalSize.width, videoAssetTrack.naturalSize.height);
transform = CGAffineTransformRotate(translateToCenter, M_PI);
} else if(degrees == ){
// 顺时针旋转270°
translateToCenter = CGAffineTransformMakeTranslation(0.0, videoAssetTrack.naturalSize.width);
transform = CGAffineTransformRotate(translateToCenter, M_PI_2 + M_PI);
}else if(degrees == -){
// 绕x轴旋转180度
//仿射变换的坐标为iOS的屏幕坐标x向右为正y向下为正
#if 1
// transform = CGAffineTransformTranslate(transform, videoAssetTrack.naturalSize.width, videoAssetTrack.naturalSize.height);
//transform = CGAffineTransformRotate(transform, 90/180.0f*M_PI); // 旋转90度
//transform = CGAffineTransformScale(transform, 1.0, -1.0); // 上下颠倒视频 // translateToCenter = CGAffineTransformMakeTranslation(videoAssetTrack.naturalSize.height, 0.0);
// transform = CGAffineTransformRotate(translateToCenter, -M_PI_2); transform = CGAffineTransformScale(transform, -1.0, 1.0); // 左右颠倒视频
transform = CGAffineTransformTranslate(transform, -videoAssetTrack.naturalSize.width, );
// transform = CGAffineTransformRotate(translateToCenter, -M_PI_2); //transform = CGAffineTransformScale(transform, 1.0, 1.0); // 使用原始大小 //原始视频
// ___
// | |
// | |
// -------------------- +x
// |
// |
// |
// |
// |
// |
// |
// +y //transform = CGAffineTransformScale(transform, 1.0, -1.0); // 上下颠倒视频 // -------------------- +x
// | | |
// | |___|
// |
// |
// |
// |
// |
// +y //transform = CGAffineTransformTranslate(transform, 0, -videoAssetTrack.naturalSize.height);// 将视频平移到原始位置 // ___
// | |
// | |
// -------------------- +x
// |
// |
// |
// |
// |
// |
// |
// +y // transform = CGAffineTransformScale(transform, 1.0, -1.0); // 上下颠倒视频
// transform = CGAffineTransformTranslate(transform, 0, -videoAssetTrack.naturalSize.height);
#else
transform = videoAssetTrack.preferredTransform;
transform = CGAffineTransformTranslate(transform, , -videoAssetTrack.naturalSize.height);
#endif
}
} #if 0 - cropVideo
//Here we shift the viewing square up to the TOP of the video so we only see the top
CGAffineTransform t1 = CGAffineTransformMakeTranslation(videoAssetTrack.naturalSize.height, ); //Use this code if you want the viewing square to be in the middle of the video
//CGAffineTransform t1 = CGAffineTransformMakeTranslation(videoAssetTrack.naturalSize.height, -(videoAssetTrack.naturalSize.width - videoAssetTrack.naturalSize.height) /2 ); //Make sure the square is portrait
transform = CGAffineTransformRotate(t1, M_PI_2);
#endif return transform;
} - (int)degressFromVideoFileWithVideoAssetTrack:(AVAssetTrack *)videoAssetTrack {
int degress = ;
CGAffineTransform t = videoAssetTrack.preferredTransform;
if(t.a == && t.b == 1.0 && t.c == -1.0 && t.d == ){
// Portrait
degress = ;
} else if(t.a == && t.b == -1.0 && t.c == 1.0 && t.d == ){
// PortraitUpsideDown
degress = ;
} else if(t.a == 1.0 && t.b == && t.c == && t.d == 1.0){
// LandscapeRight
degress = ;
} else if(t.a == -1.0 && t.b == && t.c == && t.d == -1.0){
// LandscapeLeft
degress = ;
} else if(t.a == -1.0 && t.b == && t.c == && t.d == -1.0){
// LandscapeLeft
degress = ;
} else if(t.a == 1.0 && t.b == && t.c == && t.d == -1.0){
// x-axis
degress = -;
} return degress;
} - (void)exportDidFinish:(NSURL *)fileURL {
NSLog(@"fileURL is %@", fileURL); dispatch_async(dispatch_get_main_queue(), ^{ if ([XCFileManager isExistsAtPath:[self.videoUrl path]]) { NSURL *outputURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"temp.mov"]]; [self convertVideoToLowQuailtyWithInputURL:fileURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.recordState = FMRecordStateFinish;
}); if (exportSession.status == AVAssetExportSessionStatusCompleted) { self.videoUrl = outputURL;
self.videoFirstImage = firstImage; }else {
printf("error\n");
}
}]; } }); }
转载:https://blog.csdn.net/jeffasd/article/details/51887064
CGAffineTransform 视频旋转(转)的更多相关文章
- Android WebRTC视频旋转问题
最近在对接WebRTC到安卓手机上,有个需求就是手机横屏时将对方图像进行旋转,研究了WebRTC video_render的代码后发现远端的视频渲染使用opengles20或surfaceview实现 ...
- CGAffineTransform 缩放 / 旋转 / 平移
CGAffineTransform此类是一个3*3矩阵的变换. - (void)transformImageView { CGAffineTransform t = CGAffineTransform ...
- CGAffineTransform函数旋转操作
本文转载至 http://blog.sina.com.cn/s/blog_923fdd9b0101ahyx.html 首先获取UITableView的CGAffineTransform函数:CG ...
- ffmpeg -视频旋转和高清转码示例
手头有一个竖屏拍摄的视频(真诚建议不要这么做..),导入到电脑上以后势必要把它旋转90°,可是没想到就这样简单的一个功能,尝试了N个非编软件(openshot, pitivi,还有坑爹的lives)后 ...
- FFMPEG 视频旋转设置
fmpeg -i inputfile.mp4 -vf "transpose=1" outputfile.mp4 0=90CounterCLockwise and Vertical ...
- ffmpeg实现视频的翻转与旋转(ffmpeg4.2.2)
一,ffmpeg的安装 请参见: https://www.cnblogs.com/architectforest/p/12807683.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址:ht ...
- FFmpeg滤镜实现区域视频增强 及 D3D实现视频播放区的拉大缩小
1.区域视频增强 FFmpeg滤镜功能十分强大,用滤镜可以实现视频的区域增强功能. 用eq滤镜就可以实现亮度.对比度.饱和度等的常用视频增强功能. 推荐两篇写得不错的博文: (1)ffmpeg综合应用 ...
- 视频处理控件TVideoGrabber如何重新编码视频
TVideoGrabber中可以对音频.视频剪辑进行重新编码剪辑,多的朋友知道这个功能更点,但是具体操作上还是不是很熟悉,这里总结一下,主要步骤如下: 1.通过指定开始和停止的时间,可以简单的剪辑视频 ...
- 代码记录:使用Aforge.net让视频图像反转180度
private void CameraConn() { videoSource = new VideoCaptureDevice(videoDevices[tscbxCameras.SelectedI ...
随机推荐
- 11.6NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 100 = 300\) 实际得分:\(100 +100 +100 = 300\) 学OI两年终于AK了一次qwq(虽然题目炒鸡水..) 纪念一下这令人激 ...
- 盒模型的属性丶display显示丶浮动
一丶盒模型的属性(重要) 1.padding padding是标准文档流,父子之间调整位置 <!DOCTYPE html> <html> <head> <me ...
- (转) AJAX POST&跨域 解决方案 - CORS
跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容),因为我们在日常的项目开发时会不可避免 ...
- python 面向对象 【进阶】
多态 多态跟python没有太大关系,因为python本身原生支持多态. def func(arg): #多态 print (arg) func(1) func(‘pand ...
- atom 常用配置
基本配置 setting 位于 File -> setting 显示HTML标签闭合的竖线 Setting -> Editor Setting -> 勾选 Show Indent G ...
- 关于实现XX系统设计时所实现的质量属性战术
可用性: 1)使用Try-catch对抛出的异常进行处理 2)使用Spring事务管理 易用性: 1)在类似删除相关选项时,弹出提示框,防止误操作 2)在不编辑基本信息时,对其进行折叠或者隐藏 3)提 ...
- JDBC事务和数据库事务嵌套的讨论 .
首先必须执行con.setAutoCommit(false)方法,将JDBC事务设置为手动提交,否则手动提交con.commit()无效,手动回滚con.rollback()引发SQLExceptio ...
- linux定时备份MySQL数据库并删除七天前的备份文件
1.创建备份文件夹 #cd /bak#mkdir mysqldata 2.编写运行脚本 #nano -w /usr/sbin/bakmysql.sh 注:如使用nano编辑此代码需在每行尾添加’&am ...
- 【Leetcode】【Easy】Reverse Linked List
题目: Reverse a singly linked list. 解题: 反转单链表,不再多介绍了. 如果会“先条件->定参数->确定不变式->验证后条件”的思维方法,一定会bug ...
- Grunt 使用(二)uglify插件压缩javascript代码
本文在配置grunt基本环境的基础下,讲解如何使用grunt-contrib-uglify进行javascript压缩 本文只介绍了grunt-contrib-uglify插件的一种压缩方式适用于大部 ...