115 lines
4.3 KiB
Swift
115 lines
4.3 KiB
Swift
import Adwaita
|
|
import CAdw
|
|
import CMPV
|
|
|
|
struct VideoPlayerWidget: Widget {
|
|
|
|
var url: String
|
|
@Binding var isPlaying: Bool
|
|
@Binding var position: Double
|
|
@Binding var duration: Double
|
|
|
|
func container<Data>(
|
|
data: WidgetData,
|
|
type: Data.Type
|
|
) -> ViewStorage where Data: ViewRenderData {
|
|
let glArea = gtk_gl_area_new()!
|
|
gtk_gl_area_set_required_version(glArea, 3, 2)
|
|
gtk_gl_area_set_auto_render(glArea, true)
|
|
|
|
let mpv = mpv_create()!
|
|
mpv_set_option_string(mpv, "vo", "gpu")
|
|
mpv_set_option_string(mpv, "hwdec", "auto")
|
|
mpv_initialize(mpv)
|
|
|
|
let mpvPtr = Unmanaged.passRetained(mpv as AnyObject).toOpaque()
|
|
g_object_set_data(glArea, "mpv", mpvPtr)
|
|
|
|
g_signal_connect_data(glArea, "realize", GCallback(c_realize), mpvPtr, nil, G_CONNECT_AFTER)
|
|
g_signal_connect_data(glArea, "render", GCallback(c_render), mpvPtr, nil, G_CONNECT_AFTER)
|
|
g_signal_connect_data(glArea, "unrealize", GCallback(c_unrealize), mpvPtr, nil, G_CONNECT_AFTER)
|
|
|
|
return ViewStorage(glArea.pointee.widget.pointee.opaque())
|
|
}
|
|
|
|
func update<Data>(
|
|
_ storage: ViewStorage,
|
|
data: WidgetData,
|
|
updateProperties: Bool,
|
|
type: Data.Type
|
|
) where Data: ViewRenderData {
|
|
let ptr = storage.opaquePointer?.opaque(WidgetData.self)
|
|
guard let ptr else { return }
|
|
}
|
|
}
|
|
|
|
private func c_realize(widget: UnsafeMutableRawPointer?, data: UnsafeMutableRawPointer?) {
|
|
guard let widget, let data else { return }
|
|
let glArea = widget.opaque(OpaquePointer.self)
|
|
gtk_gl_area_make_current(glArea)
|
|
let mpv = Unmanaged<AnyObject>.fromOpaque(data).takeUnretainedValue()
|
|
let mpvHandle = mpv.opaque(OpaquePointer.self)
|
|
|
|
var initParams = mpv_opengl_init_params(
|
|
get_proc_address: mpv_get_proc_address,
|
|
get_proc_address_ctx: nil
|
|
)
|
|
withUnsafeMutablePointer(to: &initParams) { params in
|
|
var renderParams: [mpv_render_param] = [
|
|
mpv_render_param(type: MPV_RENDER_PARAM_INITIALIZATION_PARAMS, data: params),
|
|
mpv_render_param()
|
|
]
|
|
var renderContext: OpaquePointer?
|
|
mpv_render_context_create(&renderContext, mpvHandle, &renderParams)
|
|
if let renderContext {
|
|
let ctxPtr = Unmanaged.passRetained(renderContext as AnyObject).toOpaque()
|
|
g_object_set_data(glArea, "mpv-render-context", ctxPtr)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func c_render(widget: UnsafeMutableRawPointer?, data: UnsafeMutableRawPointer?) -> Bool {
|
|
guard let widget else { return false }
|
|
let glArea = widget.opaque(OpaquePointer.self)
|
|
guard let ctxPtr = g_object_get_data(glArea, "mpv-render-context") else { return false }
|
|
let renderContext = Unmanaged<AnyObject>.fromOpaque(ctxPtr).takeUnretainedValue()
|
|
let renderCtx = renderContext.opaque(OpaquePointer.self)
|
|
|
|
var fbo: Int32 = 0
|
|
glGetIntegerv(GLenum(GL_FRAMEBUFFER_BINDING), &fbo)
|
|
var dims: [Int32] = [0, 0]
|
|
dims[0] = gtk_widget_get_width(gtk_widget_get_parent(glArea))
|
|
dims[1] = gtk_widget_get_height(gtk_widget_get_parent(glArea))
|
|
|
|
var renderParams: [mpv_render_param] = [
|
|
mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: &fbo),
|
|
mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: [Int32(1)]),
|
|
mpv_render_param(type: MPV_RENDER_PARAM_PRESENT_FENCE, data: [Int32(0)]),
|
|
mpv_render_param()
|
|
]
|
|
mpv_render_context_render(renderCtx, &renderParams)
|
|
return true
|
|
}
|
|
|
|
private func c_unrealize(widget: UnsafeMutableRawPointer?, data: UnsafeMutableRawPointer?) {
|
|
guard let widget else { return }
|
|
let glArea = widget.opaque(OpaquePointer.self)
|
|
if let ctxPtr = g_object_get_data(glArea, "mpv-render-context") {
|
|
let renderContext = Unmanaged<AnyObject>.fromOpaque(ctxPtr).takeUnretainedValue()
|
|
let renderCtx = renderContext.opaque(OpaquePointer.self)
|
|
mpv_render_context_free(renderCtx)
|
|
}
|
|
if let mpvPtr = g_object_get_data(glArea, "mpv") {
|
|
let mpv = Unmanaged<AnyObject>.fromOpaque(mpvPtr).takeUnretainedValue()
|
|
let mpvHandle = mpv.opaque(OpaquePointer.self)
|
|
mpv_terminate_destroy(mpvHandle)
|
|
}
|
|
}
|
|
|
|
private func mpv_get_proc_address(
|
|
_ ctx: UnsafeMutableRawPointer?,
|
|
_ name: UnsafePointer<CChar>?
|
|
) -> UnsafeMutableRawPointer? {
|
|
guard let name else { return nil }
|
|
return glXGetProcAddress(name)
|
|
}
|