记录下视频旋转

//////////////////////////////////////////////
- (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 视频旋转(转)的更多相关文章

  1. Android WebRTC视频旋转问题

    最近在对接WebRTC到安卓手机上,有个需求就是手机横屏时将对方图像进行旋转,研究了WebRTC video_render的代码后发现远端的视频渲染使用opengles20或surfaceview实现 ...

  2. CGAffineTransform 缩放 / 旋转 / 平移

    CGAffineTransform此类是一个3*3矩阵的变换. - (void)transformImageView { CGAffineTransform t = CGAffineTransform ...

  3. CGAffineTransform函数旋转操作

    本文转载至  http://blog.sina.com.cn/s/blog_923fdd9b0101ahyx.html   首先获取UITableView的CGAffineTransform函数:CG ...

  4. ffmpeg -视频旋转和高清转码示例

    手头有一个竖屏拍摄的视频(真诚建议不要这么做..),导入到电脑上以后势必要把它旋转90°,可是没想到就这样简单的一个功能,尝试了N个非编软件(openshot, pitivi,还有坑爹的lives)后 ...

  5. FFMPEG 视频旋转设置

    fmpeg -i inputfile.mp4 -vf "transpose=1" outputfile.mp4 0=90CounterCLockwise and Vertical ...

  6. ffmpeg实现视频的翻转与旋转(ffmpeg4.2.2)

    一,ffmpeg的安装 请参见: https://www.cnblogs.com/architectforest/p/12807683.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址:ht ...

  7. FFmpeg滤镜实现区域视频增强 及 D3D实现视频播放区的拉大缩小

    1.区域视频增强 FFmpeg滤镜功能十分强大,用滤镜可以实现视频的区域增强功能. 用eq滤镜就可以实现亮度.对比度.饱和度等的常用视频增强功能. 推荐两篇写得不错的博文: (1)ffmpeg综合应用 ...

  8. 视频处理控件TVideoGrabber如何重新编码视频

    TVideoGrabber中可以对音频.视频剪辑进行重新编码剪辑,多的朋友知道这个功能更点,但是具体操作上还是不是很熟悉,这里总结一下,主要步骤如下: 1.通过指定开始和停止的时间,可以简单的剪辑视频 ...

  9. 代码记录:使用Aforge.net让视频图像反转180度

    private void CameraConn() { videoSource = new VideoCaptureDevice(videoDevices[tscbxCameras.SelectedI ...

随机推荐

  1. 移动端适配(3)——rem适配

    rem适配 <meta name="viewport"  content="width=device-width,user-scalable=no"/&g ...

  2. MySQL库表详细操作

    昨天我们初始了MySQL,今天我们先从库表方面详细说一下具体操作 一.库操作 1.创建数据库 1.1 语法 CREATE DATABASE 数据库名 charset utf8; 1.2 数据库命名规则 ...

  3. Spring中无法访问resources目录下页面或静态资源

    1.新建项目,在 resources 目录下创建 views 目录,在 views 目录下创建 index.html 页面,项目跑起来,浏览器访问页面,提示找不到页面之类的错误提示. 2.再尝试访问图 ...

  4. kafka leader平衡策略

    1.1个partition的默认leader是replicas中的第一个replica 2.kafka controller会启动一个定时的check线程,kafka默认是5min周期,mafka是3 ...

  5. 【JAVA语法】04Java-多态性

    多态性 instanceof 关键字 接口的应用 一.多态性 1.多态性的体现: 方法的重载和重写 对象的多态性 2.对象的多态性: 向上转型: 程序会自动完成 父类 父类对象 = 子类实例 向下转型 ...

  6. WPF控件相对位置解析

    WPF控件相对位置的获取方法是比较简单的.对于初学者来说,掌握这一技巧的应用,可以帮助以后对WPF的深入学习,而且在实际使用中,这是一个非常常用的方法. 我们知道WPF有着比较灵活的布局方式,关于某个 ...

  7. ARC以及MRC中setter方法的差异

    ARC以及MRC中setter方法的差异 有时候,你会需要重写setter或者getter方法,你知道么,ARC与MRC的setter方法是有着差异的呢. 先看下MRC下的setter方法: 在看下A ...

  8. python 中的list&tuple

    list Python内置的一种数据类型是列表:list>>> classmates = ['Michael', 'Bob', 'Tracy']>>> classm ...

  9. July 18th 2017 Week 29th Tuesday

    My heart is stronger now that you are in it. 我的心里有了你,从此变得更强大. You will no longer feel lonely if ther ...

  10. SAP S/4HANA extensibility扩展原理介绍

    SAP产品总的extensibility扩展原理介绍: 看Jerry这篇文章. SAP Cloud for Customer Extensibility的设计与实现 我的同事Boris写的. 而本文是 ...