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

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

iOS直播---音/视频解码(四)
iOS直播---音/视频编码(三)

更多精彩内容请关注“IT实战联盟”哦~~~


IT实战联盟.jpg

参考
1.苹果官方文档AVCaptureSession_Class
2. iOS 自定义相机, UIImagePickerController && AVCaptureSession (附微信小视频模仿demo)
3. AVFoundation编程指南1-使用 Assets
4. AVFoundation编程指南2-用AVPlayer播放视频
5. iOS --- 使用PhotoKit代替ALAssetsLibrary来管理相册资源

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容