diff options
Diffstat (limited to 'video/out/cocoa_cb_common.swift')
-rw-r--r-- | video/out/cocoa_cb_common.swift | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/video/out/cocoa_cb_common.swift b/video/out/cocoa_cb_common.swift new file mode 100644 index 0000000..9c0054a --- /dev/null +++ b/video/out/cocoa_cb_common.swift @@ -0,0 +1,230 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see <http://www.gnu.org/licenses/>. + */ + +import Cocoa + +class CocoaCB: Common { + var libmpv: LibmpvHelper + var layer: GLLayer? + + @objc var isShuttingDown: Bool = false + + enum State { + case uninitialized + case needsInit + case initialized + } + var backendState: State = .uninitialized + + + @objc init(_ mpvHandle: OpaquePointer) { + let newlog = mp_log_new(UnsafeMutablePointer<MPContext>(mpvHandle), mp_client_get_log(mpvHandle), "cocoacb") + libmpv = LibmpvHelper(mpvHandle, newlog) + super.init(newlog) + layer = GLLayer(cocoaCB: self) + } + + func preinit(_ vo: UnsafeMutablePointer<vo>) { + mpv = MPVHelper(vo, log) + + if backendState == .uninitialized { + backendState = .needsInit + + guard let layer = self.layer else { + log.sendError("Something went wrong, no GLLayer was initialized") + exit(1) + } + + initView(vo, layer) + initMisc(vo) + } + } + + func uninit() { + window?.orderOut(nil) + window?.close() + mpv = nil + } + + func reconfig(_ vo: UnsafeMutablePointer<vo>) { + mpv?.vo = vo + if backendState == .needsInit { + DispatchQueue.main.sync { self.initBackend(vo) } + } else { + DispatchQueue.main.async { + self.updateWindowSize(vo) + self.layer?.update(force: true) + } + } + } + + func initBackend(_ vo: UnsafeMutablePointer<vo>) { + let previousActiveApp = getActiveApp() + initApp() + initWindow(vo, previousActiveApp) + updateICCProfile() + initWindowState() + + backendState = .initialized + } + + func updateWindowSize(_ vo: UnsafeMutablePointer<vo>) { + guard let targetScreen = getTargetScreen(forFullscreen: false) ?? NSScreen.main else + { + log.sendWarning("Couldn't update Window size, no Screen available") + return + } + + let wr = getWindowGeometry(forScreen: targetScreen, videoOut: vo) + if !(window?.isVisible ?? false) && + !(window?.isMiniaturized ?? false) && + !NSApp.isHidden + { + window?.makeKeyAndOrderFront(nil) + } + layer?.atomicDrawingStart() + window?.updateSize(wr.size) + } + + override func displayLinkCallback(_ displayLink: CVDisplayLink, + _ inNow: UnsafePointer<CVTimeStamp>, + _ inOutputTime: UnsafePointer<CVTimeStamp>, + _ flagsIn: CVOptionFlags, + _ flagsOut: UnsafeMutablePointer<CVOptionFlags>) -> CVReturn + { + libmpv.reportRenderFlip() + return kCVReturnSuccess + } + + override func lightSensorUpdate() { + libmpv.setRenderLux(lmuToLux(lastLmu)) + } + + override func updateICCProfile() { + guard let colorSpace = window?.screen?.colorSpace else { + log.sendWarning("Couldn't update ICC Profile, no color space available") + return + } + + libmpv.setRenderICCProfile(colorSpace) + layer?.colorspace = colorSpace.cgColorSpace + } + + override func windowDidEndAnimation() { + layer?.update() + checkShutdown() + } + + override func windowSetToFullScreen() { + layer?.update(force: true) + } + + override func windowSetToWindow() { + layer?.update(force: true) + } + + override func windowDidUpdateFrame() { + layer?.update(force: true) + } + + override func windowDidChangeScreen() { + layer?.update(force: true) + } + + override func windowDidChangeScreenProfile() { + layer?.needsICCUpdate = true + } + + override func windowDidChangeBackingProperties() { + layer?.contentsScale = window?.backingScaleFactor ?? 1 + } + + override func windowWillStartLiveResize() { + layer?.inLiveResize = true + } + + override func windowDidEndLiveResize() { + layer?.inLiveResize = false + } + + override func windowDidChangeOcclusionState() { + layer?.update(force: true) + } + + var controlCallback: mp_render_cb_control_fn = { ( v, ctx, e, request, data ) -> Int32 in + let ccb = unsafeBitCast(ctx, to: CocoaCB.self) + + guard let vo = v, let events = e else { + ccb.log.sendWarning("Unexpected nil value in Control Callback") + return VO_FALSE + } + + return ccb.control(vo, events: events, request: request, data: data) + } + + override func control(_ vo: UnsafeMutablePointer<vo>, + events: UnsafeMutablePointer<Int32>, + request: UInt32, + data: UnsafeMutableRawPointer?) -> Int32 + { + switch mp_voctrl(request) { + case VOCTRL_PREINIT: + DispatchQueue.main.sync { self.preinit(vo) } + return VO_TRUE + case VOCTRL_UNINIT: + DispatchQueue.main.async { self.uninit() } + return VO_TRUE + case VOCTRL_RECONFIG: + reconfig(vo) + return VO_TRUE + default: + break + } + + return super.control(vo, events: events, request: request, data: data) + } + + func shutdown(_ destroy: Bool = false) { + isShuttingDown = window?.isAnimating ?? false || + window?.isInFullscreen ?? false && mpv?.opts.native_fs ?? true + if window?.isInFullscreen ?? false && !(window?.isAnimating ?? false) { + window?.close() + } + if isShuttingDown { return } + + uninit() + uninitCommon() + + libmpv.deinitRender() + libmpv.deinitMPV(destroy) + } + + func checkShutdown() { + if isShuttingDown { + shutdown(true) + } + } + + @objc func processEvent(_ event: UnsafePointer<mpv_event>) { + switch event.pointee.event_id { + case MPV_EVENT_SHUTDOWN: + shutdown() + default: + break + } + } +} |