mangayomi-mirror/packages/media_kit_video/ios/Classes/plugin/TextureHW.swift
kodjomoustapha 7cd4ab860c fix #206
2024-06-29 10:48:47 +01:00

205 lines
5.2 KiB
Swift

import Flutter
import OpenGLES
public class TextureHW: NSObject, FlutterTexture, ResizableTextureProtocol {
public typealias UpdateCallback = () -> Void
private let handle: OpaquePointer
private let updateCallback: UpdateCallback
private let context: EAGLContext
private let textureCache: CVOpenGLESTextureCache
private var renderContext: OpaquePointer?
private var textureContexts = SwappableObjectManager<TextureGLESContext>(
objects: [],
skipCheckArgs: true
)
init(
handle: OpaquePointer,
updateCallback: @escaping UpdateCallback
) {
self.handle = handle
self.updateCallback = updateCallback
self.context = OpenGLESHelpers.createContext()
self.textureCache = OpenGLESHelpers.createTextureCache(context)
super.init()
self.initMPV()
}
deinit {
disposePixelBuffer()
disposeMPV()
OpenGLESHelpers.deleteTextureCache(textureCache)
// Deleting the context may cause potential RAM or VRAM memory leaks, as it
// is used in the `deinit` method of the `TextureGLESContext`.
// Potential fix: use a counter, and delete it only when the counter reaches
// zero
OpenGLESHelpers.deleteContext(context)
}
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
let textureContext = textureContexts.current
if textureContext == nil {
return nil
}
return Unmanaged.passRetained(textureContext!.pixelBuffer)
}
private func initMPV() {
EAGLContext.setCurrent(context)
defer {
OpenGLESHelpers.checkError("initMPV")
EAGLContext.setCurrent(nil)
}
let api = UnsafeMutableRawPointer(
mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String
)
var procAddress = mpv_opengl_init_params(
get_proc_address: {
(ctx, name) in
return TextureHW.getProcAddress(ctx, name)
},
get_proc_address_ctx: nil
)
var params: [mpv_render_param] = withUnsafeMutableBytes(of: &procAddress) {
procAddress in
return [
mpv_render_param(type: MPV_RENDER_PARAM_API_TYPE, data: api),
mpv_render_param(
type: MPV_RENDER_PARAM_OPENGL_INIT_PARAMS,
data: procAddress.baseAddress.map {
UnsafeMutableRawPointer($0)
}
),
mpv_render_param(),
]
}
MPVHelpers.checkError(
mpv_render_context_create(&renderContext, handle, &params)
)
mpv_render_context_set_update_callback(
renderContext,
{ (ctx) in
let that = unsafeBitCast(ctx, to: TextureHW.self)
DispatchQueue.main.async {
that.updateCallback()
}
},
UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
)
}
private func disposeMPV() {
EAGLContext.setCurrent(context)
defer {
OpenGLESHelpers.checkError("disposeMPV")
EAGLContext.setCurrent(nil)
}
mpv_render_context_set_update_callback(renderContext, nil, nil)
mpv_render_context_free(renderContext)
}
public func resize(_ size: CGSize) {
if size.width == 0 || size.height == 0 {
return
}
NSLog("TextureGL: resize: \(size.width)x\(size.height)")
createPixelBuffer(size)
}
private func createPixelBuffer(_ size: CGSize) {
disposePixelBuffer()
textureContexts.reinit(
objects: [
TextureGLESContext(
context: context,
textureCache: textureCache,
size: size
),
TextureGLESContext(
context: context,
textureCache: textureCache,
size: size
),
TextureGLESContext(
context: context,
textureCache: textureCache,
size: size
),
],
skipCheckArgs: true
)
}
private func disposePixelBuffer() {
textureContexts.reinit(objects: [], skipCheckArgs: true)
}
public func render(_ size: CGSize) {
let textureContext = textureContexts.nextAvailable()
if textureContext == nil {
return
}
EAGLContext.setCurrent(context)
defer {
OpenGLESHelpers.checkError("render")
EAGLContext.setCurrent(nil)
}
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), textureContext!.frameBuffer)
defer {
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), 0)
}
var fbo = mpv_opengl_fbo(
fbo: Int32(textureContext!.frameBuffer),
w: Int32(size.width),
h: Int32(size.height),
internal_format: 0
)
let fboPtr = withUnsafeMutablePointer(to: &fbo) { $0 }
var params: [mpv_render_param] = [
mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: fboPtr),
mpv_render_param(type: MPV_RENDER_PARAM_INVALID, data: nil),
]
mpv_render_context_render(renderContext, &params)
glFlush()
textureContexts.pushAsReady(textureContext!)
}
static private func getProcAddress(
_ ctx: UnsafeMutableRawPointer?,
_ name: UnsafePointer<Int8>?
) -> UnsafeMutableRawPointer? {
let symbol: CFString = CFStringCreateWithCString(
kCFAllocatorDefault,
name,
kCFStringEncodingASCII
)
let indentifier = CFBundleGetBundleWithIdentifier(
"com.apple.opengles" as CFString
)
let addr = CFBundleGetFunctionPointerForName(indentifier, symbol)
if addr == nil {
NSLog("Cannot get OpenGLES function pointer!")
}
return addr
}
}