| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- import Foundation
- import Flutter
- import UIKit
- import AliyunVideoSDKPro
- public class CameraViewFactory: NSObject, FlutterPlatformViewFactory {
- var messenger: FlutterBinaryMessenger!
- public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
- return CameraView(withFrame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
- }
- @objc public init(messenger: (NSObject & FlutterBinaryMessenger)?) {
- super.init()
- self.messenger = messenger
- }
-
- public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
- return FlutterStandardMessageCodec.sharedInstance()
- }
-
- }
- public class CameraView: NSObject, FlutterPlatformView, AliyunIRecorderDelegate, AliyunIPlayerCallback, AliyunIExporterCallback, AliyunIRenderCallback {
- public func playerDidEnd() {
-
- }
-
- public func playProgress(_ playSec: Double, streamProgress streamSec: Double) {
-
- }
-
- public func playError(_ errorCode: Int32) {
-
- }
-
- public func seekDidEnd() {
-
- }
-
- public func playerDidStart() {
-
- }
-
-
- fileprivate var viewId: Int64!
- fileprivate var cameraView: UIView!
- fileprivate var channel: FlutterMethodChannel!
- fileprivate var recordPath: String?
- fileprivate var taskPath: String?
- fileprivate var recorder: AliyunIRecorder!
- fileprivate var composeResult: FlutterResult?
- public init(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger: FlutterBinaryMessenger) {
- super.init()
-
- self.viewId = viewId
-
- self.cameraView = UIView()
- self.cameraView.frame = UIScreen.main.bounds
- self.channel = FlutterMethodChannel(name: "flutter_ali_camera_\(viewId)", binaryMessenger: binaryMessenger)
- self.channel.setMethodCallHandler({
- [weak self]
- (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
- if let this = self {
- this.onMethodCall(call: call, result: result)
- }
- })
- }
-
-
- public func view() -> UIView {
- return self.cameraView
- }
- func onMethodCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
- let args = call.arguments as? [String: Any]
- let method = call.method
- if call.method == "initializeSdk" {
- // initSdk(result)
- result(true)
- } else if call.method == "cleanAudioData" {
- let videoId = args!["videoId"] as! String
- let pathAudio = args!["pathAudio"] as! String
- deleteFileWithPrefix(folderPath: pathAudio, prefix: "\(videoId)_")
- result(true)
- } else if call.method == "getFilterParentPath" {
- print("path \(Bundle.main.path(forResource: "icon", ofType: "png"))")
- let url = Bundle.main.bundlePath
- result("\(url)/filter/")
- } else if method == "startPreview" {
- initCameraView()
- recorder?.clipManager?.deleteAllPart()
- recorder?.startPreview(withPositon: AliyunIRecorderCameraPosition.front)
- result(true)
- } else
- if method == "startPreview" {
- initCameraView()
- recorder?.clipManager?.deleteAllPart()
- recorder?.startPreview(withPositon: AliyunIRecorderCameraPosition.front)
- result(true)
- } else if method == "setRecordPath" {
- self.recordPath = args!["path"] as? String
- self.taskPath = args!["taskPath"] as? String
- result(true)
- } else if method == "onStop" {
- onStop()
- result(true)
- } else if method == "onResume" {
- recorder?.startPreview(withPositon: AliyunIRecorderCameraPosition.front)
- result(true)
- } else if method == "onDestory" {
- onStop()
- onDestory()
- result(true)
- } else if method == "switchCamera" {
- recorder.switchCameraPosition()
- result(true)
- } else if method == "setBeautyLevel" {
- let level = args!["level"] as! Int
- recorder.beautifyStatus = (level == 0)
- recorder.beautifyValue = Int32(level)
- result(true)
- } else if method == "startRecord" {
- let maxDuration = args!["maxDuration"] as! Int
- let videoId = args!["videoId"] as! String
- let index = args!["index"] as! Int
- let fileName = args!["fileName"] as! String
- if recorder?.clipManager?.videoAbsolutePaths != nil && recorder?.clipManager?.videoAbsolutePaths.count != 0 {
- recorder?.clipManager?.deletePart()
- }
- clearCacheVideo(videoId: videoId, index: index)
- recorder?.outputPath = self.recordPath! + "\(fileName).mp4"
- recorder?.clipManager?.maxDuration = CGFloat(Float(maxDuration) / 1000.0)
- recorder?.startRecording()
- result(true)
- } else if method == "stopRecord" {
- recorder?.stopRecording()
- result(true)
- } else if method == "finishRecord" {
- recorder?.finishRecording()
- result(true)
- } else if method == "setFilter" {
- let path: String? = args?["path"] as? String
- if path == nil || path?.count == 0 {
- // delete filter
- recorder?.deleteFilter()
- return
- }
- recorder?.apply(AliyunEffectFilter.init(file: path))
- } else if method == "startCompose" {
- let outputPath = args!["outputPath"] as! String
- let bgmPath = args!["bgmPath"] as! String
- let paths = args!["paths"] as! [String]
- let durations = args!["durations"] as! [Int]
- composeResult = result
- startCompose(outputPath: outputPath, bgmPath: bgmPath, paths: paths, durations: durations)
- } else if method == "create"{
- result(FlutterMethodNotImplemented)
- }
- }
- private func initCameraView() {
- recorder = AliyunIRecorder.init(delegate: self, videoSize: CGSize(width: 720, height: 1280))
- recorder?.preview = self.cameraView
- recorder?.taskPath = self.taskPath
- recorder?.clipManager?.maxDuration = 0
- }
-
- private func onStop() {
- recorder?.stopRecording()
- recorder?.stopPreview()
- }
-
- private func onDestory() {
- recorder?.destroy()
- recorder = nil
- cameraView = nil
- }
-
- var editor: AliyunEditor?
- private func startCompose(outputPath: String, bgmPath: String, paths: [String], durations: [Int]) {
- AliyunVideoSDKInfo.print()
- if durations.count != paths.count {
- return
- }
- // AliyunVideoSDKInfo.setLogLevel(AlivcLogLevel.debug)
-
- let importer = AliyunImporter.init(path: self.taskPath, outputSize: CGSize(width: 480, height: 720))
- let param = AliyunVideoParam.init()
- param.fps = 30
- param.gop = 30
- param.videoQuality = AliyunVideoQuality.medium
- param.scaleMode = AliyunScaleMode.fill
- // 编码模式
- param.codecType = AliyunVideoCodecType.hardware
- importer?.setVideoParam(param)
- for index in 0..<paths.count {
- print("paths: \(paths[index])")
- // 取出有效的document地址
- let documentRance: Range = paths[index].range(of: "/Documents/")!
- let distance: Int = paths[index].distance(from: paths[index].startIndex, to: documentRance.upperBound)
- let truePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] + paths[index].subString(from: distance - 1)
- print("true path: \(truePath)")
-
- importer?.addMediaClip(AliyunClip.init(videoPath: truePath, animDuration: 0))
- }
- importer?.generateProjectConfigure()
- editor = AliyunEditor.init(path: self.taskPath, preview: nil)
- editor?.apply(AliyunEffectMusic.init(file: bgmPath))
- editor?.delegate = self
- editor?.startEdit()
-
- let exporter = editor?.getExporter()
- exporter?.startExport(outputPath)
- }
-
- private func clearCacheVideo(videoId: String, index: Int) {
- deleteFileWithPrefix(folderPath: self.recordPath!, prefix: "\(videoId)_\(index)_")
- }
-
- private func deleteFileWithPrefix(folderPath: String, prefix: String) {
- let manager = FileManager.default
- let files:[String] = try! manager.contentsOfDirectory(atPath: folderPath)
-
- for file in files{
- do {
- if file.hasPrefix(prefix) {
- try manager.removeItem(atPath: folderPath + "/\(file)")
- }
- } catch {
- print("faild to delete")
- }
- }
- }
-
- public func recorderDeviceAuthorization(_ status: AliyunIRecorderDeviceAuthor) {
- if status == AliyunIRecorderDeviceAuthor.enabled {
- print("sdk enabled")
- } else {
- print("sdk disabled")
- }
- }
-
- public func recorderVideoDuration(_ duration: CGFloat) {
- print("recorderVideoDuration:\(duration)")
- channel.invokeMethod("recordProgress", arguments: ["progress": Int(duration * 1000)])
- }
-
- public func recoderError(_ error: Error!) {
- print("recoderError")
- recorder?.finishRecording()
- }
-
- public func recorderDidStopWithMaxDuration() {
- print("recorderDidStopWithMaxDuration")
- recorder?.finishRecording()
- }
-
- public func recorderDidFinishRecording() {
- channel.invokeMethod("recordProgress", arguments: ["progress": Int((recorder?.clipManager?.maxDuration ?? 0) * 1000), "path": recorder?.outputPath])
- }
- public func exporterDidCancel() {
-
- }
-
- public func exportProgress(_ progress: Float) {
- print("exportProgress")
- }
-
- public func exportError(_ errorCode: Int32) {
- print("export error : \(errorCode)")
- composeResult?(false)
- }
-
- public func exporterDidStart() {
- print("exporterDidStart")
- }
-
- public func exporterDidEnd(_ outputPath: String!) {
- composeResult?(true)
- }
- }
- extension String {
- func toInt() -> Int? {
- return Int(self)
- }
- func toFloat() -> Float? {
- return Float(self)
- }
- func toDouble() -> Double? {
- return Double(self)
- }
- //MARK:- 去除字符串两端的空白字符
- func trim() -> String {
- return self.trimmingCharacters(in: CharacterSet.whitespaces)
- }
- func subString(to: Int) -> String {
- var to = to
- if to > self.count {
- to = self.count
- }
- return String(self.prefix(to))
- }
- func subString(from: Int) -> String {
- if from >= self.count {
- return ""
- }
- let startIndex = self.index(self.startIndex, offsetBy: from)
- let endIndex = self.endIndex
- return String(self[startIndex..<endIndex])
- }
- func subString(start: Int, end: Int) -> String {
- if start < end {
- let startIndex = self.index(self.startIndex, offsetBy: start)
- let endIndex = self.index(self.startIndex, offsetBy: end)
-
- return String(self[startIndex..<endIndex])
- }
- return ""
- }
-
-
- }
|