| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- // Copyright (c) 2019 Tencent. All rights reserved.
- #import "SDKHeader.h"
- #import "UGCKitCutViewController.h"
- #import <MediaPlayer/MPMediaPickerController.h>
- #import <AVFoundation/AVFoundation.h>
- #import "UGCKit_UIViewAdditions.h"
- #import "UGCKitProgressHUD.h"
- #import "UGCKitVideoCutView.h"
- #import "UGCKitPlayerView.h"
- #import "UGCKitPhotoTransitionToolbar.h"
- #import "UGCKitColorMacro.h"
- #import "UGCKitSmallButton.h"
- #import "UGCKitMem.h"
- #import "UGCKitTheme.h"
- #import "UGCKitReporterInternal.h"
- #import "UGCKitSmallButton.h"
- typedef NS_ENUM(NSInteger,VideoType)
- {
- VideoType_Video,
- VideoType_Picture,
- };
- @interface UGCKitCutViewController ()<TXVideoGenerateListener,VideoPreviewDelegate, VideoCutViewDelegate,TransitionViewDelegate>
- @property(nonatomic,strong) TXVideoEditer *ugcEdit;
- @property(nonatomic,strong) UGCKitPlayerView *videoPreview;
- @property CGFloat duration;
- @end
- @implementation UGCKitCutViewController
- {
- UGCKitTheme *_theme;
- UGCKitMedia *_media;
- NSMutableArray *_cutPathList;
- NSString *_videoOutputPath;
-
- CGFloat _leftTime;
- CGFloat _rightTime;
- UILabel* _generationTitleLabel;
- UIView* _generationView;
- UIProgressView* _generateProgressView;
- UIButton* _generateCannelBtn;
-
- UIColor *_barTintColor;
-
- NSString* _filePath;
- unsigned long long _fileSize;
- BOOL _navigationBarHidden;
-
- BOOL _hasQuickGenerate;
- BOOL _hasNomalGenerate;
-
- UGCKitVideoCutView* _videoCutView;
- UGCKitPhotoTransitionToolbar* _photoTransitionToolbar;
- UGCKitRangeContentConfig *_config;
- int _renderRotation;
-
- CGFloat bottomToolbarHeight;
- CGFloat bottomInset;
- }
- - (instancetype)initWithMedia:(UGCKitMedia *)media theme:(UGCKitTheme *)theme;
- {
- if (self = [super init]) {
- _theme = theme ?: [UGCKitTheme sharedTheme];
- _media = media;
- _cutPathList = [NSMutableArray array];
- _videoOutputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"outputCut.mp4"];
- _config = [[UGCKitRangeContentConfig alloc] initWithTheme:_theme];
- _config.pinWidth = PIN_WIDTH;
- _config.thumbHeight = 50;
- _config.borderHeight = BORDER_HEIGHT;
- _config.imageCount = 15;
- }
- return self;
- }
- - (void)viewWillAppear:(BOOL)animated
- {
- [super viewWillAppear:animated];
- _navigationBarHidden = self.navigationController.navigationBar.hidden;
- self.navigationController.navigationBar.hidden = YES;
- self.navigationController.interactivePopGestureRecognizer.enabled = NO;
- }
- - (void)viewWillDisappear:(BOOL)animated
- {
- [super viewWillDisappear:animated];
- self.navigationController.navigationBar.hidden = _navigationBarHidden;
- }
- - (void)viewDidDisappear:(BOOL)animated
- {
- [super viewDidDisappear:animated];
- }
- - (void)viewDidAppear:(BOOL)animated
- {
- [super viewDidAppear:animated];
-
- [_videoPreview playVideo];
- }
- - (void)dealloc
- {
- [_videoPreview removeNotification];
- _videoPreview = nil;
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
-
- bottomToolbarHeight = 52;
- bottomInset = 10;
-
- _videoPreview = [[UGCKitPlayerView alloc] initWithFrame:CGRectMake(0, 0, self.view.ugckit_width, self.view.ugckit_height) coverImage:nil theme:_theme];
- _videoPreview.delegate = self;
- [self.view addSubview:_videoPreview];
- CGFloat top = [UIApplication sharedApplication].statusBarFrame.size.height;
- if (@available(iOS 11, *)) {
- bottomInset += [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
- }
- if (kScaleY < 1) {
- bottomToolbarHeight = round(bottomToolbarHeight * kScaleY);
- }
- UILabel *barTitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0 , 100, 44)];
- barTitleLabel.backgroundColor = [UIColor clearColor];
- barTitleLabel.font = [UIFont boldSystemFontOfSize:17];
- barTitleLabel.textColor = [UIColor whiteColor];
- barTitleLabel.textAlignment = NSTextAlignmentCenter;
- barTitleLabel.text = [_theme localizedString:@"UGCKit.Edit.VideoEdit"];
- self.navigationItem.titleView = barTitleLabel;
- self.view.backgroundColor = UIColor.blackColor;
-
- UIButton *goBackButton = [UGCKitSmallButton buttonWithType:UIButtonTypeCustom];
- [goBackButton setImage:_theme.backIcon forState:UIControlStateNormal];
- [goBackButton addTarget:self action:@selector(onBtnPopClicked) forControlEvents:UIControlEventTouchUpInside];
- goBackButton.frame = CGRectMake(15, 5 + top, 14 , 23);
- [self.view addSubview:goBackButton];
-
- CGFloat btnNextWidth = 70;
- CGFloat btnNextHeight = 30;
- UIButton *btnNext = [UIButton buttonWithType:UIButtonTypeCustom];
- btnNext.frame = CGRectMake(CGRectGetWidth(self.view.bounds) - 15 - btnNextWidth, 5 + top, btnNextWidth, btnNextHeight);
- [btnNext setTitle:[_theme localizedString:@"UGCKit.Common.Next"] forState:UIControlStateNormal];
- btnNext.titleLabel.font = [UIFont systemFontOfSize:14];
- [btnNext setBackgroundImage:_theme.nextIcon forState:UIControlStateNormal];
- [btnNext addTarget:self action:@selector(onBtnNextClicked) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:btnNext];
-
- // CGFloat heightDist = 52 * kScaleY;
- // _videoCutView = [[VideoCutView alloc] initWithFrame:CGRectMake(0, self.view.height - heightDist - 20 * kScaleY, self.view.width,heightDist) videoPath:_videoPath videoAssert:_videoAsset config:config];
- // _videoCutView.delegate = self;
- // [self.view addSubview:_videoCutView];
-
- TXPreviewParam *param = [[TXPreviewParam alloc] init];
- param.videoView = _videoPreview.renderView;
- param.renderMode = PREVIEW_RENDER_MODE_FILL_EDGE;
- _ugcEdit = [[TXVideoEditer alloc] initWithPreview:param];
- _ugcEdit.generateDelegate = self;
- _ugcEdit.previewDelegate = _videoPreview;
- CGPoint rotateButtonCenter = CGPointZero;
- //video
- if (_media.isVideo) {
- // if (_videoAsset != nil) {
- AVAsset *asset = _media.videoAsset;
- [_ugcEdit setVideoAsset:asset];
- [self initVideoCutView];
-
- TXVideoInfo *videoMsg = [TXVideoInfoReader getVideoInfoWithAsset:asset];
- _fileSize = videoMsg.fileSize;
- _duration = videoMsg.duration;
- _rightTime = _duration;
- _renderRotation = videoMsg.angle;
- rotateButtonCenter = CGPointMake(_videoCutView.ugckit_right - 20, _videoCutView.ugckit_top - 20);
- } else {
- //image
- // if (_imageList != nil) {
- CGRect frame = CGRectMake(0, self.view.ugckit_height - bottomInset - bottomToolbarHeight, self.view.ugckit_width, bottomToolbarHeight);
- _photoTransitionToolbar = [[UGCKitPhotoTransitionToolbar alloc] initWithFrame:frame
- theme:_theme];
- _photoTransitionToolbar.delegate = self;
- [self.view addSubview:_photoTransitionToolbar];
- _photoTransitionToolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
- [_ugcEdit setPictureList:_media.images fps:30];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self onVideoTransitionLefRightSlipping];
- });
- rotateButtonCenter = CGPointMake(_photoTransitionToolbar.ugckit_right - 20 - bottomToolbarHeight, _photoTransitionToolbar.ugckit_top - bottomToolbarHeight - 10 - 20);
- }
-
- if (_media.isVideo) {
- // rotation button
- UIButton *rotateButton = [UGCKitSmallButton buttonWithType:UIButtonTypeCustom];
- [rotateButton setImage:_theme.editRotateIcon forState:UIControlStateNormal];
- [rotateButton sizeToFit];
- rotateButton.center = rotateButtonCenter;
- [rotateButton addTarget:self action:@selector(onRotatePreview:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:rotateButton];
- }
- }
- - (UIView*)generatingView
- {
- /*用作生成时的提示浮层*/
- if (!_generationView) {
- _generationView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.ugckit_width, self.view.ugckit_height + 64)];
- _generationView.backgroundColor = UIColor.blackColor;
- _generationView.alpha = 0.9f;
-
- _generateProgressView = [UIProgressView new];
- _generateProgressView.center = CGPointMake(_generationView.ugckit_width / 2, _generationView.ugckit_height / 2);
- _generateProgressView.bounds = CGRectMake(0, 0, 225, 20);
- _generateProgressView.progressTintColor = _theme.progressColor;
- [_generateProgressView setTrackImage:_theme.progressTrackImage];
- //_generateProgressView.trackTintColor = UIColor.whiteColor;
- //_generateProgressView.transform = CGAffineTransformMakeScale(1.0, 2.0);
-
- _generationTitleLabel = [UILabel new];
- _generationTitleLabel.font = [UIFont systemFontOfSize:14];
- _generationTitleLabel.text = [_theme localizedString:@"UGCKit.Edit.VideoGenerating"];
- _generationTitleLabel.textColor = UIColor.whiteColor;
- _generationTitleLabel.textAlignment = NSTextAlignmentCenter;
- _generationTitleLabel.frame = CGRectMake(0, _generateProgressView.ugckit_y - 34, _generationView.ugckit_width, 14);
-
- _generateCannelBtn = [UIButton new];
- [_generateCannelBtn setImage:_theme.closeIcon forState:UIControlStateNormal];
- _generateCannelBtn.frame = CGRectMake(_generateProgressView.ugckit_right + 15, _generationTitleLabel.ugckit_bottom + 10, 20, 20);
- [_generateCannelBtn addTarget:self action:@selector(onCancelBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
-
- [_generationView addSubview:_generationTitleLabel];
- [_generationView addSubview:_generateProgressView];
- [_generationView addSubview:_generateCannelBtn];
- }
-
- _generateProgressView.progress = 0.f;
- [[[UIApplication sharedApplication] delegate].window addSubview:_generationView];
- return _generationView;
- }
- - (void)initVideoCutView
- {
- if (_media.isVideo) {
- CGRect frame = CGRectMake(0, self.view.ugckit_height - bottomToolbarHeight - bottomInset, self.view.ugckit_width,bottomToolbarHeight);
- if(_videoCutView) [_videoCutView removeFromSuperview];
- _videoCutView = [[UGCKitVideoCutView alloc] initWithFrame:frame videoPath:nil videoAsset:_media.videoAsset config:_config];
- [self.view addSubview:_videoCutView];
- }else{
- CGRect frame = CGRectMake(0, self.view.ugckit_height - bottomToolbarHeight - bottomInset - 10 - bottomToolbarHeight, self.view.ugckit_width,bottomToolbarHeight);
- if (_videoCutView) {
- [_videoCutView updateFrame:_duration];
- }else{
- [_videoCutView removeFromSuperview];
- _videoCutView = [[UGCKitVideoCutView alloc] initWithFrame:frame pictureList:_media.images duration:_duration fps:30 config:_config];
- [self.view addSubview:_videoCutView];
- }
- }
- _videoCutView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
- _videoCutView.delegate = self;
- [_videoCutView setCenterPanHidden:YES];
- }
- - (void)pause
- {
- [_ugcEdit pausePlay];
- [_videoPreview setPlayBtn:NO];
- }
- #pragma makr - Actions
- - (void)onRotatePreview:(id)sender
- {
- _renderRotation += 90;
- [_ugcEdit setRenderRotation:_renderRotation];
- }
- - (void)onBtnPopClicked
- {
- [self pause];
- [self _goBack];
- }
- - (void)_goBack {
- UINavigationController *nav = self.navigationController;
- if (nav.presentedViewController) {
- [nav.presentedViewController dismissViewControllerAnimated:YES completion:nil];
- } else {
- [nav popToRootViewControllerAnimated:YES];
- }
- }
- -(void)onBtnNextClicked
- {
- [self pause];
- [_videoPreview setPlayBtn:NO];
-
- if (_media.isVideo) {
- TXVideoInfo *videoInfo = [TXVideoInfoReader getVideoInfoWithAsset:_media.videoAsset];
- BOOL largerThan1080p = videoInfo.width * videoInfo.height > 1920*1080;
- BOOL hasBeenRotated = _renderRotation % 360 != 0;
- if (_leftTime == 0 && _rightTime == _duration && !largerThan1080p && !hasBeenRotated) {
- //视频如果没发生剪裁,也没有旋转,这里不用走编辑逻辑,减少画面质量损失
- if (self.completion) {
- UGCKitResult *result = [[UGCKitResult alloc] init];
- result.media = _media;
- self.completion(result, _renderRotation);
- }
- }else{
- _generationView = [self generatingView];
- _generationView.hidden = NO;
- [_ugcEdit setCutFromTime:_leftTime toTime:_rightTime];
- if (largerThan1080p || _renderRotation % 360 != 0) {
- [_ugcEdit generateVideo:VIDEO_COMPRESSED_720P videoOutputPath:_videoOutputPath];
- } else {
- //使用快速剪切,速度快
- _hasQuickGenerate = YES;
- [_ugcEdit quickGenerateVideo:VIDEO_COMPRESSED_720P videoOutputPath:_videoOutputPath];
- }
- }
- }else{
- //图片编辑只能走正常生成逻辑,这里使用高码率,保留更多图片细节
- _generationView = [self generatingView];
- _generationView.hidden = NO;
- _hasNomalGenerate = YES;
- [_ugcEdit setVideoBitrate:10000];
- [_ugcEdit setCutFromTime:_leftTime toTime:_rightTime];
- [_ugcEdit quickGenerateVideo:VIDEO_COMPRESSED_720P videoOutputPath:_videoOutputPath];
- }
- }
- - (void)onCancelBtnClicked:(UIButton*)sender
- {
- _generationView.hidden = YES;
- [_ugcEdit cancelGenerate];
- }
- #pragma mark TransitionViewDelegate
- - (void)_onVideoTransition:(TXTransitionType)type {
- __weak __typeof(self) weakSelf = self;
- WEAKIFY(self);
- [_ugcEdit setPictureTransition:type duration:^(CGFloat duration) {
- STRONGIFY_OR_RETURN(self);
- self->_duration = duration;
- self->_rightTime = duration;
- [self initVideoCutView];
- [self.ugcEdit startPlayFromTime:0 toTime:weakSelf.duration];
- [self.videoPreview setPlayBtn:YES];
- }];
- }
- - (void)onVideoTransitionLefRightSlipping
- {
- [self _onVideoTransition:TXTransitionType_LefRightSlipping];
- }
- - (void)onVideoTransitionUpDownSlipping
- {
- [self _onVideoTransition:TXTransitionType_UpDownSlipping];
- }
- - (void)onVideoTransitionEnlarge
- {
- [self _onVideoTransition:TXTransitionType_Enlarge];
- }
- - (void)onVideoTransitionNarrow
- {
- [self _onVideoTransition:TXTransitionType_Narrow];
- }
- - (void)onVideoTransitionRotationalScaling
- {
- [self _onVideoTransition:TXTransitionType_RotationalScaling];
- }
- - (void)onVideoTransitionFadeinFadeout
- {
- [self _onVideoTransition:TXTransitionType_FadeinFadeout];
- }
- #pragma mark TXVideoGenerateListener
- -(void) onGenerateProgress:(float)progress
- {
- _generateProgressView.progress = progress;
- }
- -(void) onGenerateComplete:(TXGenerateResult *)result
- {
- _generationView.hidden = YES;
- if (result.retCode == 0) {
- if (_media.isVideo) {
- NSFileManager *fm = [[NSFileManager alloc] init];
- NSString *rename = [_videoOutputPath stringByAppendingString:@"-tmp.mp4"];
- [fm removeItemAtPath:rename error:nil];
- [fm moveItemAtPath:_videoOutputPath toPath:rename error:nil];
- UGCKitResult *result = [[UGCKitResult alloc]init];
- result.media = [UGCKitMedia mediaWithVideoPath:rename];
- if (self.completion) {
- self.completion(result, 0);
- }
- } else {
- UGCKitResult *result = [[UGCKitResult alloc]init];
- result.media = [UGCKitMedia mediaWithVideoPath:_videoOutputPath];
- if (self.completion) {
- self.completion(result, 0);
- }
- }
- }else{
- //系统剪切如果失败,这里使用SDK正常剪切,设置高码率,保留图像更多的细节
- if (_hasQuickGenerate && !_hasNomalGenerate) {
- _generationView = [self generatingView];
- _generationView.hidden = NO;
- [_ugcEdit cancelGenerate];
- [_ugcEdit setVideoBitrate:10000];
- [_ugcEdit setCutFromTime:_leftTime toTime:_rightTime];
- [_ugcEdit generateVideo:VIDEO_COMPRESSED_720P videoOutputPath:_videoOutputPath];
- _hasNomalGenerate = YES;
- }else{
- UGCKitResult *r = [[UGCKitResult alloc] init];
- r.code = result.retCode;
- NSString *msg = [NSString stringWithFormat:[_theme localizedString:@"UGCKit.Common.HintErrorCodeMessage"],(long)result.retCode,result.descMsg];
- r.info = @{NSLocalizedDescriptionKey: msg};
- if (self.completion) {
- self.completion(r, _renderRotation);
- }
- // UIAlertController *controller = [UIAlertController alertControllerWithTitle:[_theme localizedString:@"UGCKit.Edit.HintVideoGeneratingFailed"]
- // message:msg
- // preferredStyle:UIAlertControllerStyleAlert];
- // [controller addAction:[UIAlertAction actionWithTitle:[_theme localizedString:@"UGCKit.Common.GotIt"] style:UIAlertActionStyleCancel handler:nil]];
- // [self presentViewController:controller animated:YES completion:nil];
- }
- }
- if (_media.isVideo) {
- [UGCKitReporter report:UGCKitReportItem_videoedit userName:nil code:result.retCode msg:result.descMsg];
- }else{
- [UGCKitReporter report:UGCKitReportItem_pictureedit userName:nil code:result.retCode msg:result.descMsg];
- }
- }
- #pragma mark UGCKitPlayerViewDelegate
- - (void)onVideoPlay
- {
- CGFloat currentPos = _videoCutView.videoRangeSlider.currentPos;
- if (currentPos < _leftTime || currentPos > _rightTime)
- currentPos = _leftTime;
-
- [_ugcEdit startPlayFromTime:currentPos toTime:_videoCutView.videoRangeSlider.rightPos];
- }
- - (void)onVideoPause
- {
- [_ugcEdit pausePlay];
- }
- - (void)onVideoResume
- {
- [self onVideoPlay];
- }
- - (void)onVideoPlayProgress:(CGFloat)time
- {
- [_videoCutView setPlayTime:time];
- }
- - (void)onVideoPlayFinished
- {
- [_ugcEdit startPlayFromTime:_leftTime toTime:_rightTime];
- }
- - (void)onVideoEnterBackground
- {
- if (_generationView && !_generationView.hidden) {
- [_ugcEdit pauseGenerate];
- }else{
- [UGCKitProgressHUD hideHUDForView:self.view animated:YES];
- [_ugcEdit pausePlay];
- [_videoPreview setPlayBtn:NO];
- }
- }
- - (void)onVideoWillEnterForeground
- {
- if (_generationView && !_generationView.hidden) {
- [_ugcEdit resumeGenerate];
- }
- }
- #pragma mark - VideoCutViewDelegate
- - (void)onVideoRangeLeftChanged:(UGCKitVideoRangeSlider *)sender
- {
- //[_ugcEdit pausePlay];
- [_videoPreview setPlayBtn:NO];
- [_ugcEdit previewAtTime:sender.leftPos];
- }
- - (void)onVideoRangeRightChanged:(UGCKitVideoRangeSlider *)sender
- {
- [_videoPreview setPlayBtn:NO];
- [_ugcEdit previewAtTime:sender.rightPos];
- }
- - (void)onVideoRangeLeftChangeEnded:(UGCKitVideoRangeSlider *)sender
- {
- _leftTime = sender.leftPos;
- _rightTime = sender.rightPos;
- [_ugcEdit startPlayFromTime:sender.leftPos toTime:sender.rightPos];
- [_videoPreview setPlayBtn:YES];
- }
- - (void)onVideoRangeRightChangeEnded:(UGCKitVideoRangeSlider *)sender
- {
- _leftTime = sender.leftPos;
- _rightTime = sender.rightPos;
- [_ugcEdit startPlayFromTime:sender.leftPos toTime:sender.rightPos];
- [_videoPreview setPlayBtn:YES];
- }
- - (void)onVideoSeekChange:(UGCKitVideoRangeSlider *)sender seekToPos:(CGFloat)pos
- {
- [_ugcEdit previewAtTime:pos];
- [_videoPreview setPlayBtn:NO];
- }
- @end
|