最简单的iOSpc直播姬推流不能使用推流如何使用GPUImage,如何美颜

iOS直播实用篇(手把手教)
招聘信息:
一.简述总体内容1.直播流程介绍2.Mac搭建nginx+rtmp服务器(模拟推流拉流)3.简单的集成推流拉流(实用篇)4.好的博客推荐二.直播流程介绍& 1.简单的流程图简单的流程图2.七牛的直播流程七牛的直播流程3.视频直播,可以分为采集,前处理(美颜等等),编码,推流和传输,服务器处理,解码拉流1.采集:采集是整个视频推流过程中的第一个环节,它从系统的采集设备中获取原始视频数据,将其输出到下一个环节。视频的采集涉及两方面数据的采集:音频采集和图像采集,它们分别对应两种完全不同的输入源和数据格式.iOS系统因为软硬件种类不多, 硬件适配性比较好, 所以比较简单. 而Android端市面上机型众多, 要做些机型的适配工作.PC端是最麻烦的, 各种奇葩摄像头驱动.所以现在很多的中小型直播平台, 都放弃了PC的直播, 更有一些直播平台只做iOS端的视频直播.采集2.前处理: 美颜算法,视频的模糊效果, 水印等都是在这个环节做. 目前iOS端最著名开源框架的毫无疑问就是GPUImage.其中内置了125种渲染效果, 还支持各种脚本自定义.都说「80% 的主播没有美颜根本没法看」,美颜是直播产品中最常见的功能之一。最近准备在香港上市的美图公司的主打产品就是美颜相机和美拍,有媒体戏称其会冲击化妆品行业,其实就是美颜的效果的功劳,让美女主播们不化妆也可以自信的直播,而美颜相机的用户则可以拍出「更好的自己」。前处理3.编码:对流媒体传输来说,编码也非常重要,它的编码性能、编码速度和编码压缩比会直接影响整个流媒体传输的用户体验和传输成本.重难点在于要在分辨率,帧率,码率,GOP等参数设计上找到最佳平衡点。iOS8之后, Apple开放了VideoToolbox.framework, 可以直接进行硬编解码, 这也是为什么现在大多数直播平台最低只支持到iOS8的原因之一. iOS端硬件兼容性比较好, 可以直接采取硬编码,常用的编码有:4.推流和传输: 这块一般都是交给CDN服务商. CDN只提供带宽和服务器之间的传输, 发送端和接收端的网络连接抖动缓存还是要自己实现的.目前国内最大的CDN服务商应该是网宿.传输协议一般是RTMP,HLS,FLV5.服务器处理:需要在服务器做一些流处理工作, 让推送上来的流适配各个平台各种不同的协议, 比如:RTMP,HLS,FLV...6.解码拉流:推流需要编码,同样拉流解码是必须的. iOS端兼容较好,Android依然大坑.这块的难点在于音画同步, 目前很多直播平台这块是硬伤.国内比较好的开源项目应该是B站开源的.斗鱼就是基于的, 本项目也是基于的.7.8.9.三.Mac搭建nginx+rtmp服务器(模拟推流拉流)效果如下(把桌面的视频推到搭建的服务器再利用播放器拉流),也可以用自己写的播放软件来拉流,或者三方Mac搭建nginx+rtmp服务器(模拟推流拉流)手动输入命令的时候容易出现了bug(所以, 建议大家直接复制命令, 不要手动输入命令). 所以记录一份详细的搭建步骤,参考1.打开终端, 查看是否已经安装了Homebrew, 直接终端输入命令&&&man&brew如果Mac已经安装了, 会显示一些命令的帮助信息. 此时输入Q退出即可, 直接进入第二步.反之, 如果没有安装,执行命令&&ruby&-e&"$(curl&-fsSL&/Homebrew/install/master/install)"如果安装后, 想要卸载&&ruby&-e&"$(curl&-fsSL&/Homebrew/install/master/uninstall)"2.安装nginx先clone nginx项目到本地&&brew&tap&homebrew/nginx执行安装:&&brew&install&nginx-full&--with-rtmp-module此时, nginx和rtmp模块就安装好了输入命令:&&nginx在浏览器里打开如果出现下图, 则表示安装成功安装成功如果终端上提示nginx: [emerg] bind() to 0.0.0.0:8080 failed (48: Address already in use)nginx: [emerg] bind() to 0.0.0.0:8080 failed (48: Address already in use)nginx: [emerg] bind() to 0.0.0.0:8080 failed (48: Address already in use)nginx: [emerg] bind() to 0.0.0.0:8080 failed (48: Address already in use).....则表示8080端口被占用了, 查看端口PID&&lsof&-i&tcp:8080根据端口PID, kill掉(这儿的9603换成你自己8080端口的PID)&&kill&9603然后重新执行nginx, 打开 进行检测是否 nginx安装成功3.配置nginx和ramp首先我们查看nginx安装到哪了&&brew&info&nginx-full如图, 找到nginx.conf文件所在位置nginx.conf文件所在位置通过vim或者点击Finder->前往->前往文件夹->输入/usr/local/etc/nginx/nginx.conf->用记事本工具(推荐Sublime Text)打开nginx.conf.直接滚到最后一行, 在最后一个}(即最后的空白处, 没有任何{})后面添加&&#&在http节点后面加上rtmp配置:
&&&&server&{
&&&&listen&1935;
&&&&application&rtmplive&{
&&&&&&&&live&
&&&&&&&&record&
&}记得保存command+S然后重启nginx(其中的1.10.1要换成你自己安装的nginx版本号, 查看版本号用nginx -v命令即可)&&/usr/local/Cellar/nginx-full/1.10.1/bin/nginx&-s&reload4.安装ffmpeg执行命令&brew&install&ffmpeg安装ffmpeg时间就要长一点了. 如果速度过慢, 建议翻墙. 不过也才50多M的东西, 耐心一点就好. 等待的时间里, 再安装一个支持rtmp协议的视频播放器5.进行推流(1).ffmpeg推流,用我桌面的一个动画片为例,执行推流命令ffmpeg -re -i /Users/jinqianxiang/Desktop/BigBuck.m4v -vcodec libx264 -acodec aac -strict -2 -f flv rtmp://localhost:1935/rtmplive/room提醒: /Users/jinqianxiang/Desktop/BigBuck.m4v是路径,你可把视频拖进终端,查看路径将视频推流到服务器后,打开VLC,然后File->open network->输入:&&rtmp://localhost:1935/rtmplive/room效果如下四.简单的集成推流拉流(实用篇)1. 推流端,这里我才用的 开源的推流框架,开源的iOS推流框架. 是用OC写的, 很适合学习集成也非常简单, 几句代码就OK了.采用cocopods导入即可pod&'LFLiveKit'提示:LFLiveKit已经集成了GPUImage, 如果项目中有集成GPUImage, 需要将之前的移除掉. 且集成LFLiveKit需要关闭Bitcode.集成LFLiveKit需要关闭Bitcode.导入成功在推流的控制器写入下面的代码导入推流框架&#import&"LFLiveKit.h"
-&(LFLiveSession*)session&{
if&(!_session)&{
&&&&_session&=&[[LFLiveSession&alloc]&initWithAudioConfiguration:[LFLiveAudioConfiguration&defaultConfiguration]&videoConfiguration:[LFLiveVideoConfiguration&defaultConfiguration]];
&&&&_session.preView&=&
&&&&_session.delegate&=&
&&return&_
-&(void)startLive&{&
&&&&LFLiveStreamInfo&*streamInfo&=&[LFLiveStreamInfo&new];
&&&&streamInfo.url&=&@"your&server&rtmp&url";
&&&&[self.session&startLive:streamInfo];
-&(void)stopLive&{
&&&&&&[self.session&stopLive];
//MARK:&-&CallBack:
-&(void)liveSession:(nullable&LFLiveSession&*)session&liveStateDidChange:&(LFLiveState)
-&(void)liveSession:(nullable&LFLiveSession&*)session&debugInfo:(nullable&LFLiveDebug*)debugI
-&(void)liveSession:(nullable&LFLiveSession*)session&errorCode:(LFLiveSocketErrorCode)errorC到此推流就成功了,提示网络一定要打来2. 拉流端 主要是基于 的. 最好是打包成framework. 下载
密码: mcjt导入库:完成上述之后,运行不报错,就说明你基本上成功了,在拉流的控制器里面输入下面的代码导入&#import&&1.创建推流对象
&-&(LFLiveSession*)session&{
&&&&&if&(!_session)&{
&&&&_session&=&[[LFLiveSession&alloc]&initWithAudioConfiguration:[LFLiveAudioConfiguration&defaultConfiguration]&videoConfiguration:[LFLiveVideoConfiguration&defaultConfiguration]];
&&&&_session.delegate&=&
&&return&_
}2.在点击开始直播的方法里面输入&&&&&NSLog(@"开始直播");
//&判断是否是模拟器
if&([[UIDevice&deviceVersion]&isEqualToString:@"iPhone&Simulator"])&{
&&&&[MBProgressHUD&showError:@"请用真机进行测试,&此模块不支持模拟器测试"];
//&判断是否有摄像头
if(![UIImagePickerController&isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
&&&&[MBProgressHUD&showError:@"您的设备没有摄像头或者相关的驱动,&不能进行直播"];
//&判断是否有摄像头权限
AVAuthorizationStatus&&authorizationStatus&=&[AVCaptureDevice&authorizationStatusForMediaType:AVMediaTypeVideo];
if&(authorizationStatus&==&AVAuthorizationStatusRestricted||&authorizationStatus&==&AVAuthorizationStatusDenied)&{
&&&&[MBProgressHUD&showError:@"app需要访问您的摄像头。\n请启用摄像头-设置/隐私/摄像头"];
//&开启麦克风权限
AVAudioSession&*audioSession&=&[AVAudioSession&sharedInstance];
if&([audioSession&respondsToSelector:@selector(requestRecordPermission:)])&{
&&&&[audioSession&performSelector:@selector(requestRecordPermission:)&withObject:^(BOOL&granted)&{
&&&&&&&&if&(granted)&{
&&&&&&&&&&&&return&YES;
&&&&&&&&else&{
&&&&&&&&&&&&//[self&showInfo:@"app需要访问您的麦克风。\n请启用麦克风-设置/隐私/麦克风"];
&&&&&&&&&&&&return&NO;
LFLiveStreamInfo&*streamInfo&=&[LFLiveStreamInfo&new];
streamInfo.url&=&kTRMPS
[self.session&startLive:streamInfo];相关的类demo里面都有 密码: w935到此,推流和拉流就完成了,更多美颜等功能等等,就看更多的大神博客,下面推荐五.好的直播博客推荐(三方直播):可以进去学习一下
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量5547点击量4046点击量3713点击量3657点击量3251点击量3243点击量3231点击量3195点击量3116
&2016 Chukong Technologies,Inc.
京公网安备89视频直播(13)
利用GPUImage处理直播过程中美颜的流程
采集视频 =& 获取每一帧图片 =& 滤镜处理 =& GPUImageView展示
美颜原理.png
美颜基本概念
GPU:(Graphic Processor Unit图形处理单元)手机或者电脑用于图像处理和渲染的硬件
GPU工作原理:采集数据-& 存入主内存(RAM) -& CPU(计算处理) -& 存入显存(VRAM) -& GPU(完成图像渲染) -& 帧缓冲区 -& 显示器
GPU工作原理.jpg
OpenGL ES:(Open Graphics Library For Embedded(嵌入的) Systems开源嵌入式系统图形处理框架),一套图形与硬件接口,用于把处理好的图片显示到屏幕上。
GPUImage:是一个基于OpenGL ES 2.0图像和视频处理的开源iOS框架,提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜,内置120多种滤镜效果,并且能够自定义图像滤镜。
滤镜处理的原理:就是把静态图片或者视频的每一帧进行图形变换再显示出来。它的本质就是像素点的坐标和颜色变化
GPUImage处理画面原理
GPUImage采用链式方式来处理画面,通过addTarget:方法为链条添加每个环节的对象,处理完一个target,就会把上一个环节处理好的图像数据传递下一个target去处理,称为GPUImage处理链。
比如:墨镜原理,从外界传来光线,会经过墨镜过滤,在传给我们的眼睛,就能感受到大白天也是乌黑一片,哈哈。
一般的target可分为两类
中间环节的target, 一般是各种filter, 是GPUImageFilter或者是子类.
最终环节的target, GPUImageView:用于显示到屏幕上, 或者GPUImageMovieWriter:写成视频文件。
GPUImage处理主要分为3个环节
source(视频、图片源) -& filter(滤镜) -& final target (处理后视频、图片)
GPUImaged的Source:都继承GPUImageOutput的子类,作为GPUImage的数据源,就好比外界的光线,作为眼睛的输出源
GPUImageVideoCamera:用于实时拍摄视频
GPUImageStillCamera:用于实时拍摄照片
GPUImagePicture:用于处理已经拍摄好的图片,比如png,jpg图片
GPUImageMovie:用于处理已经拍摄好的视频,比如mp4文件
GPUImage的filter:GPUimageFilter类或者子类,这个类继承自GPUImageOutput,并且遵守GPUImageInput协议,这样既能流进,又能流出,就好比我们的墨镜,光线通过墨镜的处理,最终进入我们眼睛
GPUImage的final target:GPUImageView,GPUImageMovieWriter就好比我们眼睛,最终输入目标。
GPUImage处理原理.png
磨皮(GPUImageBilateralFilter):本质就是让像素点模糊,可以使用高斯模糊,但是可能导致边缘会不清晰,用双边滤波(Bilateral Filter) ,有针对性的模糊像素点,能保证边缘不被模糊。
美白(GPUImageBrightnessFilter):本质就是提高亮度。
关注效果,忽悠本人
GPUImage原生美颜效果
GPUImage原生.gif
利用美颜滤镜实现效果
美颜滤镜处理.gif
GPUImage实战
GPUImage原生美颜
步骤一:使用Cocoapods导入GPUImage
步骤二:创建视频源GPUImageVideoCamera
步骤三:创建最终目的源:GPUImageView
步骤四:创建滤镜组(GPUImageFilterGroup),需要组合亮度(GPUImageBrightnessFilter)和双边滤波(GPUImageBilateralFilter)这两个滤镜达到美颜效果.
步骤五:设置滤镜组链
步骤六:设置GPUImage处理链,从数据源 =& 滤镜 =& 最终界面效果
步骤七:开始采集视频
SessionPreset最好使用AVCaptureSessionPresetHigh,会自动识别,如果用太高分辨率,当前设备不支持会直接报错
GPUImageVideoCamera必须要强引用,否则会被销毁,不能持续采集视频.
必须调用startCameraCapture,底层才会把采集到的视频源,渲染到GPUImageView中,就能显示了。
GPUImageBilateralFilter的distanceNormalizationFactor值越小,磨皮效果越好,distanceNormalizationFactor取值范围:大于1。
- (void)viewDidLoad {& &&
[superviewDidLoad];
// 创建视频源
// SessionPreset:屏幕分辨率,AVCaptureSessionPresetHigh会自适应高分辨率
// cameraPosition:摄像头方向
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc]initWithSessionPreset:AVCaptureSessionPresetHighcameraPosition:AVCaptureDevicePositionFront];& & videoCamera.outputImageOrientation = UIInterfaceOrientationP&&
& _videoCamera = videoC
// 创建最终预览
ViewGPUImageView *captureVideoPreview = [[GPUImageView alloc]initWithFrame:self.view.bounds];&&
& [self.viewinsertSubview:captureVideoPreviewatIndex:0];
// 创建滤镜:磨皮,美白,组合滤镜
GPUImageFilterGroup *groupFilter = [[GPUImageFilterGroup alloc] init];
// 磨皮滤镜
GPUImageBilateralFilter *bilateralFilter = [[GPUImageBilateralFilter alloc] init];& &&
[groupFilteraddTarget:bilateralFilter];& &
&_bilateralFilter = bilateralF
// 美白滤镜
GPUImageBrightnessFilter *brightnessFilter = [[GPUImageBrightnessFilter alloc] init];& &
&[groupFilteraddTarget:brightnessFilter];&&
& _brightnessFilter = brightnessF
// 设置滤镜组链
[bilateralFilteraddTarget:brightnessFilter];&&
& [groupFiltersetInitialFilters:@[bilateralFilter]];&&
& groupFilter.terminalFilter = brightnessF
// 设置GPUImage响应链,从数据源 =& 滤镜 =& 最终界面效果
[videoCameraaddTarget:groupFilter];&&
& [groupFilteraddTarget:captureVideoPreview];
// 必须调用startCameraCapture,底层才会把采集到的视频源,渲染到GPUImageView中,就能显示了。// 开始采集视频
[videoCamera startCameraCapture];
- (IBAction)brightnessFilter:(UISlider *)sender&
_brightnessFilter.brightness = sender.
- (IBAction)bilateralFilter:(UISlider *)sender {
// 值越小,磨皮效果越好CGFloat maxValue =10;& &
&[_bilateralFiltersetDistanceNormalizationFactor:(maxValue - sender.value)];
利用美颜滤镜实现
步骤一:使用Cocoapods导入GPUImage
步骤二:导入GPUImageBeautifyFilter文件夹
步骤三:创建视频源GPUImageVideoCamera
步骤四:创建最终目的源:GPUImageView
步骤五:创建最终美颜滤镜:GPUImageBeautifyFilter
步骤六:设置GPUImage处理链,从数据源 =& 滤镜 =& 最终界面效果
切换美颜效果原理:移除之前所有处理链,重新设置处理链
- (void)viewDidLoad {&
&& [superviewDidLoad];
// Do any additional setup after loading the view.
// 创建视频源// SessionPreset:屏幕分辨率,AVCaptureSessionPresetHigh会自适应高分辨率
// cameraPosition:摄像头方向
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc]initWithSessionPreset:AVCaptureSessionPresetHighcameraPosition:AVCaptureDevicePositionFront];&&
& videoCamera.outputImageOrientation = UIInterfaceOrientationP& &
&_videoCamera = videoC
// 创建最终预览
ViewGPUImageView *captureVideoPreview = [[GPUImageView alloc]initWithFrame:self.view.bounds];
& & [self.viewinsertSubview:captureVideoPreviewatIndex:0];&&
& _captureVideoPreview = captureVideoP
// 设置处理链
[_videoCameraaddTarget:_captureVideoPreview];
// 必须调用startCameraCapture,底层才会把采集到的视频源,渲染到GPUImageView中,就能显示了。
// 开始采集视频
[videoCamera startCameraCapture];
- (IBAction)openBeautifyFilter:(UISwitch *)sender {
// 切换美颜效果原理:移除之前所有处理链,重新设置处理链
if(sender.on) {
// 移除之前所有处理链
[_videoCamera removeAllTargets];
// 创建美颜滤镜
GPUImageBeautifyFilter *beautifyFilter = [[GPUImageBeautifyFilter alloc] init];
// 设置GPUImage处理链,从数据源 =& 滤镜 =& 最终界面效果
[_videoCameraaddTarget:beautifyFilter];& & &
&& [beautifyFilteraddTarget:_captureVideoPreview];&
// 移除之前所有处理链[_videoCamera removeAllTargets];& & &
&& [_videoCameraaddTarget:_captureVideoPreview];& &
GPUImage扩展
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14233次
排名:千里之外
原创:80篇
(1)(2)(16)(3)(66)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜。现在各种各样的直播、视频App层出不穷,美颜滤镜的需求也越来越多。为了回馈开源,现在我把它放到了GitHub
/Guikunzhi/BeautifyFaceDemo
上面,感兴趣的朋友可以去下载。下面将主要介绍实现美颜滤镜的原理和思路。
2.GPUImage
GPUImage 是一个开源的基于GPU的图片或视频的处理框架,其本身内置了多达120多种常见的滤镜效果。有了它,添加实时的滤镜只需要简单地添加几行代码。下面的例子是以摄像头的数据为源,对其实时地进行反色的操作(类似相片底片的效果):
利用GPUImage对摄像头数据添加滤镜的示例2.1
其实美颜也是一样,如果有这么一个美颜的滤镜(姑且叫做GPUImageBeautifyFilter),那么只需要把示例2.1中的GPUImageColorInvertFilter替换成GPUImageBeautifyFilter即可。我们只需要做一个GPUImageBeautifyFilter就能实现实时美颜了,问题来了,到底什么算是美颜呢?我的理解是,大家对于美颜比较常见的需求就是磨皮、美白。当然提高饱和度、提亮之类的就根据需求而定。本文将着重介绍磨皮的实现(实际上GPUImageBeautifyFilter也实现了美白、提亮等效果)。
磨皮的本质实际上是模糊。而在图像处理领域,模糊就是将像素点的取值与周边的像素点取值相关联。而我们常见的高斯模糊 ,它的像素点取值则是由周边像素点求加权平均所得,而权重系数则是像素间的距离的高斯函数,大致关系是距离越小、权重系数越大。下图3.1是高斯模糊效果的示例:
高斯模糊效果示例3.1
如果单单使用高斯模糊来磨皮,得到的效果是不尽人意的。原因在于,高斯模糊只考虑了像素间的距离关系,没有考虑到像素值本身之间的差异。举个例子来讲,头发与人脸分界处(颜色差异很大,黑色与人皮肤的颜色),如果采用高斯模糊则这个边缘也会模糊掉,这显然不是我们希望看到的。而双边滤波(Bilateral Filter) 则考虑到了颜色的差异,它的像素点取值也是周边像素点的加权平均,而且权重也是高斯函数。不同的是,这个权重不仅与像素间距离有关,还与像素值本身的差异有关,具体讲是,像素值差异越小,权重越大,也是这个特性让它具有了保持边缘的特性,因此它是一个很好的磨皮工具。下图3.2是双边滤波的效果示例:
双边滤波效果示例3.2
对比3.1和3.2,双边滤波效果确实在人脸细节部分保留得更好,因此我采用了双边滤波作为磨皮的基础算法。双边滤波在GPUImage中也有实现,是GPUImageBilateralFilter。
根据图3.2,可以看到图中仍有部分人脸的细节保护得不够,还有我们并不希望将人的头发也模糊掉(我们只需要对皮肤进行处理)。由此延伸出来的改进思路是结合双边滤波,边缘检测以及肤色检测。整体逻辑如下:
磨皮处理逻辑图3.3
Combination &Filter是我们自己定义的三输入的滤波器。三个输入分别是原图像A(x, y),双边滤波后的图像B(x, y),边缘图像C(x, y)。其中A,B,C可以看成是图像矩阵,(x,y)可以看成其中某一像素的坐标。Combination &Filter的处理逻辑如下图:
Combination Filter逻辑图3.3
下面是主要的shader代码:
combination filter的shader代码3.4
Combination Filter通过肤色检测和边缘检测,只对皮肤和非边缘部分进行处理。下面是采用这种方式进行磨皮之后的效果图:
最终磨皮效果图3.5
对比3.5与3.2,可以看到3.5对人脸细节的保护更好,同时对于面部磨皮效果也很好,给人感觉更加真实。
我所采用的磨皮算法是基于双边滤波的,主要是考虑到它同时结合了像素间空间距离以及像素值本身的差异。当然也不一定要采用双边滤波,也有通过改进高斯模糊(结合像素值差异)来实现磨皮的,甚至能取得更好的效果。另外GPUImageBeautifyFilter不仅仅具有磨皮功能,也实现了log曲线调色,亮度、饱和度的调整,具体详情可以参见demo 。
/Guikunzhi/BeautifyFaceDemo
阅读(...) 评论()最简单的iOS直播推流(三)使用系统接口捕获音视频数据
最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!!
通过相机录制视频获取音视频数据,是推流的第一步。
中提供2种获取音视频数据的方法:一是使用系统自带接口;二是使用GPUImage。
本篇首先介绍第一种。
网络上关于获取视频数据的代码有不少,但是为了方便代码,这里简要介绍一下。
[注意]请仔细阅读代码注释
相关代码入口
整套推流代码的入口:AWAVCaptureManager,它是根据参数创建上述2种获取数据方法的一个工厂类。
可以通过设置 captureType 来决定使用哪种数据获取方式。
AWAVCaptureManager部分代码如下:
typedef enum : NSUInteger {
AWAVCaptureTypeNone,
AWAVCaptureTypeSystem,
AWAVCaptureTypeGPUImage,
} AWAVCaptureT
@interface AWAVCaptureManager : NSObject
//视频捕获类型
@property (nonatomic, unsafe_unretained) AWAVCaptureType captureT
@property (nonatomic, weak) AWAVCapture *avC
//省略其他代码
设置了captureType之后,直接可以通过avCapture获取到正确的捕获视频数据的对象了。
AWAVCapture 是一个虚基类(c++中的说法,不会直接产生对象,只用来继承的类,java中叫做抽象类)。
它的两个子类分别是 AWSystemAVCapture 和 AWGPUImageAVCapture。
这里使用了多态。
如果 captureType设置的是 AWAVCaptureTypeSystem,avCapture获取到的真实对象就是 AWSystemAVCapture类型;
如果 captureType设置的是 AWAVCaptureTypeGPUImage,avCapture获取到的真实对象就是 AWGPUImageAVCapture类型。
AWSystemAVCapture类的功能只有一个:调用系统相机,获取音视频数据。
相机数据获取的方法
分为3步骤:
1. 初始化输入输出设备。
2. 创建AVCaptureSession,用来管理视频与数据的捕获。
3. 创建预览UI。
还包括一些其他功能:
1. 切换摄像头
2. 更改fps
在代码中对应的是 AWSystemAVCapture中的 onInit方法。只要初始化就会调用。
【注意】请仔细阅读下文代码中的注释
初始化输入设备
-(void) createCaptureDevice{
// 初始化前后摄像头
// 执行这几句代码后,系统会弹框提示:应用想要访问您的相机。请点击同意
// 另外iOS10 需要在info.plist中添加字段NSCameraUsageDescription。否则会闪退,具体请自行baidu。
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
self.frontCamera = [AVCaptureDeviceInput deviceInputWithDevice:videoDevices.firstObject error:nil];
self.backCamera =[AVCaptureDeviceInput deviceInputWithDevice:videoDevices.lastObject error:nil];
// 初始化麦克风
// 执行这几句代码后,系统会弹框提示:应用想要访问您的麦克风。请点击同意
// 另外iOS10 需要在info.plist中添加字段NSMicrophoneUsageDescription。否则会闪退,具体请自行baidu。
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
self.audioInputDevice = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
//省略其他代码
初始化输出设备
-(void) createOutput{
//创建数据获取线程
dispatch_queue_t captureQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//视频数据输出
self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
//设置代理,需要当前类实现protocol:AVCaptureVideoDataOutputSampleBufferDelegate
[self.videoDataOutput setSampleBufferDelegate:self queue:captureQueue];
//抛弃过期帧,保证实时性
[self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
//设置输出格式为 yuv420
[self.videoDataOutput setVideoSettings:@{
(__bridge NSString *)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
//音频数据输出
self.audioDataOutput = [[AVCaptureAudioDataOutput alloc] init];
//设置代理,需要当前类实现protocol:AVCaptureAudioDataOutputSampleBufferDelegate
[self.audioDataOutput setSampleBufferDelegate:self queue:captureQueue];
// AVCaptureVideoDataOutputSampleBufferDelegate 和 AVCaptureAudioDataOutputSampleBufferDelegate 回调方法名相同都是:
// captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
// 最终视频和音频数据都可以在此方法中获取。
创建 captureSession
// AVCaptureSession 创建逻辑很简单,它像是一个中介者,从音视频输入设备获取数据,处理后,传递给输出设备(数据代理/预览layer)。
-(void) createCaptureSession{
self.captureSession = [AVCaptureSession new];
//修改配置
[self.captureSession beginConfiguration];
//加入视频输入设备
if ([self.captureSession canAddInput:self.videoInputDevice]) {
[self.captureSession addInput:self.videoInputDevice];
//加入音频输入设备
if ([self.captureSession canAddInput:self.audioInputDevice]) {
[self.captureSession addInput:self.audioInputDevice];
//加入视频输出
if([self.captureSession canAddOutput:self.videoDataOutput]){
[self.captureSession addOutput:self.videoDataOutput];
[self setVideoOutConfig];
//加入音频输出
if([self.captureSession canAddOutput:self.audioDataOutput]){
[self.captureSession addOutput:self.audioDataOutput];
//设置预览分辨率
//这个分辨率有一个值得注意的点:
//iphone4录制视频时 前置摄像头只能支持 480*640 后置摄像头不支持 540*960 但是支持 720*1280
//诸如此类的限制,所以需要写一些对分辨率进行管理的代码。
//目前的处理是,对于不支持的分辨率会抛出一个异常
//但是这样做是不够、不完整的,最好的方案是,根据设备,提供不同的分辨率。
//如果必须要用一个不支持的分辨率,那么需要根据需求对数据和预览进行裁剪,缩放。
if (![self.captureSession canSetSessionPreset:self.captureSessionPreset]) {
@throw [NSException exceptionWithName:@&Not supported captureSessionPreset& reason:[NSString stringWithFormat:@&captureSessionPreset is [%@]&, self.captureSessionPreset] userInfo:nil];
self.captureSession.sessionPreset = self.captureSessionP
//提交配置变更
[self.captureSession commitConfiguration];
//开始运行,此时,CaptureSession将从输入设备获取数据,处理后,传递给输出设备。
[self.captureSession startRunning];
创建预览UI
// 其实只有一句代码:CALayer layer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
// 它其实是 AVCaptureSession的一个输出方式而已。
// CaptureSession会将从input设备得到的数据,处理后,显示到此layer上。
// 我们可以将此layer变换后加入到任意UIView中。
-(void) createPreviewLayer{
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
self.previewLayer.frame = self.preview.
[self.preview.layer addSublayer:self.previewLayer];
切换摄像头
-(void)setVideoInputDevice:(AVCaptureDeviceInput *)videoInputDevice{
if ([videoInputDevice isEqual:_videoInputDevice]) {
//captureSession 修改配置
[self.captureSession beginConfiguration];
//移除当前输入设备
if (_videoInputDevice) {
[self.captureSession removeInput:_videoInputDevice];
//增加新的输入设备
if (videoInputDevice) {
[self.captureSession addInput:videoInputDevice];
//提交配置,至此前后摄像头切换完毕
[self.captureSession commitConfiguration];
_videoInputDevice = videoInputD
-(void) updateFps:(NSInteger) fps{
//获取当前capture设备
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
//遍历所有设备(前后摄像头)
for (AVCaptureDevice *vDevice in videoDevices) {
//获取当前支持的最大fps
float maxRate = [(AVFrameRateRange *)[vDevice.activeFormat.videoSupportedFrameRateRanges objectAtIndex:0] maxFrameRate];
//如果想要设置的fps小于或等于做大fps,就进行修改
if (maxRate &= fps) {
//实际修改fps的代码
if ([vDevice lockForConfiguration:NULL]) {
vDevice.activeVideoMinFrameDuration = CMTimeMake(10, (int)(fps * 10));
vDevice.activeVideoMaxFrameDuration = vDevice.activeVideoMinFrameD
[vDevice unlockForConfiguration];
至此,我们达到了所有目标:能够录制视频,预览,获取音视频数据,切换前后摄像头,修改捕获视频的fps。

我要回帖

更多关于 同学录留言简单到流泪 的文章

 

随机推荐