iOS拍个小视频
需求
公司混合开发,uni端拍小视频不是很理想,为达到仿微信效果,原生插件走起
思路
第1步:1个AVCaptureSession, 1块AVCaptureVideoPreviewLayer[考虑兼容替换成AVPreView]
第2步:视频录制需video & audio, 需要对应的AVCaptureDeviceInput,同理对应的AVCaptureVideoDataOutput与AVCaptureAudioDataOutput
第3步:代理中设置output区分video与audio, 并将对应的CMSampleBufferRef写入到视频文件中
第4步:写入视频文件中,用到AVAssetWriter, 对应video & audio 需两个AVAssetWriterInput, 加入AVAssetWriter
第5步:CMSampleBufferRef不断过来,AssetWriter不断写入,直到停止
上菜
第一步的初始化就不写了,没事可以翻看本人前面的博客
第2步:两个AVCaptureDeviceInput 两个Output, 且设置Output的代理
self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
if (error) {
NSLog(@"取得设备摄入videoInput对象时出错, 错误原因: %@", error);
return;
} // 设备添加到会话中
if ([self.session canAddInput:self.videoInput]) {
[self.session addInput:self.videoInput];
} [self.videoOutput setSampleBufferDelegate:self queue:self.videoQueue];
if ([self.session canAddOutput:self.videoOutput]) {
[self.session addOutput:self.videoOutput];
} // 音频相关
AVCaptureDevice *adevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:adevice error:&error]; if ([self.session canAddInput:self.audioInput]) {
[self.session addInput:self.audioInput];
} [self.audioOutput setSampleBufferDelegate:self queue:self.videoQueue];
if ([self.session canAddOutput:self.audioOutput]) {
[self.session addOutput:self.audioOutput];
} // 视频输出
- (AVCaptureVideoDataOutput *)videoOutput {
if (!_videoOutput) {
_videoOutput = [[AVCaptureVideoDataOutput alloc] init];
_videoOutput.alwaysDiscardsLateVideoFrames = YES;
}
return _videoOutput;
} // 音频输出
- (AVCaptureAudioDataOutput *)audioOutput {
if (!_audioOutput) {
_audioOutput = [[AVCaptureAudioDataOutput alloc] init];
}
return _audioOutput;
}第3步:启动Session,代理里面操作CMSampleBufferRef
#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate & AVCaptureAudioDataOutputSampleBufferDelegate
- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
@autoreleasepool {
// 视频
if (connection == [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]) {
if (!self.manager.outputVideoFormatDescription) {
@synchronized(self) {
CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
self.manager.outputVideoFormatDescription = formatDescription;
}
} else {
@synchronized(self) {
if (self.manager.state == StateRecording) {
[self.manager appendBuffer:sampleBuffer type:AVMediaTypeVideo];
}
}
}
} //音频
if (connection == [self.audioOutput connectionWithMediaType:AVMediaTypeAudio]) {
if (!self.manager.outputAudioFormatDescription) {
@synchronized(self) {
CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
self.manager.outputAudioFormatDescription = formatDescription;
}
}
@synchronized(self) {
if (self.manager.state == StateRecording) {
[self.manager appendBuffer:sampleBuffer type:AVMediaTypeAudio];
}
}
}
}
}
第4步:AVAssetWriter以及对应的Input
// writer初始化
self.writer = [AVAssetWriter assetWriterWithURL:_videoUrl fileType:AVFileTypeMPEG4 error:nil]; _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:_videoSettings];
//expectsMediaDataInRealTime 必须设为yes,需要从capture session 实时获取数据
_videoInput.expectsMediaDataInRealTime = YES; _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:_audioSettings];
_audioInput.expectsMediaDataInRealTime = YES; if ([_writer canAddInput:_videoInput]) {
[_writer addInput:_videoInput];
}
if ([_writer canAddInput:_audioInput]) {
[_writer addInput:_audioInput];
}
第5步:第3步的CMSampleBufferRef通过AVAssetWriter写入到视频文件中
- (void)appendBuffer:(CMSampleBufferRef)buffer type:(NSString *)mediaType {
if (buffer == NULL) {
NSLog(@"empty sampleBuffer");
return;
} @synchronized (self) {
if (self.state < StateRecording) {
NSLog(@"not ready yet");
return;
}
} CFRetain(buffer);
dispatch_async(self.queue, ^{
@autoreleasepool {
@synchronized (self) {
if (self.state > StateFinish) {
CFRelease(buffer);
return;
}
} if (!self.canWrite && mediaType == AVMediaTypeVideo) {
[self.writer startWriting];
[self.writer startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(buffer)];
self.canWrite = YES;
} if(!self.timer) {
dispatch_async(dispatch_get_main_queue(), ^{
self.timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
});
} // 写入视频数据
if (mediaType == AVMediaTypeVideo) {
if (self.videoInput.readyForMoreMediaData) {
BOOL success = [self.videoInput appendSampleBuffer:buffer];
if (!success) {
@synchronized (self) {
[self stop:^{}];
[self destroy];
}
}
}
} // 写入音频数据
if (mediaType == AVMediaTypeAudio) {
if (self.audioInput.readyForMoreMediaData) {
BOOL success = [self.audioInput appendSampleBuffer:buffer];
if (!success) {
@synchronized (self) {
[self stop:^{}];
[self destroy];
}
}
}
}
CFRelease(buffer);
}
});
}写在末尾:
AVAssetWriterInput设置视频属性时,按照自己的需要设计,其中码率与帧率的设置会影响到拍摄后视频的质量与大小,具体看各自项目的要求
如果视频视角存在问题,可以从三个方向入手调整
1.layer的connect设置下videoOrientation
2.AVCaptureOutput的connect设置下videoOrientation
3.AVAssetWriterInput针对video是设置下transform,比如Rotation M_PI/2 角度
iOS拍个小视频的更多相关文章
- IOS版微信小视频导出方法
1.在电脑上连接手机,打开iTools 选择 应用-应用-文件共享. 2.依次打开/Library/WechatPrivate/6e2809aac61608de6a6cc55d9570d25b/Sig ...
- [iOS]手把手教你实现微信小视频
本文个人原创,转载请注明出处,谢谢. 前段时间项目要求需要在聊天模块中加入类似微信的小视频功能,这边博客主要是为了总结遇到的问题和解决方法,希望能够对有同样需求的朋友有所帮助. 效果预览: 这里先罗列 ...
- ios设备突破微信小视频6S限制的方法
刷微信朋友圈只发文字和图片怎能意犹未竟,微信小视频是一个很好的补充,音视频到位,流行流行最流行.但小视频时长不能超过6S,没有滤镜等是很大的遗憾.but有人突破限制玩出了花样,用ios设备在朋友圈晒出 ...
- Android 仿微信朋友圈拍小视频上传到服务器
这个接上一个写的实现拍小视频和传到服务器的 界面是这个样子滴. 我也知不知道怎么给图片搞小一点o(╯□╰)o 布局文件是这样的[认真脸] <?xml version="1.0&quo ...
- iOS微信小视频优化心得
小视频是微信6.0版本重大功能之一,在开发过程中遇到不少问题.本文先叙述小视频的产品需求,介绍了几个实现方案,分析每个方案的优缺点,最后总结出最优的解决方案. 小视频播放需求 可以同时播放多个视频 用 ...
- iOS燃烧动画、3D视图框架、天气动画、立体相册、微信朋友圈小视频等源码
iOS精选源码 iOS天气动画,包括太阳,云,雨,雷暴,雪动画. 较为美观的多级展开列表 3D立体相册,可以旋转的立方体 一个仪表盘Demo YGDashboardView 一个基于UIScrollV ...
- 如何保存微信的小视频 How to keep WeChat 'Sights'
微信小视频非常方便,但很难将其下载到本地电脑长期保存.网上有介绍方法,如百度经验上办法,但目前看来它可能只适用安卓系统,而且或已失效(可能由于版本更新).对Windows Phone无效,而对于更加封 ...
- 利用ffmpeg给小视频结尾增加logo水印
背景 1.app有类似微信拍摄小视频功能,时长上限8s,视频文件保存在第三方云存储,app直接上传,后端数据库只记录视频的存放地址. 2.最近一次功能迭代,增加了小视频下载功能,小视频有可能在别的社交 ...
- 微信小视频复制到手机本地Android APP 分享
因为需要将拍的宝宝的微信小视频上传到亲宝宝软件,每次去手动找文件比较麻烦,所以做了个微信视频复制到手机本地的APP,做工虽然粗糙,但是绝对实用, 下载地址 http://pan.baidu.com/s ...
随机推荐
- (7)Linux使用注意事项
1.Linux 严格区分大小写 和 Windows 不同,Linux 是严格区分大小写的,包括文件名和目录名.命令.命令选项.配置文件设置选项等. 2.Windows 下的程序不能直接在 Linux ...
- CCF-交通规划-dijkstra+贪心
交通规划 问题描述 G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统. 建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改造成 ...
- dedecms文章页的上下篇颠倒的问题
dedecms的文章页底下的上下篇,如果按照时间排序的话,最新的一篇应该是最上了,但是底下还是会显示上一篇文章还有,然后下一篇文章没有了,就是颠倒了.如何修改呢. 1.修改include目录下arc. ...
- java类里的成员变量是自身的对象问题
今晚看单例模式饿汉时想到一个问题:假如java类里的成员变量是自身的对象,则新建该类对象时内存中怎么分配空间,我感觉似乎死循环了.于是上网搜索了下,哈哈,果然有人早就思考过这个问题了,站在巨人的肩膀上 ...
- 【bzoj 3333】排队计划(线段树)
n个数,求一次逆序对.接着有m次修改操作,把每次输入的位置p的数之后<=它的数取出来,从小到大排序后再放回空位里,求逆序对.(N,M<=500,000 , Ai<=10^9)思路:1 ...
- 郁闷的出纳员 HYSBZ - 1503
OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他 ...
- Codeforces Round #515 (Div. 3) E. Binary Numbers AND Sum (二进制,前缀和)
题意:有两个\(01\)字符串\(a\)和\(b\),每次让\(a\)和\(b\)进行与运算,将值贡献给答案,然后将\(b\)右移一位,直到\(b=0\). 题解:因为\(a\)不变,而\(b\)每次 ...
- linux运维面试精华题
Linux运维跳槽面试精华题|第一集 1.什么是运维?什么是游戏运维? 1)运维是指大型组织已经建立好的网络软硬件的维护,就是要保证业务的上线与运作的正常,在他运转的过程中,对他进行维护,他集合了网络 ...
- 流水线cpu —Verilog HDL
一.准备工作 先看看书(<计算机原理与设计 Verilog HDL版>),搞懂一点原理.然后照着书上的代码写一写(用8.4的就可以了,不用8.6的). 注意mux2x32,mux4,cla ...
- C# 特殊符号
特殊符号 @开头 前面提到过,字符串里免转义用的, 字符串里写的啥就是啥,遇到\ 不转义 ?? 判断一个值是不是null,是的话就变成后面的默认值,不是的话就还是原值 $开头 字符串篡改 和forma ...