iOS -自定义视频录制方法之AVCaptureSession

前言####

这些年App的呈现方式不断在进化,从最初的文字到图片,再到gif动态图片,现在是视频展示,所以我觉得我们的技术也要不断的更新,那么今天就从录制小视频开始吧。

录制视频的方式###

简单的来讲主要有两种
1、UIImagePickerController,比较简单,功能单一
2、AVFoundation的AVCaptureSession视频捕获类(本文主讲)
由于考虑到视频录制以后可能会用到,所以我把录制视频封装成工具类。视频源码地址:自定义视频录制之AVCaptureSession
录制效果:

Snip20161008_37.png
Snip20161008_37.png

录制视频的步骤####

1、相机、麦克风、保存视频的相册是否授权

//相机是否可以用   
 - (BOOL)isAvailableWithCamera
{
    return [self isAvailableWithDeviveMediaType:AVMediaTypeVideo];
 }
//麦克风是否可以用
- (BOOL)isAvailableWithMic
{
  return [self isAvailableWithDeviveMediaType:AVMediaTypeAudio];
}
- (BOOL)isAvailableWithDeviveMediaType:(NSString *)mediaType
{
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if(status == ALAuthorizationStatusDenied||status == ALAuthorizationStatusRestricted)
    return NO;
else
    return YES;
}

2、初始化输入输出、摄像头、数据流管理、视频预览层

 @property (strong, nonatomic) AVCaptureSession *captureSession;  //负责输入和输出设备之间的连接会话,数据流的管理控制
 @property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;//捕获到的视频呈现的layer
 @property (strong, nonatomic) AVCaptureDeviceInput       *backCameraInput;//后置摄像头输入
 @property (strong, nonatomic) AVCaptureDeviceInput       *frontCameraInput;//前置摄像头输入
 @property (strong, nonatomic) AVCaptureDeviceInput       *audioMicInput;//麦克风输入
 @property (strong, nonatomic) AVCaptureConnection        *videoConnection;//视频录制连接
 @property (strong,nonatomic) AVCaptureMovieFileOutput    *captureMovieFileOutput;//视频输出流

由于初始化的东西比较多,那么我就简单的列举几个,详情可以查看demo自定义视频录制之AVCaptureSession

 //捕获视频的会话
- (AVCaptureSession *)captureSession
{
if(_captureSession == nil)
{
    _captureSession = [[AVCaptureSession alloc] init];
    //设置分辨率
    if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        _captureSession.sessionPreset=AVCaptureSessionPreset1280x720;
    }
    //添加后置摄像头的输入
    if ([_captureSession canAddInput:self.backCameraInput]) {
        [_captureSession addInput:self.backCameraInput];
    }
    //添加后置麦克风的输入
    if ([_captureSession canAddInput:self.audioMicInput]) {
        [_captureSession addInput:self.audioMicInput];
    }
    //将设备输出添加到会话中
    if ([_captureSession canAddOutput:self.captureMovieFileOutput]) {
        [_captureSession addOutput:self.captureMovieFileOutput];
    }
    //设置视频录制的方向
    self.videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
}
return _captureSession;

}

初始化录制视频的预览层

//捕获到的视频呈现的layer
 - (AVCaptureVideoPreviewLayer *)previewLayer {
if (_previewLayer == nil) {
    //通过AVCaptureSession初始化
    AVCaptureVideoPreviewLayer *preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
    //设置比例为铺满全屏
    preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    _previewLayer = preview;
}
return _previewLayer;
}

4、初始化完成之后,就可以启动录制功能(注意:是启动录制功能,并不是开始录制),启动录制功能的之前一定要把视频预览层放到你想要的录制区域,这样开启录制功能就能预览录制效果

//启动录制功能
- (void)startRecordFunction
{
  [self.captureSession startRunning];
  }
 //关闭录制功能
- (void)stopRecordFunction
{
if(self.captureSession)
    [self.captureSession stopRunning];
}

5、在录制视频开始之前要设置录制视频的输入视频流的存放地址,你可以存放到您想存放的地方,本文存放到temp文件中

   #pragma mark - 视频地址
  - (NSString *)getVideoPathCache
 {
NSString *videoCache = [NSTemporaryDirectory() stringByAppendingPathComponent:@"videos"] ;
BOOL isDir = NO;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL existed = [fileManager fileExistsAtPath:videoCache isDirectory:&isDir];
if ( !(isDir == YES && existed == YES) ) {
    [fileManager createDirectoryAtPath:videoCache withIntermediateDirectories:YES attributes:nil error:nil];
};
return videoCache;
 }
- (NSString *)getVideoNameWithType:(NSString *)fileType
{
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"HHmmss"];
NSDate * NowDate = [NSDate dateWithTimeIntervalSince1970:now];
;
NSString * timeStr = [formatter stringFromDate:NowDate];
NSString *fileName = [NSString stringWithFormat:@"video_%@.%@",timeStr,fileType];
return fileName;
}

6、开始录制

  //开始录制
- (void)startCapture
{
if(self.captureMovieFileOutput.isRecording)
    return;
NSString *defultPath = [self getVideoPathCache];
NSString *outputFielPath=[ defultPath stringByAppendingPathComponent:[self getVideoNameWithType:@"mp4"]];
NSLog(@"save path is :%@",outputFielPath);
NSURL *fileUrl=[NSURL fileURLWithPath:outputFielPath];
//设置录制视频流输出的路径
[self.captureMovieFileOutput startRecordingToOutputFileURL:fileUrl recordingDelegate:self]; 
}
//停止录制
- (void) stopCapture
 {
if ([self.captureMovieFileOutput isRecording]) {
    [self.captureMovieFileOutput stopRecording];//停止录制
}
}

7、视频录制过程中有AVCaptureFileOutputRecordingDelegate记录监听录制过程,我们可以实现代理方法查看,并且在录制完成,我们希望把视频保存到我们的相册中

 #pragma mark - 视频输出代理
 -(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections{
NSLog(@"开始录制...");
}
 -(void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error{
NSLog(@"视频录制完成.");
//视频录入完成之后在后台将视频存储到相
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
    if (error) {
        NSLog(@"保存视频到相簿过程中发生错误,错误信息:%@",error.localizedDescription);
    }
    NSLog(@"成功保存视频到相簿.");
}];    
}

8、在录制过程中我们有时候还要增加一些功能,比如切换摄像头、开启闪光灯、录制进度显示等

  #注意:改变会话的配置前一定要先开启配置,配置完成后提交配置改变 
    //开启闪光灯
- (void)openFlashLight
{
//改变会话的配置前一定要先开启配置,配置完成后提交配置改变
[self.captureSession beginConfiguration];
AVCaptureDevice *backCamera = [self backCamera];
if (backCamera.torchMode == AVCaptureTorchModeOff) {
    [backCamera lockForConfiguration:nil];
    backCamera.torchMode = AVCaptureTorchModeOn;
    backCamera.flashMode = AVCaptureFlashModeOn;
    [backCamera unlockForConfiguration];
}
//提交会话配置
[self.captureSession commitConfiguration];
[self startRecordFunction];
}

详情代码请直接下载demo查看:
自定义视频录制之AVCaptureSession

最后赠言###

如果觉得文章对您有帮助,不要忘记star哦!😝,star 是对程序猿最大的鼓励!

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

推荐阅读更多精彩内容