iOS直播---音/视频采集/压缩(二)

代码界的吴彦祖 2018-01-04 17:05:59 ⋅ 927 阅读

iOS视频直播---主要的概念(一)

第一部分: 视频采集----AVCaptureSession

1.1 视频采集的流程

AVCaptureSession通过把设备的麦克风/摄像头(AVCaptureDevice)实例化成数据流输入对象(AVCaptureDeviceInput)后,再通过建立连接(AVCaptionConnection)将录制数据通过数据流输出对象(AVCaptureOutput)导出,而录制的时候咱们可以同步预览当前的录制界面(AVCaptureVideoPreviewLayer).

1.2 视频采集中的主要对象

1. AVCaptureSession: 是设备音频/视频整个录制期间的管理者;2. AVCaptureDevice: 设备管理者: 操作闪光灯,手电筒,聚焦模式等;3. AVCaptureDeviceInput: 是录制期间输入流数据的管理对象;4. AVCaptionConnection: 是将 输入流/输出流 连接起来的连接对象,视频/音频稳定,预览与录制方向一致 都在这里设置,还有audioChannels声道;5. AVCaptureOutput: 是 输出流数据 的管理对象,通过头文件可以看到有很多子类,而我们通常也使用其子类;6. AVCaptureVideoPreviewLayer: 是一个CALyer,可以让我们预览拍摄过程中的图像.

本文最终实现目标---音视频采集/压缩:

Paste_Image.png

1.3 设备授权

录制视频需真机, 因此必须首先获得授权;用以下代码来判断, 返回结果为枚举值;

//此处获取摄像头授权, 是一个枚举值[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]

枚举值---AVAuthorizationStatus为:

typedef NS_ENUM(NSInteger, AVAuthorizationStatus) {  //未进行授权选择 
    AVAuthorizationStatusNotDetermined = 0,    //未授权,且用户无法更新,如家长控制情况下
    AVAuthorizationStatusRestricted,    //用户拒绝App使用
    AVAuthorizationStatusDenied,    //已授权,可使用
    AVAuthorizationStatusAuthorized} NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;        

1.4 AVCaptureSession对象创建

- (void)initAVCapture{
    
    _captureSession = [[AVCaptureSession alloc] init];    //设置录像的分辨率
    if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
        [_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh];
    }    
    /****************************/
        [_captureSession beginConfiguration];    /*-----------------------------*/
    //摄像头<枚举值:前后>
    _videoDevice = [self deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];    //视频的输入输出
    [self videoIO];    //音频的输入<录制视频时不需要输出>
    [self audioIO];    //录制的同时播放
    [self previewLayer];    /*-----------------------------*/
    [_captureSession commitConfiguration];    //开启会话-->注意,不等于开始录制
    [_captureSession startRunning];  
}

注释:

**1. [_captureSession beginConfiguration/commitConfiguration];

**参考苹果官方文档中所述:

After calling beginConfiguration, you can for example add or remove outputs, alter
 the sessionPreset, or configure individual capture input or output properties. No changes 
are actually made until you invoke commitConfiguration(), at which time they are applied together.

1.5 视频的输入和输出--AVCaptureDeviceInput/AVCaptureMovieFileOutput

//视频的输入和输出- (void)videoIO{{    /*---------------input-------------------------*/
    NSError *videoError;    // 视频输入对象
    // 根据输入设备初始化输入对象,用户获取输入数据
    _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:&videoError];    if (videoError) {        NSLog(@"---- 取得摄像头设备时出错 ------ %@",videoError);        return;
    }    // 将视频输入对象添加到会话 (AVCaptureSession) 中
    if ([_captureSession canAddInput:_videoInput]) {
        [_captureSession addInput:_videoInput];
    }    
    /*---------------output------------------------*/
    // 拍摄视频输出对象
    // 初始化输出设备对象,用户获取输出数据
    _movieOutput = [[AVCaptureMovieFileOutput alloc] init];    
    if ([_captureSession canAddOutput:_movieOutput]) {
        [_captureSession addOutput:_movieOutput];        AVCaptureConnection *captureConnection = [_movieOutput connectionWithMediaType:AVMediaTypeVideo];        // 视频稳定设置
        if ([captureConnection isVideoStabilizationSupported]) {
            captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
        }
        captureConnection.videoScaleAndCropFactor = captureConnection.videoMaxScaleAndCropFactor;
    }
}

