iOS 10 AVFoundation錄制采集視頻

//
//  YLPlayerViewController.m
//  YLPlayer
//
//  Created by 譚 on 2019/7/5.
//  Copyright ? 2019 Bksx-cp. All rights reserved.
//

#import "YLPlayerViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/Photos.h>
#import "Masonry.h"

@interface YLPlayerViewController ()<AVCaptureFileOutputRecordingDelegate>
/*
    調配銀飾品輸入輸出之間的數據流
 */
@property (nonatomic,strong) AVCaptureSession *captureSession;
/*
    捕獲的視頻數據預覽圖層
 */
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer;
/*
    輸出數據文件
 */
@property (nonatomic,strong) AVCaptureMovieFileOutput *captureMovieFileOutput;
/*
    捕獲會話中特定捕獲輸入對和捕獲輸出對象之間的連接
 */
@property (nonatomic,strong) AVCaptureConnection *captureConnection;
/*
    輸入輸出設備
 */
@property (nonatomic,strong) AVCaptureDevice *captureDevice;
/*
    設備輸入數據源
 */
@property (nonatomic,strong) AVCaptureDeviceInput *captureDeviceInput;
/*
    音頻設備
 */
@property (nonatomic,strong) AVCaptureDevice *captureAudioDevice;
/*
    音頻輸入設備
 */
@property (nonatomic,strong) AVCaptureDeviceInput *captureAudioDeviceInput;
/*
    控制播放器的播放,暫停,播放速度
 */
@property (nonatomic,strong) AVPlayer *player;
/*
    管理資源對象,提供播放數據源
 */
@property (nonatomic,strong) AVPlayerItem *playerItem;
/*
    負責顯示視頻,如果沒有添加該類,只有聲音沒有畫面
 */
@property (nonatomic,strong) AVPlayerLayer *playerLayer;
@property (nonatomic, strong) UIButton *beginButton;
@property (nonatomic, strong) UILabel *timeLabel;
@property (nonatomic, strong) UIButton *replayButton;
@property (nonatomic, strong) UIButton *saveButton;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) NSInteger timerInteger;
@property (nonatomic, strong) NSURL *videoUrl;
@property (nonatomic, assign) BOOL canSave;
@property (nonatomic, assign) BOOL isPlaying;



@end

@implementation YLPlayerViewController

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    self.navigationController.navigationBarHidden = YES;
    
    [self.captureSession startRunning];
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    self.navigationController.navigationBarHidden = NO;
    if ([self.captureSession isRunning]){
        [self.captureSession stopRunning];
    }
    
    if ([self.timer isValid]){
        [self.timer invalidate];
        self.timer = nil;
    }
}


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.timerInteger = 0;
    self.view.backgroundColor = [UIColor whiteColor];
    
    //獲取授權狀態
    [self getActhorStatus];
    
    [self setupUI];
    
}

- (void)beginVideoConfiguration{
    
    //開啟上下文
    [self addSession];
    
    [self.captureSession beginConfiguration];
    //開啟視頻
    [self addVideo];
    //開啟音頻
    [self addAudio];
    //開始設置預覽圖層
    [self AddPreviewLayer];
    //提交
    [self.captureSession commitConfiguration];
    //開始繪畫 不等于錄制
    [self.captureSession startRunning];
}

//
- (void)addSession{
    self.captureSession = [[AVCaptureSession alloc]init];
    //設置清晰度
    if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]){
        [self.captureSession setSessionPreset:AVCaptureSessionPresetHigh];
    } else{
        [self.captureSession setSessionPreset:AVCaptureSessionPreset1280x720];
    }
    
}
// 視頻
- (void)addVideo{
    AVCaptureDeviceDiscoverySession *disSession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
    
    NSArray *devices = disSession.devices;
    for(AVCaptureDevice *device in devices){
        if(device.position == AVCaptureDevicePositionBack){
            self.captureDevice = device;
        }
    }
    [self addVideoInput];// add
    [self addVideoOutput];//add
    
}

- (void)addVideoInput{
    NSError *error ;
    self.captureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:self.captureDevice error:&error];
    if(error){
        return ;
    }
    // 添加視頻輸入
    if([self.captureSession canAddInput:self.captureDeviceInput]){
        [self.captureSession addInput:self.captureDeviceInput];
    }
}

