import Flutter import UIKit import AVFoundation private let timerInterval: Double = 0.03 private let preTime: Double = 0.3 private let preLag: Double = 0.15 enum DubbingStatus { case stop, record, playRecord } public class SwiftDubbingLibPlugin: NSObject, FlutterPlugin { var registrar: FlutterPluginRegistrar! var channel: FlutterMethodChannel! public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: "dubbing_lib", binaryMessenger: registrar.messenger()) let instance = SwiftDubbingLibPlugin() registrar.addMethodCallDelegate(instance, channel: channel) instance.channel = channel instance.registrar = registrar } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { let args = call.arguments as? [String: Any]; switch call.method { case "getPlatformVersion": result("iOS " + UIDevice.current.systemVersion) break case "mixinVideoAndAudio": let videoPath = args!["videoPath"] as! String; let bgmPath = args!["bgmPath"] as! String; let resultPath = args!["resultPath"] as! String; mixinVideo(bgmPath: bgmPath, videoPath: videoPath, outPath: resultPath, result: result) break case "mixinAudio": let bgmPath = args!["bgmPath"] as! String; let audioPathList = args!["audioPaths"] as! [String]; let startTimeList = args!["startTimeList"] as! [Double]; let pathVideoMixinDir = args!["resultPath"] as! String; mixinAudio(bgmPath: bgmPath, audioPathList: audioPathList, startTimeList: startTimeList, outPath: pathVideoMixinDir, result: result) break; case "setExtraFullScreen": result("") break default: result(FlutterMethodNotImplemented) } } /// 合成音频 func mixinAudio(bgmPath: String, audioPathList: [String], startTimeList: [Double], outPath: String, result: @escaping FlutterResult) { let musicUrl = URL(fileURLWithPath: bgmPath) let composer = DubbingComposer(timeline: startTimeList, musicUrl: musicUrl, recordsUrl: audioPathList) composer.preTime = preLag let outputUrl = URL(fileURLWithPath: outPath) DispatchQueue.global().async { composer.compose(outputUrl, onSuccess: { result(outPath) }) { (message) in print("合成失败", message) result(FlutterError(code: "1005", message: "mix audio failed", details: nil)) } } } /// 合成视频 func mixinVideo(bgmPath: String, videoPath: String, outPath: String, result: @escaping FlutterResult) { let musicUrl = URL(fileURLWithPath: bgmPath) let videoUrl = URL(fileURLWithPath: videoPath) let composer = VideoComposer(videoUrl: videoUrl, musicUrl: musicUrl) let outputUrl = URL(fileURLWithPath: outPath) DispatchQueue.global().async { composer.compose(outputUrl, onSuccess: { result(outPath) }) { (message) in print("合成失败", message) result(FlutterError(code: "1006", message: "mix video failed", details: nil)) } } } } extension String{ /// check string cellection is whiteSpace var isBlank : Bool{ return allSatisfy({$0.isWhitespace}) } } extension Optional where Wrapped == String{ var isBlank : Bool{ return self?.isBlank ?? true } }