分析需求

我们先看一看微信的界面

微信效果图

1.页面下部拖动左边和右边的白色竖条控制剪切视频的开始和结束时间,预览界面跟随拖动位置跳到视频相应帧画面,控制视频长度最长15秒,最短5秒

2.拖动下部图片预览条,视频预览画面跳转到左边白条停留处的帧画面

3.下部操作区域拖动操作时,视频暂停,松手后视频播放,播放内容为两个白条之间的内容,可以循环播放

4.界面的“取消”返回,“确定”后裁剪视频输出

先上一个我做完的效果截图:

仿写效果图

我自己设计的控制条跟微信略有不同,微信是最长时间时候左右两个白色竖条离边框都还有一点距离,我这里设计的是两边白条都贴边框,返回按钮和确定裁剪按钮也不同。其实也没差,要说微信那样设计有特殊考虑的话,我只能说我不是交互和视觉设计师?

实现

1.我这里完整的拖动选择视图是封装的一个view,上面放一个scrollView来展示小的预览图片,再上面放两个image来做视频截取范围的开始和结束指示器。首先需要实现下面缩略图排列以及它的左右滑动,首先需要找到方法获取视频的帧图片。找了一下资料,很多,基本都是同一个方法,所以暂时选取了这个方法。为何说暂时,后面会解释。

#pragma 获取想要时间的帧视频图片

+(UIImage *)getCoverImage:(NSURL *)outMovieURL atTime:(CGFloat)time isKeyImage:(BOOL)isKeyImage{

AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:outMovieURL options:nil];

NSParameterAssert(asset);

AVAssetImageGenerator *assetImageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:asset];

assetImageGenerator.appliesPreferredTrackTransform = YES;

assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;

__block CGImageRef thumbnailImageRef = NULL;

NSError *thumbnailImageGenerationError = nil;

//tips:下面代码控制时间点的取图是否为关键帧图片,系统为了性能是默认取关键帧图片

CMTime myTime = CMTimeMake(time, 1);

if (!isKeyImage) {

assetImageGenerator.requestedTimeToleranceAfter = kCMTimeZero;

assetImageGenerator.requestedTimeToleranceBefore = kCMTimeZero;

CMTime duration = asset.duration;

myTime = CMTimeMake(time*30,30);

}

thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:myTime actualTime:NULL error:nil];

if (!thumbnailImageRef){

NSLog(@"thumbnailImageGenerationError %@", thumbnailImageGenerationError);

}

UIImage *thumbnailImage = thumbnailImageRef ? [[UIImage alloc]

initWithCGImage:thumbnailImageRef] : nil;

CGImageRelease(thumbnailImageRef);

return thumbnailImage;

}

通常开发者认为时间的呈现格式应该是浮点数据,我们一般使用NSTimeInterval,实际上它是简单的双精度double类型,只是typedef了一下,但是由于浮点型数据计算很容易导致精度的丢失,在一些要求高精度的应用场景显然不适合,于是苹果在Core Media框架中定义了CMTime数据类型作为时间的格式

typedef struct{

CMTimeValue    value;

CMTimeScale    timescale;

CMTimeFlags    flags;

CMTimeEpoch    epoch;

} CMTime;

//  显然,CMTime定义是一个C语言的结构体,CMTime是以分数的形式表示时间,value表示分子,timescale表示分母,flags是位掩码,表示时间的指定状态。CMTimeMake(3, 1)结果为3。

我是默认一个完整屏幕宽度为15秒的截取长度,在视频的每秒取一张帧图片作为底部预览小图,起初我是用循环视频时长秒数,每次用上面方法取一张图片,再用UIImageView放置这张图片,最后再计算imageView的位置添加到scrollView上。结果这是一个坑,视频只有二三十秒还好,如果比较长则会创建很多个imageView,内存暴涨,导致卡顿或者直接crash。后来想到了绘图,这样就不会请求内存多次分配空间,从而解决内存暴涨问题。

@interface WZScrollView : UIScrollView

@property (nonatomic, strong) UIImage *image;

@property (nonatomic, assign) CGRect *rect;

-(void)drawImage:(UIImage *)image inRect:(CGRect)rect;

@end

@implementation WZScrollView

-(void)drawRect:(CGRect)rect{

[super drawRect:rect];

[_image drawInRect:rect];

}

-(void)drawImage:(UIImage *)image inRect:(CGRect)rect{

_image = image;

_rect = &rect

[self setNeedsDisplayInRect:rect];

}

结果发现直接画图到scrollView在你拖动scrollView的时候它始终会只显示前面15张图片的效果,o(╯□╰)o!!!测试了一下,滚动是有效果的,但是体验不好啊。后来把上面的继承类从UIScrollView改成了UIView,把图片绘制到view上再加到scrollView上,设置好contentSize,问题解决。

@interface WZScrollView : UIView

