最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!!

源代码:https://github.com/hardman/AWLive

通过系统相机录制视频获取音视频数据,是推流的第一步。
源码中提供2种获取音视频数据的方法:一是使用系统自带接口;二是使用GPUImage。

本篇首先介绍第一种。

网络上关于获取视频数据的代码有不少,但是为了方便代码阅读,这里简要介绍一下。

[注意]请仔细阅读代码注释

相关代码入口

整套推流代码的入口:AWAVCaptureManager,它是根据参数创建上述2种获取数据方法的一个工厂类。

可以通过设置 captureType 来决定使用哪种数据获取方式。

AWAVCaptureManager部分代码如下:

typedef enum : NSUInteger {AWAVCaptureTypeNone,AWAVCaptureTypeSystem,AWAVCaptureTypeGPUImage,
} AWAVCaptureType;@interface AWAVCaptureManager : NSObject
//视频捕获类型
@property (nonatomic, unsafe_unretained) AWAVCaptureType captureType;
@property (nonatomic, weak) AWAVCapture *avCapture;//省略其他代码
......
@end

设置了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.captureSessionPreset;//提交配置变更[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.bounds;[self.preview.layer addSublayer:self.previewLayer];
}

切换摄像头

-(void)setVideoInputDevice:(AVCaptureDeviceInput *)videoInputDevice{if ([videoInputDevice isEqual:_videoInputDevice]) {return;}//captureSession 修改配置[self.captureSession beginConfiguration];//移除当前输入设备if (_videoInputDevice) {[self.captureSession removeInput:_videoInputDevice];}//增加新的输入设备if (videoInputDevice) {[self.captureSession addInput:videoInputDevice];}//提交配置,至此前后摄像头切换完毕[self.captureSession commitConfiguration];_videoInputDevice = videoInputDevice;
}

设置fps

-(void) updateFps:(NSInteger) fps{//获取当前capture设备NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];//遍历所有设备(前后摄像头)for (AVCaptureDevice *vDevice in videoDevices) {//获取当前支持的最大fpsfloat 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.activeVideoMinFrameDuration;[vDevice unlockForConfiguration];}}}
}

获取音视频数据

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{if (self.isCapturing) {if ([self.videoDataOutput isEqual:captureOutput]) {//捕获到视频数据,通过sendVideoSampleBuffer发送出去,后续文章会解释接下来的详细流程。[self sendVideoSampleBuffer:sampleBuffer];}else if([self.audioDataOutput isEqual:captureOutput]){//捕获到音频数据,通过sendVideoSampleBuffer发送出去[self sendAudioSampleBuffer:sampleBuffer];}}
}

至此,我们达到了所有目标:能够录制视频,预览,获取音视频数据,切换前后摄像头,修改捕获视频的fps。

文章列表

  1. 1小时学会:最简单的iOS直播推流(一)项目介绍
  2. 1小时学会:最简单的iOS直播推流(二)代码架构概述
  3. 1小时学会:最简单的iOS直播推流(三)使用系统接口捕获音视频
  4. 1小时学会:最简单的iOS直播推流(四)如何使用GPUImage,如何美颜
  5. 1小时学会:最简单的iOS直播推流(五)yuv、pcm数据的介绍和获取
  6. 1小时学会:最简单的iOS直播推流(六)h264、aac、flv介绍
  7. 1小时学会:最简单的iOS直播推流(七)h264/aac 硬编码
  8. 1小时学会:最简单的iOS直播推流(八)h264/aac 软编码
  9. 1小时学会:最简单的iOS直播推流(九)flv 编码与音视频时间戳同步
  10. 1小时学会:最简单的iOS直播推流(十)librtmp使用介绍
  11. 1小时学会:最简单的iOS直播推流(十一)sps&pps和AudioSpecificConfig介绍(完结)

1小时学会:最简单的iOS直播推流(三)使用系统接口捕获音视频数据相关推荐

  1. 1小时学会:最简单的iOS直播推流(十一)spspps和AudioSpecificConfig介绍(完结)

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  2. 1小时学会:最简单的iOS直播推流(十)librtmp使用介绍

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  3. 1小时学会:最简单的iOS直播推流(八)h264/aac 软编码

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  4. 1小时学会:最简单的iOS直播推流(七)h264/aac 硬编码

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  5. 1小时学会:最简单的iOS直播推流(六)h264、aac、flv介绍

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  6. 1小时学会:最简单的iOS直播推流(五)yuv、pcm数据的介绍和获取

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  7. 1小时学会:最简单的iOS直播推流(四)如何使用GPUImage,如何美颜

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  8. 1小时学会:最简单的iOS直播推流(二)代码架构概述

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  9. 1小时学会:最简单的iOS直播推流(一)介绍

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

最新文章

  1. Solr_全文检索引擎系统
  2. Strings in the Pocket
  3. java请实现程序输出以下星塔||输出菱形
  4. 设计模式笔记二十二:空对象模式
  5. java 企业级应用设计规范_一步一步理解Java 企业级应用的可扩展性
  6. 深度学习之激活函数详解
  7. Detecting Near-Duplicates for Web Crawling - simhash与重复信息识别
  8. java打包成jar对其进行加密处理防止反编译
  9. Update Strategy小记
  10. 6-1 哈夫曼树及哈夫曼编码分数
  11. jetson nano开发使用的基础详细分享
  12. unity保存游戏对象到mysql_Unity实现游戏存档框架
  13. lg空调代码大全解决_lg空调故障代码是什么意思 lg空调故障代码大全【详解】...
  14. Android 腾讯TUIKIT IM即时通信聊天界面语音问题备忘
  15. 酷早报:7月21日Web3加密行业新闻大汇总
  16. Ubuntu 更换国内源
  17. ASML最后的倔强,不愿失去中国市场,继续供应28纳米光刻机
  18. 如何成为一个内心强大的人
  19. 【HTML思维导图】
  20. 如何摆脱“ 穷忙 ” 的现状?

热门文章

  1. this.$router.push、replace、go的区别
  2. centos 安装 mysql 5.7
  3. MyBaties学习记录
  4. CentOS6.5 下sciki-learn numpy scipy 的安装
  5. 为图片添加半透明遮罩效果
  6. 充分理解表达式——《狂人C》习题解答2(第二章习题5)
  7. smarty的简单分页
  8. 动态生成GridView时,加入DataKeyNames属性,回调时出错解决方法
  9. 如何使用 ASP.NET 实用工具加密凭据和会话状态连接字符串
  10. VC下提前注入进程的一些方法2——远线程带参数