123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- //
- // FURenderViewController.m
- // FULiveDemo
- //
- // Created by 项林平 on 2022/7/19.
- // Copyright © 2022 FaceUnity. All rights reserved.
- //
- #import "FURenderViewController.h"
- #import "FUHeadButtonView.h"
- #import "FULightingView.h"
- #import "FUPopupMenu.h"
- #import "FULandmarkManager.h"
- #import "FUInsetsLabel.h"
- @interface FURenderViewController ()<FUPopupMenuDelegate, FULightingViewDelegate>
- /// 渲染视图
- @property (nonatomic, strong) FUGLDisplayView *renderView;
- /// 顶部功能视图
- @property (nonatomic, strong) FUHeadButtonView *headButtonView;
- ///// 拍照和录制视频按钮
- //@property (nonatomic, strong) FUCaptureButton *captureButton;
- /// 曝光度调节器
- @property (nonatomic, strong) FULightingView *lightingView;
- /// 手动对焦指示器
- @property (nonatomic, strong) UIImageView *adjustImageView;
- /// debug信息标签
- @property (nonatomic, strong) FUInsetsLabel *buglyLabel;
- @property (nonatomic, strong) UILabel *noTrackLabel;
- @property (nonatomic, strong) UILabel *tipLabel;
- @property (nonatomic, strong) FURenderViewModel *viewModel;
- @end
- @implementation FURenderViewController {
- // 对焦点击操作记录时间
- CFAbsoluteTime operatedTime;
- }
- #pragma mark - Initializer
- - (instancetype)initWithViewModel:(FURenderViewModel *)viewModel {
- self = [super init];
- if (self) {
- self.viewModel = viewModel;
- self.viewModel.delegate = self;
- }
- return self;
- }
- #pragma mark - Life cycle
- - (void)viewDidLoad {
- [super viewDidLoad];
- // 加载美颜
- if (self.viewModel.needsLoadingBeauty) {
- [[FUBeautyComponentManager sharedManager] loadBeauty];
- }
- [self configureUI];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-
- // 每次进入页面或者返回页面都需要重新设置人脸和人体检测模式
- if (self.viewModel.necessaryAIModelTypes & FUAIModelTypeFace) {
- [FURenderKitManager setFaceProcessorDetectMode:FUFaceProcessorDetectModeVideo];
- }
- if (self.viewModel.necessaryAIModelTypes & FUAIModelTypeHuman) {
- [FURenderKitManager setHumanProcessorDetectMode:FUHumanProcessorDetectModeVideo];
- }
- [self.viewModel startCameraWithRenderView:self.renderView];
- // 添加点位测试开关
- if ([FURenderKitManager sharedManager].showsLandmarks) {
- [FULandmarkManager show];
- }
- [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
- if (@available(iOS 13.0, *)) {
- UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
- appearance.backgroundEffect = nil;
- appearance.shadowColor = [UIColor clearColor];
- appearance.backgroundColor = [UIColor clearColor];
- self.navigationController.navigationBar.standardAppearance = appearance;
- self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
- }else{
- self.navigationController.navigationBar.translucent = YES;
- [self.navigationController.navigationBar setBackgroundColor:[UIColor clearColor]];
- [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:(UIBarMetricsDefault)];
- [self.navigationController.navigationBar setTitleTextAttributes:nil];
- }
-
- }
- - (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
- [self.viewModel stopCamera];
- [self.viewModel resetCameraFocusAndExposureMode];
-
- // 移除点位测试开关
- if ([FURenderKitManager sharedManager].showsLandmarks) {
- [FULandmarkManager dismiss];
- }
- }
- #pragma mark - UI
- - (void)configureUI {
- self.view.backgroundColor = [UIColor colorWithRed:17/255.0 green:18/255.0 blue:38/255.0 alpha:1.0];
-
- [self.view addSubview:self.renderView];
- [self.renderView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.edges.equalTo(self.view);
- }];
- [self.view addSubview:self.magicStickBtn];
- [self.magicStickBtn mas_makeConstraints:^(MASConstraintMaker *make) {
- make.width.height.mas_equalTo(WHScreenEqualWidth(34));
- make.right.equalTo(self.view).offset(WHScreenEqualWidth(-12));
- make.top.equalTo(self.view).offset(WHScreenEqualWidth(113));
- }];
-
- [self.view addSubview:self.headButtonView];
- [self.headButtonView mas_makeConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop).offset(80);
- } else {
- make.top.equalTo(self.view.mas_top).offset(30);
- }
- make.leading.trailing.equalTo(self.view);
- make.height.mas_equalTo(44);
- }];
-
- [self.view addSubview:self.buglyLabel];
- [self.buglyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
- make.top.equalTo(self.headButtonView.mas_bottom).offset(15);
- make.leading.equalTo(self.view).offset(10);
- }];
-
- [self.view addSubview:self.lightingView];
- [self.view addSubview:self.adjustImageView];
-
- [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);
- }];
-
- // [self.view addSubview:self.captureButton];
- // [self.captureButton mas_makeConstraints:^(MASConstraintMaker *make) {
- // make.centerX.equalTo(self.view);
- // make.bottom.equalTo(self.view.mas_bottom).mas_offset(-self.viewModel.captureButtonBottomConstant - 10);
- // make.size.mas_offset(CGSizeMake(81, 81));
- // }];
- }
- #pragma mark - Private methods
- /// 延迟隐藏视图
- - (void)hideFocusAndLightingViewAfterDelay:(NSTimeInterval)deley {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(deley * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
- if (currentTime - self->operatedTime > 1.29) {
- self.lightingView.hidden = YES;
- self.adjustImageView.hidden = YES;
- }
- });
- }
- #pragma mark - Event response
- - (void)renderViewTapAction:(UITapGestureRecognizer *)tap {
- operatedTime = CFAbsoluteTimeGetCurrent();
- self.lightingView.hidden = NO;
- self.adjustImageView.hidden = NO;
- [self.viewModel switchCameraFocusMode:FUCaptureCameraFocusModeChangeless];
- CGPoint center = [tap locationInView:self.renderView];
- CGPoint imageCenter = [tap locationInView:self.view];
- self.adjustImageView.center = imageCenter;
- // 缩放动画
- self.adjustImageView.transform = CGAffineTransformIdentity;
- [UIView animateWithDuration:0.3 animations:^{
- self.adjustImageView.transform = CGAffineTransformMakeScale(0.67, 0.67);
- } completion:^(BOOL finished) {
- [self hideFocusAndLightingViewAfterDelay:1.0];
- }];
- // 根据renderView的填充模式计算图像中心点
- CGPoint pictureCenter;
- CGFloat scale = self.viewModel.inputBufferHeight / self.viewModel.inputBufferWidth;
- CGFloat renderViewWidth = CGRectGetWidth(self.renderView.bounds);
- CGFloat renderViewHeight = CGRectGetHeight(self.renderView.bounds);
- if (self.renderView.contentMode == FUGLDisplayViewContentModeScaleAspectFill) {
- // 短边填满(宽度按比例截取中间部分)
- CGFloat leading = (renderViewHeight / scale - renderViewWidth) / 2.0;
- CGFloat pictureWidth = renderViewWidth + leading * 2;
- center.x += leading;
- if (center.y <= 0) {
- return;
- }
- pictureCenter = CGPointMake(center.y / renderViewHeight, self.viewModel.captureDevicePostion == AVCaptureDevicePositionFront ? center.x / pictureWidth : 1 - center.x / pictureWidth);
- } else if (self.renderView.contentMode == FUGLDisplayViewContentModeScaleAspectFit) {
- // 长边填满(高度上下会留空白)
- CGFloat top = (renderViewHeight - renderViewWidth * scale) / 2.0;
- CGFloat pictureHeight = renderViewHeight - top * 2;
- center.y -= top;
- if (center.y <= 0) {
- return;
- }
- pictureCenter = CGPointMake(center.y / pictureHeight, self.viewModel.captureDevicePostion == AVCaptureDevicePositionFront ? center.x / renderViewWidth : 1 - center.x / renderViewWidth);
- } else {
- // 拉伸填满
- pictureCenter = CGPointMake(center.y / renderViewHeight, self.viewModel.captureDevicePostion == AVCaptureDevicePositionFront ? center.x / renderViewWidth : 1 - center.x / renderViewWidth);
- }
- [self.viewModel setCameraFocusPoint:pictureCenter];
- }
- - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
- if (error) {
- [FUTipHUD showTips:FULocalizedString(@"保存图片失败") dismissWithDelay:1.5];
- } else {
- [FUTipHUD showTips:FULocalizedString(@"图片已保存到相册") dismissWithDelay:1.5];
- }
- }
- - (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];
- }
- }
- #pragma mark - FURenderViewModelDelegate
- - (void)renderDidOutputDebugInformations:(NSString *)informations {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (!self.buglyLabel.hidden) {
- self.buglyLabel.text = informations;
- }
- });
- }
- - (void)renderShouldCheckDetectingStatus:(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 - FULightingViewDelegate
- - (void)lightingViewValueDidChange:(float)value {
- operatedTime = CFAbsoluteTimeGetCurrent();
- [self hideFocusAndLightingViewAfterDelay:1.3];
- [self.viewModel setCameraExposureValue:value];
- }
- #pragma mark - FUHeadButtonViewDelegate
- - (void)headButtonViewBackAction:(UIButton *)btn {
- if (self.viewModel.needsLoadingBeauty) {
- [FUBeautyComponentManager destory];
- }
- // 恢复相机曝光度
- [self.viewModel setCameraExposureValue:0];
- [self.viewModel stopCamera];
- [self.viewModel resetCameraSettings];
- [FURenderKitManager clearItems];
- [self.navigationController popViewControllerAnimated:YES];
- }
- - (void)headButtonViewSegmentedChange:(NSUInteger)index {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [self.viewModel switchCameraOutputFormat];
- });
- }
- //- (void)headButtonViewSelImageAction:(UIButton *)btn {
- // if (!self.viewModel.supportPresetSelection) {
- // // 直接进入图片和视频选择页面
- // FUMediaPickerViewController *picker = [[FUMediaPickerViewController alloc] initWithViewModel:[[FUMediaPickerViewModel alloc] initWithModule:self.viewModel.module]];
- // [self.navigationController pushViewController:picker animated:YES];
- // } else {
- // // 弹出视图
- // CGFloat height;
- // BOOL hideMediaSelection;
- // if (self.viewModel.supportMediaRendering) {
- // // 支持分辨率、图片或视频视图
- // height = 132;
- // hideMediaSelection = NO;
- // } else {
- // // 只支持分辨率视图
- // height = 80;
- // hideMediaSelection = YES;
- // }
- // int selectedPresetIndex = (int)[self.viewModel.presets indexOfObject:self.viewModel.capturePreset];
- // [FUPopupMenu showRelyOnView:btn frame:CGRectMake(17, CGRectGetMaxY(self.headButtonView.frame) + 1, 340, height) defaultSelectedAtIndex:selectedPresetIndex onlyTop:hideMediaSelection dataSource:self.viewModel.presetTitles delegate:self];
- // }
- //}
- - (void)headButtonViewBuglyAction:(UIButton *)btn {
- self.buglyLabel.hidden = !self.buglyLabel.hidden;
- }
- #pragma mark - 切换前置/后置摄像头
- - (void)headButtonViewSwitchAction:(UIButton *)btn {
- btn.userInteractionEnabled = NO;
- dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
- dispatch_after(delayTime, dispatch_get_main_queue(), ^(void){
- btn.userInteractionEnabled = YES;
- });
- [self.viewModel switchCameraBetweenFrontAndRear:self.viewModel.captureDevicePostion != AVCaptureDevicePositionFront unsupportedPresetHandler:^{
- dispatch_async(dispatch_get_main_queue(), ^{
- [FUTipHUD showTips:FULocalizedString(@"设备不支持该分辨率") dismissWithDelay:1.5];
- });
- }];
- }
- - (void)chileHeadButtonViewSwitchAction:(UIButton *)btn {
- [self headButtonViewSwitchAction:btn];
- }
- #pragma mark - FUPopupMenuDelegate
- ///// 选择图片或视频
- //- (void)fuPopupMenuDidSelectedImage {
- // // 直接进入图片和视频选择页面
- // dispatch_async(dispatch_get_main_queue(), ^{
- // FUMediaPickerViewController *picker = [[FUMediaPickerViewController alloc] initWithViewModel:[[FUMediaPickerViewModel alloc] initWithModule:self.viewModel.module]];
- // [self.navigationController pushViewController:picker animated:YES];
- // });
- //}
- /// 分辨率切换
- - (void)fuPopupMenuSegment:(FUSegmentedControl *)segment didSelectedAtIndex:(NSInteger)index {
- segment.userInteractionEnabled = NO;
- AVCaptureSessionPreset selectedPreset = self.viewModel.presets[index];
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [self.viewModel switchCapturePreset:selectedPreset unsupportedPresetHandler:^{
- dispatch_async(dispatch_get_main_queue(), ^{
- [FUTipHUD showTips:FULocalizedString(@"设备不支持该分辨率") dismissWithDelay:1.5];
- });
- }];
- dispatch_async(dispatch_get_main_queue(), ^{
- segment.userInteractionEnabled = YES;
- });
- });
- }
- #pragma mark - Getters
- - (FUGLDisplayView *)renderView {
- if (!_renderView) {
- _renderView = [[FUGLDisplayView alloc] initWithFrame:self.view.bounds];
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(renderViewTapAction:)];
- [_renderView addGestureRecognizer:tap];
- }
- return _renderView;
- }
- - (FUHeadButtonView *)headButtonView {
- if (!_headButtonView) {
- _headButtonView = [[FUHeadButtonView alloc] init];
- _headButtonView.delegate = self;
- _headButtonView.selectedImageButton.hidden = (!self.viewModel.supportMediaRendering && !self.viewModel.supportPresetSelection);
- _headButtonView.segmentedControl.hidden = !self.viewModel.supportSwitchingOutputFormat;
- if (!_headButtonView.hidden) {
- [_headButtonView.selectedImageButton setImage:self.viewModel.supportPresetSelection ? [UIImage imageNamed:@"render_more"] : [UIImage imageNamed:@"render_picture"] forState:UIControlStateNormal];
- }
- [_headButtonView setHidden:YES];
- }
- return _headButtonView;
- }
- - (UIButton *)magicStickBtn{
- if(!_magicStickBtn){
- _magicStickBtn = [[UIButton alloc] init];
- [_magicStickBtn setImage:[UIImage imageNamed:@"WH_Beauty_Magic_Stick_Icon"] forState:UIControlStateNormal];
- [_magicStickBtn addTarget:self action:@selector(showSheetView) forControlEvents:UIControlEventTouchUpInside];
- }
- return _magicStickBtn;
- }
- - (FUInsetsLabel *)buglyLabel {
- if (!_buglyLabel) {
- _buglyLabel = [[FUInsetsLabel alloc] initWithFrame:CGRectZero insets:UIEdgeInsetsMake(5, 5, 5, 5)];
- _buglyLabel.layer.masksToBounds = YES;
- _buglyLabel.layer.cornerRadius = 5;
- _buglyLabel.numberOfLines = 0;
- _buglyLabel.backgroundColor = [UIColor darkGrayColor];
- _buglyLabel.text = @"resolution:\n720x1280\nfps:30\nrender time:\n0ms";
- _buglyLabel.textColor = [UIColor whiteColor];
- _buglyLabel.alpha = 0.74;
- _buglyLabel.font = [UIFont systemFontOfSize:13];
- _buglyLabel.hidden = YES;
- }
- return _buglyLabel;
- }
- - (FULightingView *)lightingView {
- if (!_lightingView) {
- _lightingView = [[FULightingView alloc] initWithFrame:CGRectMake(0, 0, 280, 40)];
- _lightingView.center = CGPointMake(CGRectGetWidth(self.view.bounds) - 20, CGRectGetHeight(self.view.bounds) / 2.0 - 60);
- _lightingView.transform = CGAffineTransformMakeRotation(-M_PI_2);
- _lightingView.slider.minimumValue = -2;
- _lightingView.slider.maximumValue = 2;
- _lightingView.slider.value = 0;
- _lightingView.delegate = self;
- _lightingView.hidden = YES;
- }
- return _lightingView;
- }
- - (UIImageView *)adjustImageView {
- if (!_adjustImageView) {
- _adjustImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"render_adjust"]];
- _adjustImageView.center = self.view.center;
- _adjustImageView.hidden = YES;
- }
- return _adjustImageView;
- }
- - (UILabel *)noTrackLabel {
- if (!_noTrackLabel) {
- _noTrackLabel = [[UILabel alloc] init];
- _noTrackLabel.textColor = [UIColor whiteColor];
- _noTrackLabel.font = [UIFont systemFontOfSize:17];
- _noTrackLabel.textAlignment = NSTextAlignmentCenter;
- _noTrackLabel.text = FULocalizedString(@"No_Face_Tracking");
- _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;
- }
- #pragma mark - Overriding
- - (BOOL)prefersStatusBarHidden {
- return !FUDeviceIsiPhoneXStyle();
- }
- - (UIStatusBarStyle)preferredStatusBarStyle {
- return UIStatusBarStyleLightContent;
- }
- @end
|