接下来就是左右开始和结束的指示图片了,由于图片太小会有可能接收不到点击事件,所以我这里的切图在开始处指示图片的右边和结束指示图片的左边多裁一部分透明范围,这样指示器的面积就比你看到的大了,方便操作。接下来就是它们的拖动操作,最开始我使用的是view的touchesMoved:withEvent:来让图片改变x值从而跟随手指移动。结果发现,手速稍快或者触点稍微偏移就会导致图片位置改变停止,体验和性能都不行。后来改用拖动手势UIPanGestureRecognizer就完美解决了此问题,这里代码多是逻辑处理问题,包括拖动范围何时会让相应图片进行位置改变的响应,上下的白色线条位置和长度改变等等。但这里需要注意三个问题:a.拖动手势的回调方法里面的改变距离和原视图位置的x值会指数相加,每次回调都应该将视图的translation置0。b.需要每次回调都计算开始和结束位置的时间点,让其有实时性。c.拖动结束时需要让播放器循环播放两个时间点间的视频内容。

-(void)panAction:(UIPanGestureRecognizer *)panGR{

//伪代码:根据需求改变开始和结束指示图片的位置

if(panGR.state == UIGestureRecognizerStateChanged){

[panGR setTranslation:CGPointZero inView:self.superview];

}

[self calculateForTimeNodes];//实时计算裁剪时间

if (panGR.state == UIGestureRecognizerStateEnded) {

//伪代码:指示播放器播放相应视频片段代码

}

//计算开始结束时间点

-(void)calculateForTimeNodes{

CGPoint offset = _scrollView.contentOffset;

_startTime =(offset.x+self.startView.frame.origin.x)*15*1.0f/self.bounds.size.width;

_endTime = (offset.x + self.endView.frame.origin.x + KendTimeButtonWidth) * 15 * 1.0f/self.bounds.size.width;

CGFloat imageTime = _startTime;//预览时间点

if (_chooseType == imageTypeEnd) {

imageTime = _endTime;

}

if (self.getTimeRange) {

self.getTimeRange(_startTime,_endTime,imageTime);//控制预览播放界面的当前画面(这里是一个播放页传过来的block的调用)

}

2.拖动scrollView时,默认是展示开始时间点的视频帧画面,在scrollViewDidScroll:方法中调用calculateForTimeNodes方法即可实时更新开始、结束和预览3个时间点参数,这一步的很多逻辑都封装到第一步的一些方法中了,所以这一步比较简单。

3.拖动时暂停播放,松手后播放相应时间范围视频内容,可以循环播放。关于开始和结束指示图片的拖动状态可以用上面提到的panGR.state == UIGestureRecognizerStateEnded来判断,进入判断说明松手了,没有则还在拖动。而scrollView的拖动和停止直接调用它的代理就行了,这里不赘述,不明白可以在demo里面查看。这里遇到个坑是因为前面在视频预览页面拖动的时候需要有当前的视频帧画面用作预览,而开始是getCoverImage: atTime: isKeyImage:这个方法来获取帧图片的,当拖动时就显示图片图层,停止拖动就隐藏图片图层,进而显示下面的视频图层。结果这个方法比较消耗cpu,会导致卡顿情况,还会经常因为cpu过高直接crash。后来发现AVPlayer里面有一个seekToTime: toleranceBefore: toleranceAfter: completionHandler:方法,作用是让视频跳到某个时间点开始播放。我去,这么简单我却饶了好大一个弯,所以大家一定要在使用类的时候要养成多看原类文件的好习惯,可以少跳抗,囧!!!其实AVPlayer还有一个seekToTime:方法,我不使用它的原因是它有一个自己的最小时间单位(貌似是关键帧),用它不会实时改变播放器画面。

视频拖动时:

[_player pause];

[_player seekToTime:CMTimeMake(time*30, 30) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {

}];

拖动停止时:

[_player seekToTime:CMTimeMake(_startTime*30, 30) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {

[_player play];

}];

4.最后就是对视频进行裁剪了,这里的这个方法不是我写的,是网上找的别人的代码,但是原代码有个小问题,就是输出的视频文件方向改变了。在这里我用了下面3行代码来保证输出视频的方向跟原视频保持一致

AVURLAsset *asset = [AVURLAsset assetWithURL:videoUrl];

AVAssetTrack *assetVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo]firstObject];

[compositionVideoTrack setPreferredTransform:assetVideoTrack.preferredTransform];

我这里视频裁剪后的输出视频路径是固定的,所以我封装的方法里面的回调是没有参数的,码友如果需要可以自行改装:

+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl andCaptureVideoWithRange:(TimeRange)videoRange completion:(void(^)(void))completionHandle;

在这个方法调用时在回调里面多加了一个保存视频方法到里面,是由于我的项目需求。这个方法会新建一个以项目名称命名的相册,用来存放剪切后的视频,回调会传回一个PHAsset对象(项目需求)。