- (void)addVideoOutput{
    self.captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc]init];
    if([self.captureSession canAddOutput:self.captureMovieFileOutput]){
        [self.captureSession addOutput:self.captureMovieFileOutput];
        
    }
    //設置鏈接管理對象
    
    //設置鏈接管理對象
    AVCaptureConnection *captureConnection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    self.captureConnection = captureConnection;
    //
    captureConnection.videoScaleAndCropFactor = captureConnection.videoMaxScaleAndCropFactor;
    //視頻穩定設置
    if ([captureConnection isVideoStabilizationSupported]){
        captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    }
}

//音頻
- (void)addAudio{
    NSError *error;
    self.captureAudioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    self.captureAudioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.captureAudioDevice error:&error];
    if (error){
        return ;
    }
    
    if ([self.captureSession canAddInput:self.captureAudioDeviceInput]){
        [self.captureSession addInput:self.captureAudioDeviceInput];
    }
}

// 捕獲視頻預覽圖層
- (void)AddPreviewLayer{
    self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
    [self.previewLayer setVideoGravity:AVLayerVideoGravityResizeAspect]; //設置視頻播放的拉伸方式
    self.previewLayer.frame = self.view.frame;
    [self.view.layer addSublayer:self.previewLayer];
}



- (void)setupUI
{
    //開始錄制按鈕
    UIButton *beginButton = [UIButton buttonWithType:UIButtonTypeCustom];
    beginButton.backgroundColor = [UIColor clearColor];
    [beginButton setTitle:@"開始錄制" forState:UIControlStateNormal];
    beginButton.layer.borderColor = [UIColor blueColor].CGColor;
    beginButton.layer.borderWidth = 1.0;
    [beginButton setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
    [beginButton addTarget:self action:@selector(beginButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:beginButton];
    self.beginButton = beginButton;
    
    [beginButton sizeToFit];
    [beginButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.view).offset(-30.0);
        make.centerX.equalTo(self.view);
    }];
    
    //計時標志
    UILabel *timeLabel = [[UILabel alloc] init];
    timeLabel.text = @"0";
    timeLabel.textAlignment = NSTextAlignmentCenter;
    timeLabel.backgroundColor = [UIColor clearColor];
    timeLabel.textColor = [UIColor redColor];
    timeLabel.font = [UIFont boldSystemFontOfSize:20.0];
    [self.view addSubview:timeLabel];
    self.timeLabel = timeLabel;
    
    [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(self.view);
        make.bottom.equalTo(self.beginButton.mas_top).offset(-15.0);
        make.height.equalTo(@25);
        make.width.equalTo(@120);
    }];
    
    //重播按鈕
    UIButton *replayButton = [UIButton buttonWithType:UIButtonTypeCustom];
    replayButton.backgroundColor = [UIColor clearColor];
    [replayButton setTitle:@"預覽播放" forState:UIControlStateNormal];
    replayButton.layer.borderColor = [UIColor blueColor].CGColor;
    replayButton.layer.borderWidth = 1.0;
    [replayButton setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
    [replayButton addTarget:self action:@selector(replayButtonDidClick) forControlEvents:UIControlEventTouchUpInside];
    replayButton.hidden = YES;
    [self.view addSubview:replayButton];
    self.replayButton = replayButton;
    
    [replayButton sizeToFit];
    [replayButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.beginButton.mas_left).offset(-30.0);
        make.centerY.equalTo(self.beginButton);
    }];
    
    //保存按鈕
    UIButton *saveButton = [UIButton buttonWithType:UIButtonTypeCustom];
    saveButton.backgroundColor = [UIColor clearColor];
    [saveButton setTitle:@"保存" forState:UIControlStateNormal];
    saveButton.layer.borderColor = [UIColor blueColor].CGColor;
    saveButton.layer.borderWidth = 1.0;
    [saveButton setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
    [saveButton addTarget:self action:@selector(saveButtonDidClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:saveButton];
    self.saveButton = saveButton;
    
    [saveButton sizeToFit];
    [saveButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.beginButton.mas_right).offset(30.0);
        make.centerY.equalTo(self.beginButton);
    }];
}

