|
@@ -0,0 +1,661 @@
|
|
|
+//
|
|
|
+// KSVideoRecordViewController.m
|
|
|
+// MusicGradeExam
|
|
|
+//
|
|
|
+// Created by Kyle on 2020/10/16.
|
|
|
+// Copyright © 2020 DayaMusic. All rights reserved.
|
|
|
+//
|
|
|
+
|
|
|
+#import "KSVideoRecordViewController.h"
|
|
|
+#import "AppDelegate.h"
|
|
|
+#import "UIDevice+TFDevice.h"
|
|
|
+#import <AVFoundation/AVFoundation.h>
|
|
|
+#import <AssetsLibrary/AssetsLibrary.h>
|
|
|
+#import "KSNormalAlertView.h"
|
|
|
+#import "SubjectImageModel.h"
|
|
|
+#import "TZImageManager.h"
|
|
|
+
|
|
|
+@interface KSVideoRecordViewController ()<AVCaptureFileOutputRecordingDelegate>
|
|
|
+
|
|
|
+//会话 负责输入和输出设备之间的数据传递
|
|
|
+@property (nonatomic, strong) AVCaptureSession *captureSession;
|
|
|
+
|
|
|
+@property (nonatomic, strong) AVCaptureDeviceInput *videoCaptureDeviceInput;
|
|
|
+@property (nonatomic, strong) AVCaptureDeviceInput *audioCaptureDeviceInput;
|
|
|
+
|
|
|
+// 视频流输出
|
|
|
+@property (nonatomic, strong) AVCaptureMovieFileOutput *captureMovieFileOutput;
|
|
|
+
|
|
|
+// 相机拍摄预览图层
|
|
|
+@property (nonatomic, strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;
|
|
|
+
|
|
|
+// 自定义UI控件容器
|
|
|
+@property (nonatomic, strong) UIView *viewContainer;
|
|
|
+// 录制时常
|
|
|
+@property (nonatomic, strong) UILabel *timeLabel;
|
|
|
+
|
|
|
+// 计时器
|
|
|
+@property (nonatomic, strong) NSTimer *timer;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIButton *bottomButton;
|
|
|
+
|
|
|
+@property (nonatomic, strong) SubjectImageModel *guideImageModel;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIImageView *tipsImage;
|
|
|
+
|
|
|
+@property (nonatomic, assign) NSInteger prepareTime;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isPrepare;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *bottomCountLabel;
|
|
|
+
|
|
|
+@property (nonatomic, assign) NSInteger currentRecordIndex;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *topTipsLabel;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIView *topTipsView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIImageView *warningImage;
|
|
|
+
|
|
|
+@property (nonatomic, assign) NSInteger duration;
|
|
|
+
|
|
|
+@property (nonatomic, copy) VideoRecordBlock callback;
|
|
|
+
|
|
|
+@property (nonatomic, strong) NSMutableArray *videoAssetArray;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isStartExam;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isRecording;
|
|
|
+
|
|
|
+@property (nonatomic, assign) BOOL isQuiting;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UIView *songCardView;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *subjectLabel;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *songTitle;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *songNameLabel;
|
|
|
+
|
|
|
+@property (nonatomic, strong) UILabel *songTimeLabel;
|
|
|
+
|
|
|
+@property (nonatomic, assign) NSInteger songCountTime;
|
|
|
+
|
|
|
+@end
|
|
|
+
|
|
|
+@implementation KSVideoRecordViewController
|
|
|
+
|
|
|
+- (void)viewWillAppear:(BOOL)animated {
|
|
|
+ [super viewWillAppear:animated];
|
|
|
+ self.zh_statusBarHidden = YES;
|
|
|
+ // 切换到横屏
|
|
|
+ AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
|
|
|
+ delegate.allowAutoRotate = YES;
|
|
|
+ [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight];
|
|
|
+ [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)viewWillDisappear:(BOOL)animated {
|
|
|
+ [super viewWillDisappear:animated];
|
|
|
+ // 竖屏
|
|
|
+ AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
|
|
|
+ delegate.allowAutoRotate = NO;
|
|
|
+ [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait];
|
|
|
+ [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
|
|
|
+ self.zh_statusBarHidden = NO;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)viewDidLoad {
|
|
|
+ [super viewDidLoad];
|
|
|
+ // Do any additional setup after loading the view.
|
|
|
+ self.view.backgroundColor = HexRGB(0x141414);
|
|
|
+ [self configMessage];
|
|
|
+ // 切换到横屏
|
|
|
+ AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
|
|
|
+ delegate.allowAutoRotate = YES;
|
|
|
+ [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight];
|
|
|
+ [self configUI];
|
|
|
+ [self.timer setFireDate:[NSDate distantPast]];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configMessage {
|
|
|
+ self.prepareTime = 10;
|
|
|
+ self.currentRecordIndex = 0;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configUI {
|
|
|
+ _captureSession = [[AVCaptureSession alloc] init];
|
|
|
+ // 初始化会话对象
|
|
|
+ if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetInputPriority]) {
|
|
|
+ _captureSession.sessionPreset = AVCaptureSessionPresetInputPriority;
|
|
|
+ }
|
|
|
+ NSError *error = nil;
|
|
|
+
|
|
|
+ // 获取视频输出对象
|
|
|
+ AVCaptureDevice *videoCaptureDevice = [self cameraDeviceWithPosition:(AVCaptureDevicePositionBack)];
|
|
|
+ if (!videoCaptureDevice) {
|
|
|
+ NSLog(@"获取后置摄像头失败!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _videoCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoCaptureDevice error:&error];
|
|
|
+ if (error) {
|
|
|
+ NSLog(@"取得视频设备输入对象错误");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取音频输入对象
|
|
|
+ AVCaptureDevice *audioCaptureDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
|
|
|
+ _audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
|
|
|
+ if (error) {
|
|
|
+ NSLog(@"取得音频设备输入对象时出错");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化设备输出对象
|
|
|
+ _captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
|
|
|
+ //将设备输入添加到会话中
|
|
|
+ if ([_captureSession canAddInput:_videoCaptureDeviceInput]) {
|
|
|
+ [_captureSession addInput:_videoCaptureDeviceInput];
|
|
|
+ [_captureSession addInput:_audioCaptureDeviceInput];
|
|
|
+
|
|
|
+ //防抖功能
|
|
|
+ AVCaptureConnection *captureConnection = [_captureMovieFileOutput connectionWithMediaType:AVMediaTypeAudio];
|
|
|
+ if ([captureConnection isVideoStabilizationSupported]) {
|
|
|
+ captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //将设备输出添加到会话中
|
|
|
+ if ([_captureSession canAddOutput:_captureMovieFileOutput]) {
|
|
|
+ [_captureSession addOutput:_captureMovieFileOutput];
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建视频预览图层
|
|
|
+ _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
|
|
|
+ self.viewContainer.layer.masksToBounds = YES;
|
|
|
+ _captureVideoPreviewLayer.frame = self.viewContainer.bounds;
|
|
|
+ _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
|
|
+ _captureVideoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
|
|
|
+ [self.view.layer addSublayer:_captureVideoPreviewLayer];
|
|
|
+
|
|
|
+ [self.view addSubview:self.viewContainer];
|
|
|
+ [self configSongCardView];
|
|
|
+ self.songCardView.hidden = YES;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configSongCardView {
|
|
|
+ [self.view addSubview:self.songCardView];
|
|
|
+ [self.songCardView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.width.mas_equalTo(180);
|
|
|
+ make.right.mas_equalTo(self.view.mas_right);
|
|
|
+ make.centerY.mas_equalTo(self.view.mas_centerY);
|
|
|
+ }];
|
|
|
+ self.songCardView.layer.cornerRadius = 5.0f;
|
|
|
+
|
|
|
+ [self.songCardView addSubview:self.subjectLabel];
|
|
|
+ self.subjectLabel.text = [NSString stringWithFormat:@"%@,%@", self.subjectName, self.leverName];
|
|
|
+ [self.subjectLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(self.songCardView.mas_left).offset(10);
|
|
|
+ make.right.mas_equalTo(self.songCardView.mas_right).offset(10);
|
|
|
+ make.top.mas_equalTo(self.songCardView.mas_top).offset(10);
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ }];
|
|
|
+ [self.songCardView addSubview:self.songTitle];
|
|
|
+ [self.songTitle mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(self.songCardView.mas_left).offset(10);
|
|
|
+ make.right.mas_equalTo(self.songCardView.mas_right).offset(10);
|
|
|
+ make.top.mas_equalTo(self.subjectLabel.mas_bottom).offset(10);
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.songCardView addSubview:self.songNameLabel];
|
|
|
+ self.songNameLabel.text = [self.songMessageArray firstObject];
|
|
|
+ [self.songNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(self.songCardView.mas_left).offset(10);
|
|
|
+ make.right.mas_equalTo(self.songCardView.mas_right).offset(10);
|
|
|
+ make.top.mas_equalTo(self.songTitle.mas_bottom).offset(10);
|
|
|
+ }];
|
|
|
+
|
|
|
+ [self.songCardView addSubview:self.songTimeLabel];
|
|
|
+ [self.songTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(self.songCardView.mas_left).offset(10);
|
|
|
+ make.right.mas_equalTo(self.songCardView.mas_right).offset(10);
|
|
|
+ make.top.mas_equalTo(self.songNameLabel.mas_bottom).offset(10);
|
|
|
+ make.bottom.mas_equalTo(self.songCardView.mas_bottom).offset(-10);
|
|
|
+ }];
|
|
|
+
|
|
|
+ self.songCountTime = self.singleSongRecordMinutes * 60;
|
|
|
+ self.songTimeLabel.text = [NSString stringWithFormat:@"当前曲目剩余时间:%zds",self.songCountTime];
|
|
|
+}
|
|
|
+
|
|
|
+-(void)viewDidAppear:(BOOL)animated{
|
|
|
+ [super viewDidAppear:animated];
|
|
|
+ [self.captureSession startRunning];
|
|
|
+}
|
|
|
+
|
|
|
+-(void)viewDidDisappear:(BOOL)animated{
|
|
|
+ [super viewDidDisappear:animated];
|
|
|
+ [self.captureSession stopRunning];
|
|
|
+ [self stopDurationTimer];
|
|
|
+}
|
|
|
+#pragma mark ---- buttonAction
|
|
|
+- (void)bottomButtonAction:(UIButton *)sender {
|
|
|
+
|
|
|
+ if ([sender.titleLabel.text isEqualToString:@"已就位"]) {
|
|
|
+ [sender setTitle:@"开始考级" forState:UIControlStateNormal];
|
|
|
+ }
|
|
|
+ else if ([sender.titleLabel.text isEqualToString:@"开始考级"]) {
|
|
|
+ self.isPrepare = YES;
|
|
|
+ self.topTipsLabel.text = @"请考生在10秒内就位演奏";
|
|
|
+ self.topTipsView.hidden = NO;
|
|
|
+ self.bottomCountLabel.hidden = NO;
|
|
|
+ if (self.currentRecordIndex + 1 == self.songMessageArray.count) {
|
|
|
+ [sender setTitle:@"完成录制" forState:UIControlStateNormal];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [sender setTitle:@"下一首" forState:UIControlStateNormal];
|
|
|
+ }
|
|
|
+ sender.hidden = YES;
|
|
|
+ }
|
|
|
+ else if ([sender.titleLabel.text isEqualToString:@"下一首"]) {
|
|
|
+
|
|
|
+ [KSNormalAlertView ks_showAlertWithTitle:@"确定切换下一曲吗?" leftTitle:@"取消" rightTitle:@"确定" cancel:^{
|
|
|
+
|
|
|
+ } confirm:^{
|
|
|
+ self.currentRecordIndex++;
|
|
|
+ self.topTipsLabel.text = @"请考生在10秒内就位演奏";
|
|
|
+ self.prepareTime = 10;
|
|
|
+ self.isPrepare = YES;
|
|
|
+ [self.captureMovieFileOutput stopRecording];
|
|
|
+ if (self.currentRecordIndex + 1 == self.songMessageArray.count) {
|
|
|
+ [sender setTitle:@"完成录制" forState:UIControlStateNormal];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ [sender setTitle:@"下一首" forState:UIControlStateNormal];
|
|
|
+ }
|
|
|
+ sender.hidden = YES;
|
|
|
+ }];
|
|
|
+
|
|
|
+ }
|
|
|
+ else if ([sender.titleLabel.text isEqualToString:@"完成录制"]) {
|
|
|
+ [KSNormalAlertView ks_showAlertWithTitle:@"确定完成录制吗?" leftTitle:@"取消" rightTitle:@"确定" cancel:^{
|
|
|
+
|
|
|
+ } confirm:^{
|
|
|
+ // 退出录播 返回数据
|
|
|
+ if (self.isRecording) {
|
|
|
+ if ([self.captureMovieFileOutput isRecording]) {
|
|
|
+ [self.captureMovieFileOutput stopRecording];
|
|
|
+ }
|
|
|
+ self.isQuiting = YES;
|
|
|
+ [MBProgressHUD ksShowHUDWithText:@"视频保存中..."];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.callback(VIDEORECORDACTION_BACK, self.videoAssetArray);
|
|
|
+ [self quitRecordExam];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setCurrentRecordIndex:(NSInteger)currentRecordIndex {
|
|
|
+ _currentRecordIndex = currentRecordIndex;
|
|
|
+ self.songCountTime = self.singleSongRecordMinutes * 60;
|
|
|
+ self.songTimeLabel.text = [NSString stringWithFormat:@"当前曲目剩余时间:%zds",self.songCountTime];
|
|
|
+ if (self.songMessageArray.count > currentRecordIndex) {
|
|
|
+ NSString *songName = self.songMessageArray[currentRecordIndex];
|
|
|
+ self.songNameLabel.text = songName;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+#pragma mark -------- AVCaptureFileOutputRecordingDelegate ----------
|
|
|
+- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections {
|
|
|
+ NSLog(@"开始录制");
|
|
|
+ _isRecording = YES;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
|
|
|
+ NSLog(@"录制结束");
|
|
|
+ // 是否保存到相册
|
|
|
+ [[TZImageManager manager] saveVideoWithUrl:outputFileURL completion:^(PHAsset *asset, NSError *error) {
|
|
|
+ self.isRecording = NO;
|
|
|
+ // 删除文件
|
|
|
+ [self removeVideoWithPath:outputFileURL.path];
|
|
|
+ // 记录当前相册asset
|
|
|
+ [self.videoAssetArray addObject:asset];
|
|
|
+ if (self.isQuiting) { // 保存完成退出
|
|
|
+ [MBProgressHUD ksHideHUD];
|
|
|
+ self.callback(VIDEORECORDACTION_BACK, self.videoAssetArray);
|
|
|
+ [self quitRecordExam];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)removeVideoWithPath:(NSString *)videoUrl {
|
|
|
+ NSFileManager *fileMamager = [NSFileManager defaultManager];
|
|
|
+ if ([fileMamager fileExistsAtPath:videoUrl]) {
|
|
|
+ [fileMamager removeItemAtPath:videoUrl error:nil];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**取得指定位置的摄像头*/
|
|
|
+- (AVCaptureDevice *)cameraDeviceWithPosition:(AVCaptureDevicePosition)position {
|
|
|
+ NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
|
|
+ for (AVCaptureDevice *camera in cameras) {
|
|
|
+ if ([camera position] == position) {
|
|
|
+ return camera;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark ---- lazying
|
|
|
+// 乐曲卡片
|
|
|
+- (UIView *)songCardView {
|
|
|
+ if (!_songCardView) {
|
|
|
+ _songCardView = [[UIView alloc] init];
|
|
|
+ _songCardView.backgroundColor = HexRGBAlpha(0x141414, 0.5f);
|
|
|
+ }
|
|
|
+ return _songCardView;
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)subjectLabel {
|
|
|
+ if (!_subjectLabel) {
|
|
|
+ _subjectLabel = [[UILabel alloc] init];
|
|
|
+ _subjectLabel.textColor = HexRGB(0xffffff);
|
|
|
+ _subjectLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ }
|
|
|
+ return _subjectLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)songTitle {
|
|
|
+ if (!_songTitle) {
|
|
|
+ _songTitle = [[UILabel alloc] init];
|
|
|
+ _songTitle.textColor = THEMECOLOR;
|
|
|
+ _songTitle.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ _songTitle.text = @"当前曲目:";
|
|
|
+ }
|
|
|
+ return _songTitle;
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)songNameLabel {
|
|
|
+ if (!_songNameLabel) {
|
|
|
+ _songNameLabel = [[UILabel alloc] init];
|
|
|
+ _songNameLabel.textColor = HexRGB(0xffffff);
|
|
|
+ _songNameLabel.numberOfLines = 0;
|
|
|
+ _songNameLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ }
|
|
|
+ return _songNameLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)songTimeLabel {
|
|
|
+ if (!_songTimeLabel) {
|
|
|
+ _songTimeLabel = [[UILabel alloc] init];
|
|
|
+ _songTimeLabel.textColor = HexRGB(0xffffff);
|
|
|
+ _songTimeLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ }
|
|
|
+ return _songTimeLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableArray *)videoAssetArray {
|
|
|
+ if (!_videoAssetArray) {
|
|
|
+ _videoAssetArray = [NSMutableArray arrayWithCapacity:self.songMessageArray.count];
|
|
|
+ }
|
|
|
+ return _videoAssetArray;
|
|
|
+}
|
|
|
+- (UILabel *)timeLabel {
|
|
|
+ if (!_timeLabel) {
|
|
|
+ _timeLabel = [[UILabel alloc] init];
|
|
|
+ _timeLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ _timeLabel.textColor = HexRGB(0xffffff);
|
|
|
+
|
|
|
+ }
|
|
|
+ return _timeLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)configTime:(NSInteger)subTime recordFinishBlock:(VideoRecordBlock)block {
|
|
|
+ if (block) {
|
|
|
+ self.callback = block;
|
|
|
+ }
|
|
|
+ self.duration = subTime;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setDuration:(NSInteger)duration {
|
|
|
+ _duration = duration;
|
|
|
+ if (_duration < 300) {
|
|
|
+// self.timeLabel.textColor = HexRGB(0xff3535);
|
|
|
+ }
|
|
|
+ if (_duration < 0) {
|
|
|
+ [self stopDurationTimer];
|
|
|
+ if (self.callback) {
|
|
|
+ self.callback(VIDEORECORDACTION_OVER,self.videoAssetArray);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+- (void)stopDurationTimer {
|
|
|
+ [self.timer setFireDate:[NSDate distantFuture]];
|
|
|
+ if (self.timer.valid) {
|
|
|
+ [self.timer invalidate];
|
|
|
+ self.timer = nil;
|
|
|
+ }
|
|
|
+}
|
|
|
+- (NSString *)formatTime {
|
|
|
+
|
|
|
+ if (self.duration < 0) {
|
|
|
+ return @"00分00秒";
|
|
|
+ }
|
|
|
+ NSInteger durationInteger = self.duration--;
|
|
|
+ NSInteger durationS = durationInteger % 60;
|
|
|
+ NSInteger durationM = (durationInteger - durationS) / 60;
|
|
|
+ NSString *minuteStr = [NSString stringWithFormat:@"%02ld", durationM];
|
|
|
+ NSString *secondStr = [NSString stringWithFormat:@"%02ld", durationS];
|
|
|
+
|
|
|
+ return [NSString stringWithFormat:@"%@分%@秒", minuteStr, secondStr];
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)topTipsLabel {
|
|
|
+ if (!_topTipsLabel) {
|
|
|
+ _topTipsLabel = [[UILabel alloc] init];
|
|
|
+ _topTipsLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ _topTipsLabel.textColor = HexRGB(0x00ffef);
|
|
|
+ }
|
|
|
+ return _topTipsLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (NSTimer *)timer {
|
|
|
+ if (_timer == nil) {
|
|
|
+ _timer = [NSTimer scheduledTimerWithTimeInterval:1
|
|
|
+ target:self
|
|
|
+ selector:@selector(timeFunction:)
|
|
|
+ userInfo:nil
|
|
|
+ repeats:YES];
|
|
|
+ [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
|
|
|
+ }
|
|
|
+ return _timer;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)timeFunction:(NSTimer *)timer {
|
|
|
+ if (self.isPrepare) {
|
|
|
+ if (self.prepareTime > 0) {
|
|
|
+ self.bottomCountLabel.text = [NSString stringWithFormat:@"%zds",self.prepareTime];
|
|
|
+ self.bottomCountLabel.hidden = NO;
|
|
|
+ self.prepareTime--;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.isStartExam = YES;
|
|
|
+ self.isPrepare = NO;
|
|
|
+ self.topTipsLabel.text = @"正在考级,学生必须保持在画面之内";
|
|
|
+ self.songCardView.hidden = NO;
|
|
|
+ self.bottomCountLabel.hidden = YES;
|
|
|
+ self.bottomButton.hidden = NO;
|
|
|
+ NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"VideoData"];
|
|
|
+ NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
+ BOOL isDir = FALSE;
|
|
|
+ BOOL isDirExist = [fileManager fileExistsAtPath:path isDirectory:&isDir];
|
|
|
+ if(!(isDirExist && isDir)) {
|
|
|
+ BOOL bCreateDir = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
|
|
|
+ if(!bCreateDir){
|
|
|
+ NSLog(@"创建文件夹失败!");
|
|
|
+ }
|
|
|
+ NSLog(@"创建文件夹成功,文件路径%@",path);
|
|
|
+ }
|
|
|
+ NSString *songName = [[self.songMessageArray objectAtIndex:self.currentRecordIndex] MD5];
|
|
|
+ NSString *fileName = [NSString stringWithFormat:@"%@.mp4",songName];
|
|
|
+ NSString *filePath = [path stringByAppendingPathComponent:fileName];
|
|
|
+ NSLog(@"%@",filePath);
|
|
|
+ [self.captureMovieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:filePath] recordingDelegate:self];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (_isStartExam) {
|
|
|
+ self.songCountTime--;
|
|
|
+ if (self.songCountTime >= 0) {
|
|
|
+ self.songTimeLabel.text = [NSString stringWithFormat:@"当前曲目剩余时间:%zds",self.songCountTime];
|
|
|
+ }
|
|
|
+ if (self.songCountTime == 0) {
|
|
|
+ _isStartExam = NO;
|
|
|
+ // 切换下一曲
|
|
|
+ [self bottomButtonAction:self.bottomButton];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ self.timeLabel.text = [NSString stringWithFormat:@"考级剩余:%@",[self formatTime]];
|
|
|
+}
|
|
|
+
|
|
|
+- (UIImageView *)tipsImage {
|
|
|
+ if (!_tipsImage) {
|
|
|
+ _tipsImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
|
|
|
+ }
|
|
|
+ return _tipsImage;
|
|
|
+}
|
|
|
+
|
|
|
+- (SubjectImageModel *)guideImageModel {
|
|
|
+ if (!_guideImageModel) {
|
|
|
+ _guideImageModel = [[SubjectImageModel alloc] init];
|
|
|
+ _guideImageModel.subjectName = self.subjectName;
|
|
|
+ }
|
|
|
+ return _guideImageModel;
|
|
|
+}
|
|
|
+- (UIButton *)bottomButton {
|
|
|
+ if (!_bottomButton) {
|
|
|
+ _bottomButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
+ [_bottomButton setTitle:@"已就位" forState:UIControlStateNormal];
|
|
|
+ _bottomButton.frame = CGRectMake(kScreenWidth - 120 - 20, 10, 120, 44);
|
|
|
+ _bottomButton.layer.cornerRadius = 22;
|
|
|
+ _bottomButton.titleLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ _bottomButton.backgroundColor = HexRGB(0xff5a5a);
|
|
|
+ [_bottomButton addTarget:self action:@selector(bottomButtonAction:) forControlEvents:UIControlEventTouchUpInside];
|
|
|
+ }
|
|
|
+ return _bottomButton;
|
|
|
+}
|
|
|
+
|
|
|
+- (UIView *)topTipsView {
|
|
|
+ if (!_topTipsView) {
|
|
|
+ _topTipsView = [[UIView alloc] init];
|
|
|
+ _warningImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"warning_image"]];
|
|
|
+ _warningImage.frame = CGRectMake(0, 4, 14, 12);
|
|
|
+ [_topTipsView addSubview:_warningImage];
|
|
|
+ [_topTipsView addSubview:self.topTipsLabel];
|
|
|
+ }
|
|
|
+ return _topTipsView;
|
|
|
+}
|
|
|
+
|
|
|
+- (UIView *)viewContainer {
|
|
|
+ if (!_viewContainer) {
|
|
|
+ _viewContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
|
|
|
+
|
|
|
+ // 声部示意图
|
|
|
+ NSString *tipsImageName = self.guideImageModel.guideImage;
|
|
|
+ if (![NSString isEmptyString:tipsImageName]) {
|
|
|
+ [self.tipsImage setImage:[UIImage imageNamed:tipsImageName]];
|
|
|
+ [self.viewContainer addSubview:self.tipsImage];
|
|
|
+ }
|
|
|
+
|
|
|
+ UIView *headView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 64)];
|
|
|
+ headView.backgroundColor = HexRGBAlpha(0x141414, 0.5f);
|
|
|
+ [_viewContainer addSubview:headView];
|
|
|
+
|
|
|
+ UIButton *cancleButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
+ cancleButton.frame = CGRectMake(kScreenWidth - 120 - iPhoneXSafeBottomMargin, 0, 120, 64);
|
|
|
+ cancleButton.titleLabel.font = [UIFont systemFontOfSize:14.0f];
|
|
|
+ [cancleButton addTarget:self action:@selector(cancleRecordAction) forControlEvents:UIControlEventTouchUpInside];
|
|
|
+ [cancleButton setTitle:@"放弃本次录制" forState:UIControlStateNormal];
|
|
|
+ [headView addSubview:cancleButton];
|
|
|
+ [headView addSubview:self.topTipsView];
|
|
|
+ [self.topTipsView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.centerX.mas_equalTo(headView.mas_centerX);
|
|
|
+ make.centerY.mas_equalTo(headView.mas_centerY);
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ }];
|
|
|
+ [self.topTipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.top.bottom.right.mas_equalTo(self.topTipsView);
|
|
|
+ make.left.mas_equalTo(self.warningImage.mas_right).offset(5);
|
|
|
+ }];
|
|
|
+ self.topTipsView.hidden = YES;
|
|
|
+ [headView addSubview:self.timeLabel];
|
|
|
+ [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.left.mas_equalTo(headView.mas_left).offset(15);
|
|
|
+ make.centerY.mas_equalTo(headView.mas_centerY);
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ }];
|
|
|
+
|
|
|
+
|
|
|
+ UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, kScreenHeight - 64, kScreenWidth, 64)];
|
|
|
+ bottomView.backgroundColor = HexRGBAlpha(0x141414, 0.5f);
|
|
|
+ [_viewContainer addSubview:bottomView];
|
|
|
+
|
|
|
+ [bottomView addSubview:self.bottomButton];
|
|
|
+
|
|
|
+ [bottomView addSubview:self.bottomCountLabel];
|
|
|
+ [self.bottomCountLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
+ make.height.mas_equalTo(20);
|
|
|
+ make.center.mas_equalTo(bottomView);
|
|
|
+ make.width.mas_equalTo(40);
|
|
|
+ }];
|
|
|
+ self.bottomCountLabel.hidden = YES;
|
|
|
+ }
|
|
|
+ return _viewContainer;
|
|
|
+}
|
|
|
+
|
|
|
+- (UILabel *)bottomCountLabel {
|
|
|
+ if (!_bottomCountLabel) {
|
|
|
+ _bottomCountLabel = [[UILabel alloc] init];
|
|
|
+ _bottomCountLabel.textColor = [UIColor whiteColor];
|
|
|
+ _bottomCountLabel.font = [UIFont systemFontOfSize:16.0f];
|
|
|
+ }
|
|
|
+ return _bottomCountLabel;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)cancleRecordAction {
|
|
|
+ // 弹窗提示退出房间
|
|
|
+ [KSNormalAlertView ks_showAlertWithTitle:@"确定退出录播吗?" leftTitle:@"取消" rightTitle:@"确定" cancel:^{
|
|
|
+
|
|
|
+ } confirm:^{
|
|
|
+ // 退出录播
|
|
|
+ [self quitRecordExam];
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)quitRecordExam {
|
|
|
+ [self dismissViewControllerAnimated:NO completion:^{
|
|
|
+ if ([self.captureMovieFileOutput isRecording]) {
|
|
|
+ [self.captureMovieFileOutput stopRecording];
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+#pragma mark - Navigation
|
|
|
+
|
|
|
+// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
|
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
|
+ // Get the new view controller using [segue destinationViewController].
|
|
|
+ // Pass the selected object to the new view controller.
|
|
|
+}
|
|
|
+*/
|
|
|
+
|
|
|
+@end
|