123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- //
- // FUVideoRenderViewController.m
- // FULiveDemo
- //
- // Created by 项林平 on 2022/8/8.
- //
- #import "FUVideoRenderViewController.h"
- #import "FUExportVideoView.h"
- #import "FULandmarkManager.h"
- @interface FUVideoRenderViewController ()<FUExportVideoViewDelegate>
- @property (nonatomic, strong) FUGLDisplayView *renderView;
- @property (nonatomic, strong) UIButton *playVideoButton;
- @property (nonatomic, strong) UIButton *downloadButton;
- @property (nonatomic, strong) UILabel *noTrackLabel;
- @property (nonatomic, strong) UILabel *tipLabel;
- @property (nonatomic, strong) FUExportVideoView *exportingView;
- @property (nonatomic, strong) NSURL *videoURL;
- @property (nonatomic, strong) FUVideoRenderViewModel *viewModel;
- @end
- @implementation FUVideoRenderViewController
- #pragma mark - Initializer
- - (instancetype)initWithViewModel:(FUVideoRenderViewModel *)viewModel {
- self = [super init];
- if (self) {
- self.viewModel = viewModel;
- self.viewModel.delegate = self;
- }
- return self;
- }
- #pragma mark - Life cycle
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- [self configureUI];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
-
- [self.viewModel startPreviewing];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- // 添加点位测试开关
- if ([FURenderKitManager sharedManager].showsLandmarks) {
- [FULandmarkManager show];
- }
- }
- - (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
- // 移除点位测试开关
- if ([FURenderKitManager sharedManager].showsLandmarks) {
- [FULandmarkManager dismiss];
- }
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
- }
- #pragma mark - UI
- - (void)configureUI {
- self.view.backgroundColor = [UIColor blackColor];
-
- [self.view addSubview:self.renderView];
- [self.renderView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.leading.trailing.equalTo(self.view);
- if (@available(iOS 11.0, *)) {
- make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop);
- if(FUDeviceIsiPhoneXStyle()) {
- make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).mas_offset(-50);
- } else {
- make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
- }
- } else {
- make.top.equalTo(self.view.mas_top);
- make.bottom.equalTo(self.view.mas_bottom);
- }
- make.leading.trailing.equalTo(self.view);
- }];
-
- UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
- [backButton setImage:[UIImage imageNamed:@"back_item"] forState:UIControlStateNormal];
- [backButton addTarget:self action:@selector(backAction:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:backButton];
- [backButton mas_makeConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop).offset(20);
- } else {
- make.top.equalTo(self.view.mas_top).offset(30);
- }
- make.leading.equalTo(self.view.mas_leading).offset(10);
- make.size.mas_offset(CGSizeMake(44, 44));
- }];
-
- [self.view addSubview:self.noTrackLabel];
- [self.noTrackLabel mas_makeConstraints:^(MASConstraintMaker *make) {
- make.center.equalTo(self.view);
- }];
-
- [self.view addSubview:self.tipLabel];
- [self.tipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
- make.centerY.equalTo(self.view.mas_centerY).mas_offset(24);
- make.centerX.equalTo(self.view);
- make.width.mas_equalTo(300);
- make.height.mas_equalTo(32);
- }];
-
- [self.view addSubview:self.playVideoButton];
- [self.playVideoButton mas_makeConstraints:^(MASConstraintMaker *make) {
- make.center.equalTo(self.view);
- make.size.mas_offset(CGSizeMake(85, 85));
- }];
-
- [self.view addSubview:self.downloadButton];
- [self.downloadButton mas_makeConstraints:^(MASConstraintMaker *make) {
- make.bottom.equalTo(self.view.mas_bottom).offset(-self.viewModel.downloadButtonBottomConstant - 10);
- make.centerX.equalTo(self.view);
- make.size.mas_offset(CGSizeMake(85, 85));
- }];
- }
- #pragma mark - Instance methods
- - (void)updateBottomConstraintsOfDownloadButton:(CGFloat)constraints {
- [self.downloadButton mas_updateConstraints:^(MASConstraintMaker *make) {
- make.bottom.equalTo(self.view.mas_bottom).mas_offset(-constraints-10);
- }];
- [UIView animateWithDuration:0.15 animations:^{
- [self.view layoutIfNeeded];
- }];
- }
- #pragma mark - Private methods
- - (void)showExportVideoView {
- [self.view addSubview:self.exportingView];
- }
- - (void)hideExportVideoView {
- [UIView animateWithDuration:0.3 animations:^{
- self.exportingView.alpha = 0;
- } completion:^(BOOL finished) {
- [self.exportingView removeFromSuperview];
- self.exportingView.alpha = 1;
- [self.exportingView setExportProgress:0];
- // 显示播放按钮
- if (self.playVideoButton.hidden) {
- self.playVideoButton.hidden = NO;
- }
- }];
- }
- #pragma mark - Event response
- - (void)backAction:(UIButton *)sender {
- [self.viewModel destroy];
- [self.navigationController popViewControllerAnimated:YES];
- }
- - (void)playVideoAction:(UIButton *)sender {
- sender.hidden = YES;
- [self.viewModel startReading];
- }
- - (void)downloadAction:(UIButton *)sender {
- // 隐藏播放按钮
- if (!self.playVideoButton.hidden) {
- self.playVideoButton.hidden = YES;
- }
- // 显示导出进度视图
- [self showExportVideoView];
-
- if (self.viewModel.isReading) {
- // 停止播放
- [self.viewModel stopReading];
- }
- if (self.viewModel.isPreviewing) {
- // 停止预览
- [self.viewModel stopPreviewing];
- }
- // 开始重新解码编码
- [self.viewModel startProcessing];
- }
- - (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
- if (error) {
- [FUTipHUD showTips:FULocalizedString(@"保存视频失败") dismissWithDelay:1.5];
- } else {
- [FUTipHUD showTips:FULocalizedString(@"视频已保存到相册") dismissWithDelay:1.5];
- }
- [self hideExportVideoView];
- [self.viewModel startPreviewing];
- }
- - (void)applicationWillResignActive {
- if (self.viewModel.isReading) {
- [self.viewModel stopReading];
- self.playVideoButton.hidden = NO;
- }
- if (self.viewModel.isPreviewing) {
- [self.viewModel stopPreviewing];
- }
- if (self.viewModel.isProcessing) {
- [self.viewModel stopProcessing];
- [self hideExportVideoView];
- }
- }
- - (void)applicationDidBecomeActive {
- [self.viewModel startPreviewing];
- }
- #pragma mark - FUVideoRenderViewModelDelegate
- - (void)videoRenderDidOutputPixelBuffer:(CVPixelBufferRef)pixelBuffer {
- [self.renderView displayPixelBuffer:pixelBuffer];
- }
- - (void)videoRenderDidFinishReading {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.playVideoButton.hidden = NO;
- });
- }
- - (void)videoRenderDidFinishProcessing {
- // 保存视频到相册
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.exportingView setExportProgress:1];
- UISaveVideoAtPathToSavedPhotosAlbum(kFUFinalPath, self, @selector(video:didFinishSavingWithError:contextInfo:), NULL);
- });
- }
- - (void)videoRenderProcessingProgress:(CGFloat)progress {
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.exportingView setExportProgress:progress];
- });
- }
- - (void)videoRenderShouldCheckDetectingStatus:(FUDetectingParts)parts {
- @autoreleasepool {
- BOOL detectingResult = YES;
- switch (parts) {
- case FUDetectingPartsFace:
- detectingResult = [FURenderKitManager faceTracked];
- break;
- case FUDetectingPartsHuman:
- detectingResult = [FURenderKitManager humanTracked];
- break;
- case FUDetectingPartsHand:
- detectingResult = [FURenderKitManager handTracked];
- break;
- default:
- break;
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- self.noTrackLabel.hidden = detectingResult;
- if (!detectingResult) {
- self.noTrackLabel.text = parts == FUDetectingPartsFace ? FULocalizedString(@"未检测到人脸") : (parts == FUDetectingPartsHuman ? FULocalizedString(@"未检测到人体") : FULocalizedString(@"未检测到手势"));
- }
- });
- }
- }
- #pragma mark - FUExportVideoViewDelegate
- - (void)exportVideoViewDidClickCancel {
- [self.viewModel stopProcessing];
- [self hideExportVideoView];
- [self.viewModel startPreviewing];
- }
- #pragma mark - Getters
- - (UIButton *)playVideoButton {
- if (!_playVideoButton) {
- _playVideoButton = [UIButton buttonWithType:UIButtonTypeCustom];
- [_playVideoButton setBackgroundImage:[UIImage imageNamed:@"render_play"] forState:UIControlStateNormal];
- [_playVideoButton addTarget:self action:@selector(playVideoAction:) forControlEvents:UIControlEventTouchUpInside];
- }
- return _playVideoButton;
- }
- - (UIButton *)downloadButton {
- if (!_downloadButton) {
- _downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
- _downloadButton.frame = CGRectMake(CGRectGetWidth(self.view.bounds) / 2.0 - 42.5, CGRectGetHeight(self.view.bounds) - 85 - FUHeightIncludeBottomSafeArea(10), 85, 85);
- _downloadButton.backgroundColor = [UIColor whiteColor];
- _downloadButton.layer.cornerRadius = 42.5;
- [_downloadButton setBackgroundImage:[UIImage imageNamed:@"render_save"] forState:UIControlStateNormal];
- [_downloadButton addTarget:self action:@selector(downloadAction:) forControlEvents:UIControlEventTouchUpInside];
- }
- return _downloadButton;
- }
- - (UILabel *)noTrackLabel {
- if (!_noTrackLabel) {
- _noTrackLabel = [[UILabel alloc] init];
- _noTrackLabel.textColor = [UIColor whiteColor];
- _noTrackLabel.font = [UIFont systemFontOfSize:17];
- _noTrackLabel.text = FULocalizedString(@"未检测到人脸");
- _noTrackLabel.hidden = YES;
- }
- return _noTrackLabel;
- }
- - (UILabel *)tipLabel {
- if (!_tipLabel) {
- _tipLabel = [[UILabel alloc] init];
- _tipLabel.textColor = [UIColor whiteColor];
- _tipLabel.font = [UIFont systemFontOfSize:32];
- _tipLabel.textAlignment = NSTextAlignmentCenter;
- _tipLabel.hidden = YES;
- }
- return _tipLabel;
- }
- - (FUGLDisplayView *)renderView {
- if (!_renderView) {
- _renderView = [[FUGLDisplayView alloc] initWithFrame:self.view.bounds];
- _renderView.contentMode = FUGLDisplayViewContentModeScaleAspectFit;
- _renderView.origintation = (FUGLDisplayViewOrientation)self.viewModel.videoOrientation;
- }
- return _renderView;
- }
- - (FUExportVideoView *)exportingView {
- if (!_exportingView) {
- _exportingView = [[FUExportVideoView alloc] initWithFrame:self.view.bounds];
- _exportingView.delegate = self;
- }
- return _exportingView;
- }
- #pragma mark - Override methods
- - (BOOL)prefersStatusBarHidden {
- return !FUDeviceIsiPhoneXStyle();
- }
- - (UIStatusBarStyle)preferredStatusBarStyle {
- return UIStatusBarStyleLightContent;
- }
- @end
|