1.6 音频的输入---AVCaptureDeviceInput

#pragma mark 音频的输入输出- (void)audioIO{    /*-------------input---------*/
    NSError *audioError;    // 添加一个音频输入设备
    _audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];    //  音频输入对象
    _audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:_audioDevice error:&audioError];    if (audioError) {        NSLog(@"取得录音设备时出错 ------ %@",audioError);        return;
    }    // 将音频输入对象添加到会话 (AVCaptureSession) 中
    if ([_captureSession canAddInput:_audioInput]) {
        [_captureSession addInput:_audioInput];
    }
}

1.7 展示的录制视频

- (void)previewLayer{
    [self.view layoutIfNeeded];    
    // 通过会话 (AVCaptureSession) 创建预览层
    _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    _captureVideoPreviewLayer.frame = self.view.layer.bounds;    //有时候需要拍摄完整屏幕大小的时候可以修改这个
    //    _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    // 如果预览图层和视频方向不一致,可以修改这个
    _captureVideoPreviewLayer.connection.videoOrientation = [_movieOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation;
    _captureVideoPreviewLayer.position = CGPointMake(self.videoView.frame.size.width*0.5,self.videoView.frame.size.height*0.5);    
    // 显示在视图表面的图层
    CALayer *layer = self.videoView.layer;
    layer.masksToBounds = true;
    [self.view layoutIfNeeded];
    [layer addSublayer:_captureVideoPreviewLayer];
    
}

第二部分

  1. 视频压缩

1.1需要引入系统框架--AssetsLibrary.framework与AVKit.framework

# 压缩视频- (IBAction)compressVideo:(id)sender{    NSLog(@"开始压缩,压缩前大小 %f MB",[self fileSize:self.videoUrl]);    
    self.saveBtn.enabled = NO;    
    AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:self.videoUrl options:nil];    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];    if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {        
        AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:AVAssetExportPreset640x480];
        exportSession.outputURL = [self compressedURL];        //优化网络
        exportSession.shouldOptimizeForNetworkUse = true;        //转换后的格式
        exportSession.outputFileType = AVFileTypeMPEG4;        //异步导出
        [exportSession exportAsynchronouslyWithCompletionHandler:^{            // 如果导出的状态为完成
            if ([exportSession status] == AVAssetExportSessionStatusCompleted) {                NSLog(@"压缩完毕,压缩后大小 %f MB",[self fileSize:[self compressedURL]]);
                [self saveVideo:[self compressedURL]];
            }else{                NSLog(@"当前压缩进度:%f",exportSession.progress);
            }            
            self.saveBtn.enabled = YES;
        }];
    }
}

压缩是使用的AVURLAsset的流程图如下:

Paste_Image.png

2.保存暂时使用的是ALAssetsLibrary;

ALAssetsLibrary提供了我们对iOS设备中的相片、视频的访问。

//ALAssetsLibrary提供了我们对iOS设备中的相片、视频的访问。- (void)saveVideo:(NSURL *)outputFileURL
{
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
                                completionBlock:^(NSURL *assetURL, NSError *error) {                                    if (error) {                                        NSLog(@"保存视频失败:%@",error);
                                    } else {                                        NSLog(@"保存视频到相册成功");
                                    }
                                }];
}

注释

PhotoKit是苹果推出的用于替代ALAssetsLibrary的框架。
PhotoKit为使用照片和视频资源提供了新的API。PhotoKit还包含一个线程安全架构用以获取、缓存缩略图和全尺寸图片,请求资产更改,遵守其他应用所做的变化,以及对资产内容进行可恢复的编辑。

