// // AliCameraViewFactory.swift // AliyunOSSiOS // // Created by weihong huang on 2020/8/20. // import Flutter import Foundation import AliyunVideoSDKPro public class AliCameraViewFactory : NSObject, FlutterPlatformViewFactory { var messeneger: FlutterBinaryMessenger! public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { return AliCameraView(frame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: self.messeneger) } init(messeneger: FlutterBinaryMessenger) { super.init() self.messeneger = messeneger } public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { return FlutterStandardMessageCodec.sharedInstance() } } public class AliCameraView : NSObject, FlutterPlatformView, AliyunIRecorderDelegate, AliyunIExporterCallback { fileprivate var uiView: UIView = UIView() fileprivate var recorder: AliyunIRecorder! fileprivate var methodChannel: FlutterMethodChannel! fileprivate var taskPath: String! fileprivate var aliyunEditor: AliyunEditor! fileprivate var exportResult: FlutterResult! init(frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger: FlutterBinaryMessenger) { super.init() // init view size let dict = args as! [String: Any] self.uiView.frame = CGRect.init(x: dict["x"] as? Float64 ?? 0, y: dict["y"] as? Float64 ?? 0, width: dict["width"] as? Float64 ?? Float64(UIScreen.main.bounds.width), height: dict["height"] as? Float64 ?? Float64(UIScreen.main.bounds.height)) // init method channel self.methodChannel = FlutterMethodChannel(name: "com.i2edu.cameraLib/camera_view_\(viewId)", binaryMessenger: binaryMessenger) self.methodChannel?.setMethodCallHandler ({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in if let this = self { this.onMethonCall(call: call, result: result) } }) } public func view() -> UIView { return self.uiView } func onMethonCall(call: FlutterMethodCall, result: @escaping FlutterResult) { let args = call.arguments as? [String: Any] switch call.method { case "create": let recordOptions = args?["recordOption"] as? [String: Any] let taskPath = args?["iosTaskPath"] as! String do { try setUpCameraView(recordOption: recordOptions!, taskPath: taskPath) result(true) } catch { result(false) } break case "startPreview": do { try startPreview() result(true) } catch { result(false) } break; case "stopPreview": do { try stopPreview() result(true) } catch { result(false) } break; case "switchCamera": do { try switchCamera() result(true) } catch { result(false) } break; case "setBeauty": do { try setBeauty(level: args?["level"] as? Int32 ?? 0) result(true) } catch { result(false) } break; case "setFilter": do { try setFilter(path: args?["path"] as? String) result(true) } catch { result(false) } break; case "startRecord": do { try startRecord( maxDuration: args?["max"] as! Int32, recordPath: args?["recordPath"] as! String) result(true) } catch { result(FlutterError.init(code: "1001", message: error.localizedDescription, details: nil)) } break case "startCompose": do { self.exportResult = result let composeOption = args?["composeOption"] as! [String: Any] try startCompose( outputPath: args?["outputPath"] as! String, bgmPath: args?["bgmPath"] as? String, paths: args?["paths"] as! [String], durations: args?["durations"] as! [Int32], composeOption: composeOption ) } catch { result(FlutterError.init(code: "1002", message: error.localizedDescription, details: nil)) } break case "onDestroy": do { try onDestroy() result(true) } catch { result(false) } break default: result(FlutterMethodNotImplemented) } } func setUpCameraView(recordOption: [String: Any], taskPath: String) throws { self.taskPath = taskPath self.recorder = AliyunIRecorder.init(delegate: self, videoSize: CGSize(width: recordOption["videoWidth"] as! Int, height: recordOption["videoHeight"] as! Int)) let keys = recordOption.keys if (keys.contains("fps")) { self.recorder.recordFps = recordOption["fps"] as! Int32 } if (keys.contains("videoCodecs")) { if (recordOption["videoCodecs"] as! Int == 0) { self.recorder.encodeMode = 0 } else { self.recorder.encodeMode = 1 } } if (keys.contains("quality")) { self.recorder.videoQuality = AliyunVideoQuality.init(rawValue: recordOption["quality"] as! Int) ?? AliyunVideoQuality.medium } if (keys.contains("videoBitrate")) { self.recorder.bitrate = recordOption["videoBitrate"] as! Int32 } if (keys.contains("gop")) { self.recorder.gop = recordOption["gop"] as! Int32 } self.recorder?.beautifyStatus = false self.recorder?.beautifyValue = 0 self.recorder?.preview = self.uiView } func startPreview() throws { self.recorder?.startPreview(withPositon: AliyunIRecorderCameraPosition.front) } func stopPreview() throws { self.recorder?.stopPreview() } func switchCamera() throws { self.recorder?.switchCameraPosition() } func setBeauty(level: Int32) throws { self.recorder?.beautifyStatus = level != 0 self.recorder?.beautifyValue = level } func setFilter(path: String?) throws { if path == nil || path?.count == 0 { recorder?.deleteFilter() } else { self.recorder?.apply(AliyunEffectFilter.init(file: path)) } } func startRecord(maxDuration: Int32, recordPath: String) throws { recorder?.taskPath = taskPath recorder?.clipManager?.deleteAllPart() recorder?.outputPath = recordPath recorder?.clipManager?.maxDuration = CGFloat(Float(maxDuration) / 1000.0) recorder?.startRecording() } func startCompose(outputPath: String, bgmPath: String?, paths: [String], durations: [Int32], composeOption: [String: Any]) throws { // set up AliyunImporter let importer = AliyunImporter.init( path: self.taskPath, outputSize: CGSize(width: composeOption["outputWidth"] as! CGFloat, height: composeOption["outputHeight"] as! CGFloat)) let composeParam = AliyunVideoParam.init() let keys = composeOption.keys if keys.contains("gop") { composeParam.gop = composeOption["gop"] as! Int32 } if keys.contains("bitrate") { composeParam.bitrate = composeOption["bitrate"] as! Int32 } if keys.contains("frameRate") { composeParam.fps = composeOption["frameRate"] as! Int32 } if keys.contains("videoCodecs") { var codecType:AliyunVideoCodecType let type = composeOption["videoCodecs"] as! Int32 if type == 0 { codecType = AliyunVideoCodecType.hardware } else if type == 1 { codecType = AliyunVideoCodecType.openh264 } else if type == 2 { codecType = AliyunVideoCodecType.fFmpeg } else { codecType = AliyunVideoCodecType.typeAuto } composeParam.codecType = codecType } if keys.contains("quality") { composeParam.videoQuality = AliyunVideoQuality.init(rawValue: composeOption["quality"] as! Int) ?? AliyunVideoQuality.medium } if keys.contains("scaleMode") { composeParam.scaleMode = AliyunScaleMode.init(rawValue: composeOption["scaleMode"] as! Int) ?? AliyunScaleMode.fit } for index in 0..