IOS开发入门最简单的iOS直播推流(三)使用系统接口捕获音视频数据
白羽 2019-05-21 来源 :网络 阅读 413 评论 0

摘要:本文将带你了解IOS开发入门最简单的iOS直播推流(三)使用系统接口捕获音视频数据,希望本文对大家学IOS有所帮助。

    本文将带你了解IOS开发入门最简单的iOS直播推流(三)使用系统接口捕获音视频数据,希望本文对大家学IOS有所帮助。


IOS开发入门最简单的iOS直播推流(三)使用系统接口捕获音视频数据


最简单的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
   ?123456789// 其实只有一句代码: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)  {        //获取当前支持的最大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.activeVideoMinFrameDuration;                [vDevice  unlockForConfiguration];            }        }    }}
   至此,我们达到了所有目标:能够录制视频,预览,获取音视频数据,切换前后摄像头,修改捕获视频的fps。   


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程