//
// 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
iOS 10 AVFoundation錄制采集視頻
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
推薦閱讀更多精彩內容
- 首先了解下AVFoundation AVFoundation框架是ios中很重要的框架,是蘋果 OS X 系統和 ...
- 本章介紹一下視頻采集的實現,主要有功能有1.音、視頻文件錄制播放2.焦距設置3.防抖功能4.攝像頭切換5.手電筒功...
- AVFoundation 查看介紹,蘋果在官方文檔上寫的比較清楚。大概如下圖所示。 AVCaptureSessio...
- 前言 最近剛做完一個直播類的項目,在視頻這塊也有一定研究,下面總結下。 過程 首先視頻項目一般要求定制化,用UII...
- 1、iOS直播技術的流程 從上圖中我們能夠看出直播技術的流程大致可以分為幾個步驟:數據采集、圖像處理(美顏、濾鏡)...