转载于:https://www.cnblogs.com/gongyuhonglou/p/6812829.html

iOS - 仿微信朋友圈视频剪切功能相关推荐

  1. IOS仿微信朋友圈的日期处理

    IOS仿微信朋友圈的日期处理 经常刷微信朋友圈的朋友,都能看到该条信息是什么发送的,有刚刚,有昨天,有xxxx年xx月xx日发送的,今天我们就探究微信内部是怎么样去做的. 对于传入的时间,一般是从服务 ...

  2. android bmob 朋友圈,仿微信朋友圈视频效果 – MVideo

    MVideo 仿微信朋友圈视频效果,可以拖拽及缩放,视频查看,基于ijkplayer. Demo 入门 Step 1:在buil文件中添加JitPack仓库: allprojects { reposi ...

  3. android仿微信发布动态功能,Android仿微信朋友圈发布动态功能

    一.前言 应工作上的要求,需要有一个类似于微信朋友圈发动态上传图片的功能,想起曾经已经做过了,但奈何不忍看自己以前写的代码的惨状,觉得重新封装一个使用方便,易于维护的类似功能的类,自己之后用起来也顺手 ...

  4. android 朋友圈功能,Android仿微信朋友圈全文收起功能示例(附源码)

    在众多的社交类软件中,朋友圈是必不可少的,可以与好友.同学等分享自己的日常和有意思的事情,在开发社交类App时,朋友圈发表的内容你不可能让他全部显示,全部显示的话用户体验度会非常不好,这时就要用到全文 ...

  5. android 仿微信朋友圈发布动态功能

    https://blog.csdn.net/qq_34501274/article/details/72911343

  6. 仿微信朋友圈,仿微信小视频 ,录制视频功能

    https://github.com/Naoki2015/VCameraDemo 仿微信小视频    CircleDemo  https://github.com/Naoki2015/CircleDe ...

  7. iOS粒子特效、仿微信朋友圈、转场动画、抢红包动画等源码

    iOS精选源码 viewController 之间的转场动画 swift版 视频添加水印及粒子特效 小红点(消息推送提醒)完整解决方案 仿微信朋友圈–CircleOfFriendsDisplay 图片 ...

  8. Android仿微信朋友圈7实现点赞功能

    前言: 之前一直有朋友问我点赞怎么实现?今天趁着休息时间整理出来,其实点赞的功能和用户评论差不多,都是显示一个用户列表,只不过评论有评论内容和回复评论功能.实现点赞的思路如下: 1.当用户点击点赞按钮 ...

  9. 安卓开发仿微信图片拖拽_仿微信朋友圈发表图片拖拽和删除功能

    原标题:仿微信朋友圈发表图片拖拽和删除功能 中国联通在香港公布了上市公司2017年中期业绩.2017年上半年,公司主要业绩指标持续向好,收入稳步回升,服务收入达到人民币1,241.1亿元,同比增长3. ...

最新文章

  1. %matplotlib inline %config InlineBackend.figure_format = “retina为了将图片嵌入notebook及提高分
  2. 高考查分数微信就能搞定
  3. Windbg内核调试之一: Vista Boot Config设置
  4. 【白皮书下载】《追本数源•开启产品智能化时代》| 产品指数级增长手册
  5. Hadoop vs Spark
  6. SAP CRM WebClient UI on new focus工作原理
  7. 动态调整线程池_调整线程池的重要性
  8. oracle 会话数上不去_Oracle初识
  9. 11月24日 layouts and rendering in rails(部分没有看)
  10. LeetCode:Add Binary
  11. gtest linux 性能测试,Linux下Gtest的安装与使用
  12. java jackson_Jackson 框架的高阶应用
  13. cisco ASA
  14. VC2013 ArcGIS Engine 10.0开发环境搭建
  15. JavaScript 高级程序设计(第3版)
  16. mac OSX安装VTK
  17. 网上选课系统算法了解
  18. :style动态设置背景图片
  19. FBE 与FDE学习总结
  20. 第二证券|下周解禁市值超980亿元,多家机构参与解禁股评级

热门文章

  1. 从Oracle迁移到PostgreSQL的十大理由
  2. 如果你不想做某些事情,那就找个对象吧, 让对象代你做!
  3. 浙大版《C语言程序设计实验与习题指导(第4版)》题目集 实验10-1 圆形体体积计算器
  4. animation 只触发一次的解决办法
  5. C#窗体程序实现全屏及取消全屏步骤
  6. 嵌入式行业的发展前景?
  7. CA证书原理(转载)
  8. 【lintcode】树形数据结构之Maxtree, Tree iterator, remove bst node, 优先队列之动态中位数Median, 矩阵dfs之word search II,最大连
  9. linux开vnc,linux 开启 vnc
  10. 内置超声波振动筛换能器振子设计