前言####
这些年App的呈现方式不断在进化,从最初的文字到图片,再到gif动态图片,现在是视频展示,所以我觉得我们的技术也要不断的更新,那么今天就从录制小视频开始吧。
录制视频的方式###
简单的来讲主要有两种
1、UIImagePickerController,比较简单,功能单一
2、AVFoundation的AVCaptureSession视频捕获类(本文主讲)
由于考虑到视频录制以后可能会用到,所以我把录制视频封装成工具类。视频源码地址:自定义视频录制之AVCaptureSession
录制效果:
录制视频的步骤####
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 是对程序猿最大的鼓励!