ios 相机 录视频和拍照的封装 保存到相册

使用:

@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,欢迎大家进入

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值