Преглед на файлове

视频录制 -- to be continued

Chris преди 5 години
родител
ревизия
06b0d033d3

+ 6 - 0
RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj

@@ -484,6 +484,7 @@
 		BD4B50AC22BC7DEA0073B516 /* FilterResource.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BD4B50AB22BC7DEA0073B516 /* FilterResource.bundle */; };
 		BD4B50AE22BC815F0073B516 /* PublishFilterCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD4B50AD22BC815F0073B516 /* PublishFilterCollectionCell.swift */; };
 		BD4B50B422BC8AD50073B516 /* AliyunPathManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BD4B50B322BC8AD50073B516 /* AliyunPathManager.m */; };
+		BD4B50B722BCBEBE0073B516 /* QUProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD4B50B622BCBEBE0073B516 /* QUProgressView.m */; };
 		BD6EDF48229007EA009A20FE /* OrderApplyRefundModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD6EDF47229007EA009A20FE /* OrderApplyRefundModel.swift */; };
 		BD7AB83622841A8B0030646A /* ShoppingCartPayOrderItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AB83522841A8B0030646A /* ShoppingCartPayOrderItemCell.swift */; };
 		BD7AB838228420310030646A /* ShoppingCartPayOrderHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AB837228420310030646A /* ShoppingCartPayOrderHeader.swift */; };
@@ -1054,6 +1055,8 @@
 		BD4B50AD22BC815F0073B516 /* PublishFilterCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishFilterCollectionCell.swift; sourceTree = "<group>"; };
 		BD4B50B222BC8AD50073B516 /* AliyunPathManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AliyunPathManager.h; sourceTree = "<group>"; };
 		BD4B50B322BC8AD50073B516 /* AliyunPathManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AliyunPathManager.m; sourceTree = "<group>"; };
+		BD4B50B522BCBEBD0073B516 /* QUProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QUProgressView.h; sourceTree = "<group>"; };
+		BD4B50B622BCBEBE0073B516 /* QUProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QUProgressView.m; sourceTree = "<group>"; };
 		BD6EDF47229007EA009A20FE /* OrderApplyRefundModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderApplyRefundModel.swift; sourceTree = "<group>"; };
 		BD7AB83522841A8B0030646A /* ShoppingCartPayOrderItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShoppingCartPayOrderItemCell.swift; sourceTree = "<group>"; };
 		BD7AB837228420310030646A /* ShoppingCartPayOrderHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShoppingCartPayOrderHeader.swift; sourceTree = "<group>"; };
@@ -3798,6 +3801,8 @@
 				BD4B50AD22BC815F0073B516 /* PublishFilterCollectionCell.swift */,
 				BD4B50B222BC8AD50073B516 /* AliyunPathManager.h */,
 				BD4B50B322BC8AD50073B516 /* AliyunPathManager.m */,
+				BD4B50B522BCBEBD0073B516 /* QUProgressView.h */,
+				BD4B50B622BCBEBE0073B516 /* QUProgressView.m */,
 			);
 			path = PublishTakeVideo;
 			sourceTree = "<group>";
@@ -4999,6 +5004,7 @@
 				A7CC74D6226FF421003C4F38 /* MineNavigationBarView.swift in Sources */,
 				BD4B50B422BC8AD50073B516 /* AliyunPathManager.m in Sources */,
 				BDAF83AA22B388F20004BCC3 /* RecommendDefaultBackCell.swift in Sources */,
+				BD4B50B722BCBEBE0073B516 /* QUProgressView.m in Sources */,
 				A71AF0BC226F099B001730FE /* ProductHBigTableViewCell.swift in Sources */,
 				BD108C9622A60C2100837DAB /* HGImagePickerCell.swift in Sources */,
 				A7A98E3C228036D7005306E9 /* ShoppingMallCategoryCollectionViewCell.swift in Sources */,

+ 1 - 1
RainbowPlanet/RainbowPlanet/Macro/RainbowPlanet-Bridging-Header.h

@@ -61,8 +61,8 @@
 #import "KSMediaPickerCollectionView.h"
 #import "KSVideoPlayerBaseView.h"
 
-
 #import "AliyunPathManager.h"
+#import "QUProgressView.h"
 
 
 #endif /* RainbowPlanet_Bridging_Header_h */

