使用:
@interface ViewController ()
@property (nonatomic, strong) CameraTool *videoTool;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;//相机拍摄预览图层
@end
@implementation ViewController
- (CameraTool *)videoTool {
if(!_videoTool) {
_videoTool = [[CameraTool alloc]init];
}
return _videoTool;
}
-(void)viewDidLoad {
[super viewDidLoad];
self.captureVideoPreviewLayer = [self.videoTool previewLayer];
CALayer *layer=self.view.layer;
layer.masksToBounds=YES;
self.captureVideoPreviewLayer.frame = layer.bounds;
[layer addSublayer:self.captureVideoPreviewLayer];
[self.videoTool startRecordFunction];
}
主要代码:
CameraTool.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
typedef void(^Block)(NSData *data);//回调照片流
@interface CameraTool : NSObject
@property (strong, nonatomic) NSString *videoPath;//视频路径
//捕获到的视频呈现的layer
- (AVCaptureVideoPreviewLayer *)previewLayer;
//启动录制功能
- (void)startRecordFunction;
//关闭录制功能
- (void)stopRecordFunction;
//开始录制
- (void) startCapture;
//停止录制
- (void) stopCapture;
//拍照
- (void)shutterCamera:(Block)block;
//开启闪光灯
- (void)openFlashLight;
//关闭闪光灯
- (void)closeFlashLight;
//切换前后置摄像头
- (void)changeCameraInputDeviceisFront:(BOOL)isFront;
-(void)saveAllVideoToPoto;//保存视频到相册
-(void)deleteAllVideo;//删除所有视频
@end
CameraTool.m
#import "CameraTool.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/Photos.h>
@interface CameraTool() <AVCaptureFileOutputRecordingDelegate>
@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;//视频输出流
@property (nonatomic, strong)AVCaptureStillImageOutput *stillImageOutput;//照片输出流对象
@end
@implementation CameraTool
#pragma mark -API
//启动录制功能
- (void)startRecordFunction
{
[self.captureSession startRunning];
}
//关闭录制功能
- (void)stopRecordFunction
{
if(self.captureSession)
[self.captureSession stopRunning];
}
//开始录制
- (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];//停止录制
}
}
// 这是拍照按钮的方法
- (void)shutterCamera:(Block)block
{
AVCaptureConnection *videoConnection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
if (!videoConnection) {
NSLog(@"空");
return;
}
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer == NULL) {
return;
}
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
block(imageData);
UIImage *image = [UIImage imageWithData:imageData];
[self SavedPhoto:image];
NSLog(@"image size = %@", NSStringFromCGSize(image.size));
}];
}
//保存图片到相册
- (void)SavedPhoto:(UIImage *)image
{
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)self);
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
NSLog(@"image = %@, error = %@, contextInfo = %@", image, error, contextInfo);
}
//开启闪光灯
- (void)openFlashLight
{
//改变会话的配置前一定要先开启配置,配置完成后提交配置改变
//[self stopRecordFunction];
[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];
}
//关闭闪光灯
- (void)closeFlashLight
{
//改变会话的配置前一定要先开启配置,配置完成后提交配置改变
// [self stopRecordFunction];
[self.captureSession beginConfiguration];
AVCaptureDevice *backCamera = [self backCamera];
if (backCamera.torchMode == AVCaptureTorchModeOn) {
[backCamera lockForConfiguration:nil];
backCamera.torchMode = AVCaptureTorchModeOff;
backCamera.flashMode = AVCaptureTorchModeOff;
[backCamera unlockForConfiguration];
}
//提交会话配置
[self.captureSession commitConfiguration];
[self startRecordFunction];
}
//切换前后置摄像头
- (void)changeCameraInputDeviceisFront:(BOOL)isFront {
//改变会话的配置前一定要先开启配置,配置完成后提交配置改变
[self stopRecordFunction];
[self.captureSession beginConfiguration];
if (isFront) {
[self.captureSession removeInput:self.backCameraInput];
if ([self.captureSession canAddInput:self.frontCameraInput]) {
//[self changeCameraAnimation];
[self.captureSession addInput:self.frontCameraInput];
}
}else {
[self.captureSession removeInput:self.frontCameraInput];
if ([self.captureSession canAddInput:self.backCameraInput]) {
//[self changeCameraAnimation];
[self.captureSession addInput:self.backCameraInput];
}
}
//提交会话配置
[self.captureSession commitConfiguration];
[self startRecordFunction];
}
#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(@"视频录制完成.");
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
[self startCapture];
//视频录入完成之后在后台将视频存储到相
// [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
// } completionHandler:^(BOOL success, NSError * _Nullable error) {
// if (error) {
// NSLog(@"保存视频到相簿过程中发生错误,错误信息:%@",error.localizedDescription);
// }else {
// NSLog(@"成功保存视频到相簿.");
// }
// }];
}
-(void)saveAllVideoToPoto {
NSArray *arr = [self getAllFile];
for (NSString *str in arr) {
NSURL *fileUrl=[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",[self getVideoPathCache],str]];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:fileUrl];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (error) {
NSLog(@"保存视频到相簿过程中发生错误,错误信息:%@",error.localizedDescription);
}else {
NSLog(@"成功保存视频到相簿.");
}
}];
}
}
-(void)deleteAllVideo {
NSArray *arr = [self getAllFile];
for (NSString *str in arr) {
NSString *file = [NSString stringWithFormat:@"%@/%@",[self getVideoPathCache],str];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL is = [fileManager removeItemAtPath:file error:nil];
if (!is) {
NSLog(@"删除文件错误");
}
}
}
#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;
}
-(NSArray *)getAllFile {
NSArray *files = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:[self getVideoPathCache] error:nil];
return files;
}
#pragma mark - Device init Method
//捕获到的视频呈现的layer
- (AVCaptureVideoPreviewLayer *)previewLayer {
if (_previewLayer == nil) {
//通过AVCaptureSession初始化
AVCaptureVideoPreviewLayer *preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
//设置比例为铺满全屏
preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
_previewLayer = preview;
}
return _previewLayer;
}
//捕获视频的会话
- (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];
}
//照片输出流
if ([_captureSession canAddOutput:self.stillImageOutput]) {
[_captureSession addOutput:self.stillImageOutput];
}
//设置视频录制的方向
self.videoConnection.videoOrientation = AVCaptureVideoOrientationPortrait;
}
return _captureSession;
}
//后置摄像头输入
- (AVCaptureDeviceInput *)backCameraInput {
if (_backCameraInput == nil) {
NSError *error;
_backCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backCamera] error:&error];
if (error) {
NSLog(@"获取后置摄像头失败~%d",[self isAvailableWithCamera]);
}
}
return _backCameraInput;
}
//前置摄像头输入
- (AVCaptureDeviceInput *)frontCameraInput {
if (_frontCameraInput == nil) {
NSError *error;
_frontCameraInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self frontCamera] error:&error];
if (error) {
NSLog(@"获取前置摄像头失败~");
}
}
return _frontCameraInput;
}
//麦克风输入
- (AVCaptureDeviceInput *)audioMicInput {
if (_audioMicInput == nil) {
AVCaptureDevice *mic = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error;
_audioMicInput = [AVCaptureDeviceInput deviceInputWithDevice:mic error:&error];
if (error) {
NSLog(@"获取麦克风失败~%d",[self isAvailableWithMic]);
}
}
return _audioMicInput;
}
//照片输出流
-(AVCaptureStillImageOutput *)stillImageOutput {
if (!_stillImageOutput) {
_stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
// 这是输出流的设置参数AVVideoCodecJPEG参数表示以JPEG的图片格式输出图片
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
[_stillImageOutput setOutputSettings:outputSettings];
}
return _stillImageOutput;
}
//初始化设备输出对象,用于获得输出数据
- (AVCaptureMovieFileOutput *)captureMovieFileOutput
{
if(_captureMovieFileOutput == nil)
{
_captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc]init];
}
return _captureMovieFileOutput;
}
//视频连接
- (AVCaptureConnection *)videoConnection {
_videoConnection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
if ([_videoConnection isVideoStabilizationSupported ]) {
_videoConnection.preferredVideoStabilizationMode=AVCaptureVideoStabilizationModeAuto;
}
return _videoConnection;
}
//返回前置摄像头
- (AVCaptureDevice *)frontCamera {
return [self cameraWithPosition:AVCaptureDevicePositionFront];
}
//返回后置摄像头
- (AVCaptureDevice *)backCamera {
return [self cameraWithPosition:AVCaptureDevicePositionBack];
}
//用来返回是前置摄像头还是后置摄像头
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition) position {
//返回和视频录制相关的所有默认设备
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
//遍历这些设备返回跟position相关的设备
for (AVCaptureDevice *device in devices) {
if ([device position] == position) {
return device;
}
}
return nil;
}
@end
@implementation CameraTool(Authorization)
- (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;
}
@end
我的业余技术微信公众号:YKJGZH,欢迎大家进入