Demo详见github
https://github.com/mugworts/iOSLive




全部评论: 0

    我有话说:

    iOS直播---主要的概念(一)

    直播可谓风生水起, 热火朝天, 借此也对视频进行一次深入学习, 希望有需要的大家一块学习.第一步对直播的大

    iOS实战篇:[译]iOS扩充--OCR光学字符识别(内附项目GitHub地址)

    OCR(Optical Character Recognition) 光学字符识别, 是从图像中电子扫描提取文本的过程, 可以在文档编辑等多种形式重用它,例如: 文本搜索/压缩等用途。

    品质建设 - iOS启动优化《原理篇》

    前言 启动是 App 给用户的第一印象,启动越慢用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环。启动优化涉及到的知识点非常多面也很广,一篇文章难以包含全部,所以拆分成两部分:原理和实践。 本文从基础知识出发,先回顾一些核心概念,为后...

    自学视频剪辑要多长时间才能学会?

      <p><strong>雾隐门视频剪辑软件</strong><br /> 雾隐门快剪辑是款非常适合自媒体人士使用的视频剪辑软件,快速上手是

    微信小程序抖实战-小视频弹幕

    如果你去抖只是为了看小视频就少了一大乐趣,评论区才是最有趣的地方,边看视频边看评论的弹幕是不是更有意思

    品质建设 - iOS启动优化《实战篇》

    实战,本文是实战篇。 原理篇:抖品质建设-iO...

    iOS实战篇:iOS 界面卡顿原因

    界面卡顿的原因在 VSync[1] 信号到来后,系统图形服务会通过 CADisplayLink 等机制通知 App,App 主线程开始在 CPU 中计算显示内容......

    iOS性能优化实践:头条抖如何实现OOM崩溃率下降50%+

    iOS OOM 崩溃在生产环境中的归因一直是困扰业界已久的疑难问题,字节跳动旗下的头条、抖等产品也面临同样的问题。在字节跳动性能与稳定性保障团队的研发实践中,我们自研了一款基于内存快照技术并且可

    iOS TableView性能优化

    TableView的性能优化非常考验开发的基本功,之前做项目实战的时候经常被这个问题困扰

    微信小程序抖实战-支持播放小视频

    之前的案例只支持图片的播放,经过粉丝的反馈说视频弄不出来,本节内容就教大家怎么做

    「轻阅读」基于 Flink SQL CDC的实时数据同步方案,附视频

    整理:陈政羽(Flink 社区志愿者)原文:https://mp.weixin.qq.com/s/QNJlacBUlkMT7ksKKSNa5Q Flink 1.11 引入了 Flink SQL CDC,CDC 能给我们数据和业务间能带来什么变化?...

    Nodejs视频服务器 切片ffmpeg

    Node 视频服务器 切片ffmpeg

    微信小程序抖实战-首页(下)

    小程序首页动态数据获取

    微信小程序抖实战-首页(上)

    你也可以用微信小程序编写一个抖

    精品推荐:无推送,无新闻,无广告,2倍速看视频,看直播的超强浏览器

    今天给大家推荐一款小众却功能强大的应用,这款应用不怎么出名,一直很低调,但是却受到众多好评,相对其他大众的浏

    采集Nginx日志的几种方式

    来源 | https://dwz.cn/ofiCxRK0 由于nginx功能强大,性能突出,越来越多的web应用采用nginx作为http和反向代理的web服务器。而nginx的访问日志不管是做

    Kafka系列

      分区 Kafka 的消息组织方 式实际上是三级结构:主题 - 分区 - 消息 问题一:为什么 Kafka 要做这样的设计?为什么使用分区的概念而不是直接使用多个主题呢? 分区的

    APP 性能优化系列:Java 内存优化篇

    memory)崩溃。抖作为一款用户使用广泛的产品,需要在...