+ 138 - 8
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishTakeVideo/PublishVideoRecorderController.swift

@@ -9,6 +9,7 @@
 import UIKit
 import JXSegmentedView
 import AliyunVideoSDKPro
+import CoreMotion
 
 class PublishVideoRecorderController: BaseViewController {
     
@@ -18,12 +19,54 @@ class PublishVideoRecorderController: BaseViewController {
     // 滤镜Items
     var effectFilterItems: Array<AliyunEffectFilter> = []
     
+    // 视频片段管理器
+    var clipManager: AliyunClipManager?
+    
+    // 开始录制时间
+    var downTime: Double?
+    
+    // 结束录制时间
+    var upTime: Double?
+    
+    // 开始录制视频段数
+    var downVideoCount: Int = 0
+    
+    // 结束录制视频段数
+    var upVideoCount: Int = 0
+    
+    // 录制时间
+    var recordingDuration: CFTimeInterval?
+    
+    var motionManager: CMMotionManager?
+    
+    // 相机旋转角度
+    var cameraRotate: Int = 90
+    
+    // 录制时间区间
+    let maxDuration: CGFloat = 60.0
+    let minDuration: CGFloat = 3.0
+    
+    
+    
     override func viewDidLoad() {
         super.viewDidLoad()
         
         setupViews()
         setupLayouts()
         setupFilterEffectData()
+        
+        //录制片段设置
+        clipManager = recorder.clipManager
+        clipManager?.maxDuration = maxDuration
+        clipManager?.minDuration = minDuration
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        startRetainCameraRotate()
+    }
+    
+    override func viewWillDisappear(_ animated: Bool) {
+        motionManager?.stopDeviceMotionUpdates()
     }
     
     deinit {
@@ -50,6 +93,40 @@ class PublishVideoRecorderController: BaseViewController {
         }
     }
     
+    func startRetainCameraRotate() {
+        if motionManager == nil {
+            motionManager = CMMotionManager()
+        }
+        
+        if motionManager?.isDeviceMotionAvailable ?? false {
+            motionManager?.deviceMotionUpdateInterval = 1
+            motionManager?.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {
+                [weak self] (motion, error) in
+                // Gravity 获取手机的重力值在各个方向上的分量,根据这个就可以获得手机的空间位置,倾斜角度等
+                let gravityX: Double = motion?.gravity.x ?? 0
+                let gravityY: Double = motion?.gravity.y ?? 0
+                //手机旋转角度
+                let xyTheta: Double = atan2(gravityX,gravityY)/Double.pi*180.0
+                
+                if (xyTheta >= -45 && xyTheta <= 45) {
+                    //down
+                    self?.cameraRotate = 180;
+                } else if (xyTheta > 45 && xyTheta < 135) {
+                    //left
+                    self?.cameraRotate = 90;
+                } else if ((xyTheta >= 135 && xyTheta < 180) || (xyTheta >= -180 && xyTheta < -135)) {
+                    //up
+                    self?.cameraRotate = 0;
+                } else if (xyTheta >= -135 && xyTheta < -45) {
+                    //right
+                    self?.cameraRotate = 270;
+                }
+            })
+        }
+    }
+    
+    
+    // SDK录制类
     private lazy var recorder: AliyunIRecorder = {
         //清除之前生成的录制路径
         let recordDir: String = AliyunPathManager.createRecrodDir()
@@ -60,7 +137,7 @@ class PublishVideoRecorderController: BaseViewController {
         let videoSavePath: String = taskPath.appending(AliyunPathManager.randomString()).appending("mp4")
         
         
-        let recorder = AliyunIRecorder.init(delegate: self as? AliyunIRecorderDelegate, videoSize: CGSize(width: 720, height: 1280))
+        let recorder = AliyunIRecorder.init(delegate: self, videoSize: CGSize(width: 720, height: 1280))
         
         // 预览视图,必须设置
         recorder?.preview = videoCameraView.previewView
@@ -174,29 +251,82 @@ extension PublishVideoRecorderController {
         }
     }
     
-    // 点击录制button开始录制
     func recordButtonRecordVideo() {
+        print("---------->点击了录制按钮")
+        
         recorder.startRecording()
+        
+        downTime = CFAbsoluteTimeGetCurrent()
+        downVideoCount = clipManager?.partCount ?? 0
+        if clipManager?.partCount ?? 0 <= 0 {
+            recorder.cameraRotate = Int32(cameraRotate)
+        }
+        
+        if recorder.startRecording() == 0 {
+            // 隐藏UI
+            
+        } else {
+            print("---------->startRecording错误error:");
+            // 还原UI
+            
+//            self.magicCameraView.progressView.videoCount--;
+//            [self.magicCameraView resetRecordButtonUI];
+//            self.magicCameraView.recording = NO;
+//            _magicCameraView.realVideoCount = [_clipManager partCount];
+        }
     }
     
-    // 点击录制button停止录制
     func recordButtonPauseVideo() {
+        print("---------->点击了暂停录制按钮")
+        
         recorder.stopRecording()
+        upTime = CFAbsoluteTimeGetCurrent();
+        
+        // 还原UI
+        
     }
     
-    // 收到录制停止回调,调用完成录制
     func recordButtonFinishVideo() {
         recorder.finishRecording()
     }
     
+}
+
+// MARK: - AliyunIRecorderDelegate
+extension PublishVideoRecorderController: AliyunIRecorderDelegate {
+    func recorderDeviceAuthorization(_ status: AliyunIRecorderDeviceAuthor) {
+        if (status.rawValue == 1) {            
+            SwiftProgressHUD.shared().showText("麦克风无权限")
+        } else if (status.rawValue == 2) {
+            SwiftProgressHUD.shared().showText("摄像头无权限")
+        }
+    }
+    
+    // 暂停录制回调
+    func recorderDidStopRecording() {
+        print("---------->暂停录制回调")
+        
+        upVideoCount = clipManager?.partCount ?? 0
+        
+        let vDura: CGFloat = CGFloat(recordingDuration ?? 0)
+        if vDura >= minDuration {
+            // 允许结束button点按
+        } else {
+            // 禁止结束button点按
+        }
+        
+    }
+    
+    // 收到完成录制回调,视频已经保存到初始化设置的`视频输出沙盒路径`路径下
+    func recorderDidFinishRecording() {
+        print("----录制完成")
+    }
+    
+    // 收到录制达到最大时长回调,调用完成录制
     func recorderDidStopWithMaxDuration() {
-        // 收到录制达到最大时长回调,调用完成录制
         recorder.finishRecording()
         print("----超时")
     }
-    func recorderDidFinishRecording() {
-        // 收到完成录制回调,视频已经保存到初始化设置的`视频输出沙盒路径`路径下
-    }
     
 }
 

+ 30 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishTakeVideo/QUProgressView.h

@@ -0,0 +1,30 @@
+//
+//  QUProgressView.h
+//  AliyunVideo
+//
+//  Created by dangshuai on 17/3/7.
+//  Copyright (C) 2010-2017 Alibaba Group Holding Limited. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface QUProgressView : UIView
+
+@property (nonatomic, assign) NSInteger videoCount;
+@property (nonatomic, assign) NSInteger selectedIndex;
+@property (nonatomic, assign) BOOL showBlink;
+@property (nonatomic, assign) BOOL showNoticePoint;
+@property (nonatomic, assign) CGFloat minDuration;
+@property (nonatomic, assign) CGFloat maxDuration;
+@property (nonatomic, strong) NSMutableArray *pointArray;
+
+@property (nonatomic, strong) UIColor *colorProgress;
+@property (nonatomic, strong) UIColor *colorSelect;
+@property (nonatomic, strong) UIColor *colorNotice;
+@property (nonatomic, strong) UIColor *colorSepatorPoint;
+
+- (void)updateProgress:(CGFloat)progress;
+
+-(void)reset;
+
+@end

+ 139 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishTakeVideo/QUProgressView.m

@@ -0,0 +1,139 @@
+//
+//  QUProgressView.m
+//  AliyunVideo
+//
+//  Created by dangshuai on 17/3/7.
+//  Copyright (C) 2010-2017 Alibaba Group Holding Limited. All rights reserved.
+//
+
+#import "QUProgressView.h"
+
+@implementation QUProgressView {
+    NSTimer *_timer;
+    NSInteger _times;
+    CGFloat _progress;
+    CGFloat _lineWidth;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.backgroundColor = [UIColor colorWithRed:239/255.0f green:75/255.0f blue:129/255.0f alpha:1.0];
+        [self defaultParam];
+    }
+    return self;
+}
+
+- (void)defaultParam {
+    _pointArray = [NSMutableArray arrayWithCapacity:0];
+    _lineWidth = CGRectGetHeight(self.bounds) * [UIScreen mainScreen].scale;
+    _colorNotice = [UIColor whiteColor];
+    _colorProgress = [UIColor colorWithRed:239/255.0f green:75/255.0f blue:129/255.0f alpha:1.0];
+    _colorSepatorPoint = [UIColor whiteColor];
+    _colorSelect = [UIColor redColor];
+    _selectedIndex = -1;
+}
+
+- (void)setShowBlink:(BOOL)showBlink {
+    _showBlink = showBlink;
+    [self destroyTimer];
+    if (_showBlink) {
+        [self startTimer];
+    }
+}
+
+- (void)setShowNoticePoint:(BOOL)showNoticePoint {
+    _showNoticePoint = showNoticePoint;
+}
+
+- (void)destroyTimer {
+    [_timer invalidate];
+    _timer = nil;
+    
+}
+
+- (void)setVideoCount:(NSInteger)videoCount {
+    
+    if (_videoCount < videoCount) {
+        [_pointArray addObject:@(_progress)];
+    } else {
+        [_pointArray removeLastObject];
+    }
+    NSLog(@"_progressArr:%@",_pointArray);
+    
+    _videoCount = videoCount < 0 ? 0 : videoCount;
+    _selectedIndex = -1;
+}
+
+- (void)updateProgress:(CGFloat)progress {
+    _progress = progress;
+    [self setNeedsDisplay];
+}
+
+- (void)startTimer {
+    _timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self
+                                            selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];
+    [_timer fire];
+}
+
+- (void)drawRect:(CGRect)rect {
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    CGContextSetLineWidth(context, _lineWidth);
+    
+    CGFloat w = CGRectGetWidth(self.superview.bounds);
+    
+    for (int i = 0; i < _videoCount; i++) {
+        CGFloat sp = [_pointArray[i] floatValue];
+        if (i == _selectedIndex) {
+            CGContextSetStrokeColorWithColor(context, _colorSelect.CGColor);
+        } else {
+            CGContextSetStrokeColorWithColor(context, _colorProgress.CGColor);
+        }
+        CGFloat x = sp / _maxDuration * w;
+        CGContextMoveToPoint(context, x, 0);
+        x = _progress / _maxDuration * w;
+        CGContextAddLineToPoint(context, x, 0);
+        CGContextStrokePath(context);
+    }
+    
+    for (int i = 0; i < _pointArray.count; i++) {
+        CGFloat p = [_pointArray[i] floatValue];
+        CGContextSetStrokeColorWithColor(context, _colorSepatorPoint.CGColor);
+        CGFloat x = p / _maxDuration * w;
+        CGContextMoveToPoint(context, x - 1, 0);
+        CGContextAddLineToPoint(context, x, 0);
+        CGContextStrokePath(context);
+    }
+    
+    if (_showNoticePoint && [self shouldShowNotice]) {
+        CGContextSetStrokeColorWithColor(context, _colorNotice.CGColor);
+        CGContextMoveToPoint(context, w * _minDuration/_maxDuration, 0);
+        CGContextAddLineToPoint(context, w * _minDuration/_maxDuration + 1,0);
+        CGContextStrokePath(context);
+    }
+    
+    if ( _showBlink && (_showBlink ? ++_times : (_times=1)) && (_times%2 == 1)) {
+        
+        CGFloat x = [self endPointX];
+        CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:239/255.0f green:75/255.0f blue:129/255.0f alpha:1.0].CGColor);
+        CGContextMoveToPoint(context, x + 0.5, 0);
+        CGContextAddLineToPoint(context, x + 4, 0);
+        CGContextStrokePath(context);
+    }
+}
+
+- (CGFloat)endPointX {
+    return _progress / _maxDuration * CGRectGetWidth(self.bounds);
+}
+
+- (BOOL)shouldShowNotice {
+    return _progress < _minDuration;
+}
+
+-(void)reset {
+    _videoCount = 0;
+    [_pointArray removeAllObjects];
+    [self updateProgress:0];
+}
+
+@end