#pragma mark --用戶權限
- (void)getActhorStatus{
    //判斷相機和麥克風權限
    NSString *mediaType = AVMediaTypeVideo;//讀取媒體類型
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];//讀取誰唄授權狀態
    if (authStatus == AVAuthorizationStatusAuthorized || authStatus == AVAuthorizationStatusRestricted){
        NSString *errorStr = @"應用相機權限,請在設置中啟用";
        [self showAlertViewWithMessage:errorStr];
        return;
    }
    
    mediaType = AVMediaTypeAudio;// 音頻
    authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
    if (authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){
        NSString *errorStr = @"麥克風權限首先,請在設置中啟用";
        [self showAlertViewWithMessage:errorStr];
        return;
    }
    
    [self beginVideoConfiguration];
}

- (void)showAlertViewWithMessage:(NSString *)message
{
    UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *ensureAction = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    
    [alertVC addAction:ensureAction];
    [alertVC addAction:cancelAction];
    
    [self presentViewController:alertVC animated:YES completion:nil];
}

- (void)loadTimer{
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    self.timer = timer;
}

//視頻保存
- (void)saveVideo:(NSURL *)outputFileURL{
    //判斷是否有相冊權限
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    if (status == PHAuthorizationStatusRestricted || status == PHAuthorizationStatusDenied){
        NSString *errorStr = @"沒有使用相冊的權限,請設置";
        [self showAlertViewWithMessage:errorStr];
        return;
    }
    
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (success){
            NSLog(@"success");
        }
        if (error){
            NSLog(@"保存視頻失敗:%@",error);
            [self.saveButton setTitle:@"保存失敗" forState: UIControlStateNormal];
            [self.saveButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
            self.replayButton.hidden = YES;
        }else{
            NSLog(@"保存視頻到相冊成功");
            [self.saveButton setTitle:@"保存成功" forState: UIControlStateNormal];
            [self.saveButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
            self.replayButton.hidden = NO;
        }
    }];

}

- (NSURL *)outPutFileURL{
    NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"outPut.mov"]];
    return url;
}

//創建預覽視圖
- (void)createPlayView{
    NSLog(@"%@",self.videoUrl);
    [self.previewLayer removeFromSuperlayer];
    self.playerItem = [AVPlayerItem playerItemWithURL:self.videoUrl];
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    self.playerLayer.frame = self.view.frame;
    self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    CALayer *layer = self.view.layer;
    layer.masksToBounds = true;
    [layer addSublayer:_playerLayer];
}

//開始錄制按鈕
- (void)beginButtonDidClick:(UIButton *)button{
    button.enabled = NO;
    NSLog(@"開始錄制按鈕");
    [self loadTimer];
    [self.captureMovieFileOutput startRecordingToOutputFileURL:[self outPutFileURL] recordingDelegate:self];
}

//重播按鈕
- (void)replayButtonDidClick{
    NSLog(@"重新播放按鈕");
    self.replayButton.enabled = NO;
    [self createPlayView];
    
    [self.view bringSubviewToFront:self.saveButton];
    [self.view bringSubviewToFront:self.replayButton];
    [self.view bringSubviewToFront:self.beginButton];
    
    [self.player play];
}

//保存按鈕
- (void)saveButtonDidClick{
    NSLog(@"保存按鈕");
    
    self.saveButton.enabled = NO;
    if (self.timer){
        [self.timer invalidate];
    }
    self.canSave = YES;
    [self.captureSession stopRunning];
    [self.captureMovieFileOutput stopRecording];
}

//定時器
- (void)timerRun{
    NSInteger seconds = self.timerInteger % 60;
    NSInteger minutes = (self.timerInteger / 60) % 60;
    NSInteger hours = self.timerInteger / 3600;
    
    self.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld",hours, minutes, seconds];
    self.timerInteger ++;
}

#pragma mark - AVCaptureFileOutputRecordingDelegate
- (void)captureOutput:(AVCaptureFileOutput *)output didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections{
    
    NSLog(@"--開始錄制--");
    
}

-(void)captureOutput:(AVCaptureFileOutput *)output didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections error:(NSError *)error{
    NSLog(@"--錄制結束-- %@-- %@--",outputFileURL,output.outputFileURL);
    
    if (outputFileURL.absoluteString.length == 0 &&output.outputFileURL.absoluteString.length){
        return;
    }
    
    if (self.canSave){
        self.videoUrl = outputFileURL;
        self.canSave = NO;
        [self saveVideo:self.videoUrl];
    }
    

    
}
@end

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容