chore: add native formatting checks
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#include "mpv_player.h"
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/egl.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
#include <gdk/gdk.h>
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/gdkx.h>
|
||||
@@ -24,9 +24,7 @@ namespace mpv {
|
||||
|
||||
MpvPlayer::MpvPlayer() {}
|
||||
|
||||
MpvPlayer::~MpvPlayer() {
|
||||
Dispose();
|
||||
}
|
||||
MpvPlayer::~MpvPlayer() { Dispose(); }
|
||||
|
||||
bool MpvPlayer::Initialize() {
|
||||
if (mpv_) {
|
||||
@@ -111,7 +109,7 @@ bool MpvPlayer::InitRenderContext() {
|
||||
}
|
||||
|
||||
EGLint num_configs = 0;
|
||||
EGLint config_attribs[] = { EGL_CONFIG_ID, config_id, EGL_NONE };
|
||||
EGLint config_attribs[] = {EGL_CONFIG_ID, config_id, EGL_NONE};
|
||||
if (!eglChooseConfig(egl_display_, config_attribs, &config, 1, &num_configs) || num_configs == 0) {
|
||||
g_warning("MPV: Failed to get Flutter's EGL config");
|
||||
return false;
|
||||
@@ -121,7 +119,8 @@ bool MpvPlayer::InitRenderContext() {
|
||||
// GL state pollution
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
EGLint context_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_CONTEXT_CLIENT_VERSION,
|
||||
2,
|
||||
EGL_NONE,
|
||||
};
|
||||
egl_context_ = eglCreateContext(egl_display_, config, EGL_NO_CONTEXT, context_attribs);
|
||||
@@ -142,8 +141,7 @@ bool MpvPlayer::InitRenderContext() {
|
||||
};
|
||||
|
||||
mpv_render_param params[] = {
|
||||
{MPV_RENDER_PARAM_API_TYPE,
|
||||
const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL)},
|
||||
{MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_OPENGL)},
|
||||
{MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &gl_init_params},
|
||||
{MPV_RENDER_PARAM_INVALID, nullptr}, // slot for X11/Wayland display
|
||||
{MPV_RENDER_PARAM_INVALID, nullptr},
|
||||
@@ -170,8 +168,7 @@ bool MpvPlayer::InitRenderContext() {
|
||||
eglMakeCurrent(egl_display_, flutter_draw, flutter_read, flutter_context);
|
||||
|
||||
if (err < 0) {
|
||||
g_warning("MPV: mpv_render_context_create() failed: %s",
|
||||
mpv_error_string(err));
|
||||
g_warning("MPV: mpv_render_context_create() failed: %s", mpv_error_string(err));
|
||||
eglDestroyContext(egl_display_, egl_context_);
|
||||
egl_context_ = EGL_NO_CONTEXT;
|
||||
return false;
|
||||
@@ -287,8 +284,7 @@ void MpvPlayer::Command(const std::vector<std::string>& args) {
|
||||
mpv_command(mpv_, c_args.data());
|
||||
}
|
||||
|
||||
void MpvPlayer::CommandAsync(const std::vector<std::string>& args,
|
||||
CommandCallback callback) {
|
||||
void MpvPlayer::CommandAsync(const std::vector<std::string>& args, CommandCallback callback) {
|
||||
if (disposed_ || !mpv_) {
|
||||
if (callback) callback(0);
|
||||
return;
|
||||
@@ -336,9 +332,7 @@ std::string MpvPlayer::GetProperty(const std::string& name) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void MpvPlayer::ObserveProperty(const std::string& name,
|
||||
const std::string& format,
|
||||
int id) {
|
||||
void MpvPlayer::ObserveProperty(const std::string& name, const std::string& format, int id) {
|
||||
if (disposed_ || !mpv_) return;
|
||||
|
||||
if (observed_properties_.find(name) != observed_properties_.end()) {
|
||||
@@ -403,8 +397,7 @@ void MpvPlayer::OnMpvWakeup(void* ctx) {
|
||||
}
|
||||
return G_SOURCE_REMOVE;
|
||||
},
|
||||
player,
|
||||
nullptr);
|
||||
player, nullptr);
|
||||
}
|
||||
|
||||
void MpvPlayer::OnMpvRenderUpdate(void* ctx) {
|
||||
@@ -482,12 +475,9 @@ void MpvPlayer::HandleMpvEvent(mpv_event* event) {
|
||||
g_message("MPV [%s] %s: %s", msg->level, msg->prefix, msg->text);
|
||||
|
||||
FlValue* data = fl_value_new_map();
|
||||
fl_value_set_string_take(data, "prefix",
|
||||
fl_value_new_string(SanitizeUtf8(msg->prefix).c_str()));
|
||||
fl_value_set_string_take(data, "level",
|
||||
fl_value_new_string(SanitizeUtf8(msg->level).c_str()));
|
||||
fl_value_set_string_take(data, "text",
|
||||
fl_value_new_string(SanitizeUtf8(msg->text).c_str()));
|
||||
fl_value_set_string_take(data, "prefix", fl_value_new_string(SanitizeUtf8(msg->prefix).c_str()));
|
||||
fl_value_set_string_take(data, "level", fl_value_new_string(SanitizeUtf8(msg->level).c_str()));
|
||||
fl_value_set_string_take(data, "text", fl_value_new_string(SanitizeUtf8(msg->text).c_str()));
|
||||
SendEvent("log-message", data);
|
||||
fl_value_unref(data);
|
||||
break;
|
||||
@@ -499,8 +489,7 @@ void MpvPlayer::HandleMpvEvent(mpv_event* event) {
|
||||
|
||||
switch (prop->format) {
|
||||
case MPV_FORMAT_STRING:
|
||||
node.u.string =
|
||||
prop->data ? *static_cast<char**>(prop->data) : nullptr;
|
||||
node.u.string = prop->data ? *static_cast<char**>(prop->data) : nullptr;
|
||||
break;
|
||||
case MPV_FORMAT_FLAG:
|
||||
node.u.flag = prop->data ? *static_cast<int*>(prop->data) : 0;
|
||||
@@ -527,13 +516,11 @@ void MpvPlayer::HandleMpvEvent(mpv_event* event) {
|
||||
case MPV_EVENT_END_FILE: {
|
||||
auto* end = static_cast<mpv_event_end_file*>(event->data);
|
||||
FlValue* data = fl_value_new_map();
|
||||
fl_value_set_string_take(data, "reason",
|
||||
fl_value_new_int(static_cast<int>(end->reason)));
|
||||
fl_value_set_string_take(data, "reason", fl_value_new_int(static_cast<int>(end->reason)));
|
||||
if (end->reason == MPV_END_FILE_REASON_ERROR) {
|
||||
fl_value_set_string_take(data, "error",
|
||||
fl_value_new_int(static_cast<int>(end->error)));
|
||||
fl_value_set_string_take(data, "message",
|
||||
fl_value_new_string(SanitizeUtf8(mpv_error_string(end->error)).c_str()));
|
||||
fl_value_set_string_take(data, "error", fl_value_new_int(static_cast<int>(end->error)));
|
||||
fl_value_set_string_take(
|
||||
data, "message", fl_value_new_string(SanitizeUtf8(mpv_error_string(end->error)).c_str()));
|
||||
}
|
||||
SendEvent("end-file", data);
|
||||
fl_value_unref(data);
|
||||
@@ -578,9 +565,7 @@ FlValue* MpvPlayer::NodeToFlValue(mpv_node* node) {
|
||||
case MPV_FORMAT_NODE_MAP: {
|
||||
FlValue* map = fl_value_new_map();
|
||||
for (int i = 0; i < node->u.list->num; i++) {
|
||||
fl_value_set_string_take(
|
||||
map, node->u.list->keys[i],
|
||||
NodeToFlValue(&node->u.list->values[i]));
|
||||
fl_value_set_string_take(map, node->u.list->keys[i], NodeToFlValue(&node->u.list->values[i]));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef MPV_PLAYER_H_
|
||||
#define MPV_PLAYER_H_
|
||||
|
||||
#include <epoxy/egl.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <mpv/client.h>
|
||||
#include <mpv/render.h>
|
||||
#include <mpv/render_gl.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
@@ -84,8 +84,7 @@ class MpvPlayer {
|
||||
std::string GetProperty(const std::string& name);
|
||||
|
||||
/// Observes an mpv property for changes.
|
||||
void ObserveProperty(const std::string& name, const std::string& format,
|
||||
int id);
|
||||
void ObserveProperty(const std::string& name, const std::string& format, int id);
|
||||
|
||||
/// Renders a frame to the specified FBO.
|
||||
void Render(int width, int height, int fbo = 0);
|
||||
|
||||
+56
-108
@@ -1,8 +1,9 @@
|
||||
#include "mpv_plugin.h"
|
||||
#include "mpv_texture.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "mpv_texture.h"
|
||||
|
||||
struct _MpvPlugin {
|
||||
GObject parent_instance;
|
||||
|
||||
@@ -12,7 +13,7 @@ struct _MpvPlugin {
|
||||
FlTextureRegistrar* texture_registrar;
|
||||
|
||||
std::unique_ptr<mpv::MpvPlayer> player;
|
||||
MpvTexture* texture; // owned via GObject ref
|
||||
MpvTexture* texture; // owned via GObject ref
|
||||
gboolean visible;
|
||||
gboolean initialized;
|
||||
};
|
||||
@@ -20,9 +21,7 @@ struct _MpvPlugin {
|
||||
G_DEFINE_TYPE(MpvPlugin, mpv_plugin, G_TYPE_OBJECT)
|
||||
|
||||
// Forward declarations
|
||||
static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
FlMethodCall* method_call,
|
||||
gpointer user_data);
|
||||
static void mpv_plugin_handle_method_call(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data);
|
||||
|
||||
static void send_event(MpvPlugin* self, FlValue* event) {
|
||||
if (self->event_channel) {
|
||||
@@ -43,8 +42,7 @@ static void mpv_plugin_dispose(GObject* object) {
|
||||
if (self->texture) {
|
||||
mpv_texture_dispose(self->texture);
|
||||
if (self->texture_registrar) {
|
||||
fl_texture_registrar_unregister_texture(self->texture_registrar,
|
||||
FL_TEXTURE(self->texture));
|
||||
fl_texture_registrar_unregister_texture(self->texture_registrar, FL_TEXTURE(self->texture));
|
||||
}
|
||||
g_object_unref(self->texture);
|
||||
self->texture = nullptr;
|
||||
@@ -62,9 +60,7 @@ static void mpv_plugin_dispose(GObject* object) {
|
||||
G_OBJECT_CLASS(mpv_plugin_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
static void mpv_plugin_class_init(MpvPluginClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = mpv_plugin_dispose;
|
||||
}
|
||||
static void mpv_plugin_class_init(MpvPluginClass* klass) { G_OBJECT_CLASS(klass)->dispose = mpv_plugin_dispose; }
|
||||
|
||||
static void mpv_plugin_init(MpvPlugin* self) {
|
||||
self->visible = FALSE;
|
||||
@@ -77,26 +73,17 @@ MpvPlugin* mpv_plugin_new(FlPluginRegistrar* registrar) {
|
||||
MpvPlugin* self = MPV_PLUGIN(g_object_new(MPV_PLUGIN_TYPE, nullptr));
|
||||
|
||||
self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar));
|
||||
self->texture_registrar =
|
||||
fl_plugin_registrar_get_texture_registrar(registrar);
|
||||
self->texture_registrar = fl_plugin_registrar_get_texture_registrar(registrar);
|
||||
self->player = std::make_unique<mpv::MpvPlayer>();
|
||||
|
||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||
self->method_channel = fl_method_channel_new(
|
||||
fl_plugin_registrar_get_messenger(registrar),
|
||||
"com.plezy/mpv_player",
|
||||
FL_METHOD_CODEC(codec));
|
||||
fl_plugin_registrar_get_messenger(registrar), "com.plezy/mpv_player", FL_METHOD_CODEC(codec));
|
||||
|
||||
fl_method_channel_set_method_call_handler(
|
||||
self->method_channel,
|
||||
mpv_plugin_handle_method_call,
|
||||
self,
|
||||
nullptr);
|
||||
fl_method_channel_set_method_call_handler(self->method_channel, mpv_plugin_handle_method_call, self, nullptr);
|
||||
|
||||
self->event_channel = fl_event_channel_new(
|
||||
fl_plugin_registrar_get_messenger(registrar),
|
||||
"com.plezy/mpv_player/events",
|
||||
FL_METHOD_CODEC(codec));
|
||||
fl_plugin_registrar_get_messenger(registrar), "com.plezy/mpv_player/events", FL_METHOD_CODEC(codec));
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -104,14 +91,10 @@ MpvPlugin* mpv_plugin_new(FlPluginRegistrar* registrar) {
|
||||
// Static reference to keep the plugin alive.
|
||||
static MpvPlugin* g_mpv_plugin = nullptr;
|
||||
|
||||
void mpv_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
|
||||
g_mpv_plugin = mpv_plugin_new(registrar);
|
||||
}
|
||||
void mpv_plugin_register_with_registrar(FlPluginRegistrar* registrar) { g_mpv_plugin = mpv_plugin_new(registrar); }
|
||||
|
||||
/// Method call handler.
|
||||
static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
FlMethodCall* method_call,
|
||||
gpointer user_data) {
|
||||
static void mpv_plugin_handle_method_call(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) {
|
||||
(void)channel;
|
||||
MpvPlugin* self = MPV_PLUGIN(user_data);
|
||||
const gchar* method = fl_method_call_get_name(method_call);
|
||||
@@ -122,8 +105,8 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
if (strcmp(method, "initialize") == 0) {
|
||||
if (self->initialized && self->texture) {
|
||||
// Already initialized — return existing texture ID
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(
|
||||
fl_value_new_int(mpv_texture_get_id(self->texture))));
|
||||
response =
|
||||
FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_int(mpv_texture_get_id(self->texture))));
|
||||
} else {
|
||||
// Create player if it was disposed or doesn't exist
|
||||
if (!self->player || self->player->IsDisposed()) {
|
||||
@@ -133,11 +116,9 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
if (self->player->Initialize()) {
|
||||
// Create the FlTextureGL and register it
|
||||
FlView* view = fl_plugin_registrar_get_view(self->registrar);
|
||||
self->texture = mpv_texture_new(
|
||||
self->player.get(), self->texture_registrar, view);
|
||||
self->texture = mpv_texture_new(self->player.get(), self->texture_registrar, view);
|
||||
|
||||
fl_texture_registrar_register_texture(
|
||||
self->texture_registrar, FL_TEXTURE(self->texture));
|
||||
fl_texture_registrar_register_texture(self->texture_registrar, FL_TEXTURE(self->texture));
|
||||
|
||||
// Create the render context eagerly — mpv needs it BEFORE any
|
||||
// file is loaded, otherwise VO init fails with "No render context
|
||||
@@ -146,23 +127,19 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
|
||||
// Set redraw callback: when mpv has a frame, mark texture available
|
||||
MpvTexture* tex = self->texture;
|
||||
self->player->SetRedrawCallback([tex]() {
|
||||
mpv_texture_mark_frame_available(tex);
|
||||
});
|
||||
self->player->SetRedrawCallback([tex]() { mpv_texture_mark_frame_available(tex); });
|
||||
|
||||
self->initialized = TRUE;
|
||||
|
||||
// Set up event callback
|
||||
self->player->SetEventCallback([self](FlValue* event) {
|
||||
send_event(self, event);
|
||||
});
|
||||
self->player->SetEventCallback([self](FlValue* event) { send_event(self, event); });
|
||||
|
||||
// Return the texture ID for the Dart Texture widget
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(
|
||||
fl_value_new_int(mpv_texture_get_id(self->texture))));
|
||||
response =
|
||||
FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_int(mpv_texture_get_id(self->texture))));
|
||||
} else {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INIT_FAILED", "Failed to initialize MPV player", nullptr));
|
||||
response =
|
||||
FL_METHOD_RESPONSE(fl_method_error_response_new("INIT_FAILED", "Failed to initialize MPV player", nullptr));
|
||||
}
|
||||
}
|
||||
} else if (strcmp(method, "dispose") == 0) {
|
||||
@@ -171,8 +148,7 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
// during player disposal.
|
||||
if (self->texture) {
|
||||
mpv_texture_dispose(self->texture);
|
||||
fl_texture_registrar_unregister_texture(self->texture_registrar,
|
||||
FL_TEXTURE(self->texture));
|
||||
fl_texture_registrar_unregister_texture(self->texture_registrar, FL_TEXTURE(self->texture));
|
||||
g_object_unref(self->texture);
|
||||
self->texture = nullptr;
|
||||
}
|
||||
@@ -186,14 +162,11 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
} else if (strcmp(method, "command") == 0) {
|
||||
if (!self->player || !self->initialized) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
} else {
|
||||
FlValue* args_value = fl_value_lookup_string(args, "args");
|
||||
if (args_value == nullptr ||
|
||||
fl_value_get_type(args_value) != FL_VALUE_TYPE_LIST) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'args' list", nullptr));
|
||||
if (args_value == nullptr || fl_value_get_type(args_value) != FL_VALUE_TYPE_LIST) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'args' list", nullptr));
|
||||
} else {
|
||||
std::vector<std::string> command_args;
|
||||
size_t len = fl_value_get_length(args_value);
|
||||
@@ -207,8 +180,8 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
self->player->CommandAsync(command_args, [method_call](int error) {
|
||||
g_autoptr(FlMethodResponse) async_response = nullptr;
|
||||
if (error < 0) {
|
||||
async_response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"COMMAND_FAILED", "MPV command failed", nullptr));
|
||||
async_response =
|
||||
FL_METHOD_RESPONSE(fl_method_error_response_new("COMMAND_FAILED", "MPV command failed", nullptr));
|
||||
} else {
|
||||
async_response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
}
|
||||
@@ -220,37 +193,28 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
}
|
||||
} else if (strcmp(method, "setProperty") == 0) {
|
||||
if (!self->player || !self->initialized) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
} else {
|
||||
FlValue* name_value = fl_value_lookup_string(args, "name");
|
||||
FlValue* value_value = fl_value_lookup_string(args, "value");
|
||||
|
||||
if (name_value == nullptr ||
|
||||
fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
} else if (value_value == nullptr ||
|
||||
fl_value_get_type(value_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'value'", nullptr));
|
||||
if (name_value == nullptr || fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
} else if (value_value == nullptr || fl_value_get_type(value_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'value'", nullptr));
|
||||
} else {
|
||||
self->player->SetProperty(fl_value_get_string(name_value),
|
||||
fl_value_get_string(value_value));
|
||||
self->player->SetProperty(fl_value_get_string(name_value), fl_value_get_string(value_value));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
}
|
||||
}
|
||||
} else if (strcmp(method, "setLogLevel") == 0) {
|
||||
if (!self->player || !self->initialized) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
} else {
|
||||
FlValue* level_value = fl_value_lookup_string(args, "level");
|
||||
|
||||
if (level_value == nullptr ||
|
||||
fl_value_get_type(level_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'level'", nullptr));
|
||||
if (level_value == nullptr || fl_value_get_type(level_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'level'", nullptr));
|
||||
} else {
|
||||
self->player->SetLogLevel(fl_value_get_string(level_value));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
@@ -258,62 +222,47 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
}
|
||||
} else if (strcmp(method, "getProperty") == 0) {
|
||||
if (!self->player || !self->initialized) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
} else {
|
||||
FlValue* name_value = fl_value_lookup_string(args, "name");
|
||||
|
||||
if (name_value == nullptr ||
|
||||
fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
if (name_value == nullptr || fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
} else {
|
||||
std::string value =
|
||||
self->player->GetProperty(fl_value_get_string(name_value));
|
||||
std::string value = self->player->GetProperty(fl_value_get_string(name_value));
|
||||
if (value.empty()) {
|
||||
response =
|
||||
FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
} else {
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(
|
||||
fl_value_new_string(value.c_str())));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_string(value.c_str())));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (strcmp(method, "observeProperty") == 0) {
|
||||
if (!self->player || !self->initialized) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("NOT_INITIALIZED", "Player not initialized", nullptr));
|
||||
} else {
|
||||
FlValue* name_value = fl_value_lookup_string(args, "name");
|
||||
FlValue* format_value = fl_value_lookup_string(args, "format");
|
||||
FlValue* id_value = fl_value_lookup_string(args, "id");
|
||||
|
||||
if (name_value == nullptr ||
|
||||
fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
} else if (format_value == nullptr ||
|
||||
fl_value_get_type(format_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'format'", nullptr));
|
||||
} else if (id_value == nullptr ||
|
||||
fl_value_get_type(id_value) != FL_VALUE_TYPE_INT) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'id'", nullptr));
|
||||
if (name_value == nullptr || fl_value_get_type(name_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'name'", nullptr));
|
||||
} else if (format_value == nullptr || fl_value_get_type(format_value) != FL_VALUE_TYPE_STRING) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'format'", nullptr));
|
||||
} else if (id_value == nullptr || fl_value_get_type(id_value) != FL_VALUE_TYPE_INT) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'id'", nullptr));
|
||||
} else {
|
||||
self->player->ObserveProperty(fl_value_get_string(name_value),
|
||||
fl_value_get_string(format_value),
|
||||
static_cast<int>(fl_value_get_int(id_value)));
|
||||
self->player->ObserveProperty(
|
||||
fl_value_get_string(name_value), fl_value_get_string(format_value),
|
||||
static_cast<int>(fl_value_get_int(id_value)));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
}
|
||||
}
|
||||
} else if (strcmp(method, "setVisible") == 0) {
|
||||
FlValue* visible_value = fl_value_lookup_string(args, "visible");
|
||||
|
||||
if (visible_value == nullptr ||
|
||||
fl_value_get_type(visible_value) != FL_VALUE_TYPE_BOOL) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new(
|
||||
"INVALID_ARGS", "Missing 'visible'", nullptr));
|
||||
if (visible_value == nullptr || fl_value_get_type(visible_value) != FL_VALUE_TYPE_BOOL) {
|
||||
response = FL_METHOD_RESPONSE(fl_method_error_response_new("INVALID_ARGS", "Missing 'visible'", nullptr));
|
||||
} else {
|
||||
self->visible = fl_value_get_bool(visible_value);
|
||||
|
||||
@@ -331,8 +280,7 @@ static void mpv_plugin_handle_method_call(FlMethodChannel* channel,
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
|
||||
} else if (strcmp(method, "isInitialized") == 0) {
|
||||
gboolean initialized = self->player && self->initialized;
|
||||
response = FL_METHOD_RESPONSE(
|
||||
fl_method_success_response_new(fl_value_new_bool(initialized)));
|
||||
response = FL_METHOD_RESPONSE(fl_method_success_response_new(fl_value_new_bool(initialized)));
|
||||
} else {
|
||||
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "mpv_texture.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/egl.h>
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
// EGLImage extension function pointers
|
||||
typedef EGLImageKHR (*PFNEGLCREATEIMAGEKHRPROC)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*);
|
||||
@@ -17,7 +17,8 @@ static void init_egl_image_extensions() {
|
||||
if (!initialized) {
|
||||
_eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
|
||||
_eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
|
||||
_glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
_glEGLImageTargetTexture2DOES =
|
||||
(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
@@ -25,9 +26,9 @@ static void init_egl_image_extensions() {
|
||||
struct _MpvTexture {
|
||||
FlTextureGL parent_instance;
|
||||
|
||||
mpv::MpvPlayer* player; // not owned
|
||||
FlTextureRegistrar* registrar; // not owned
|
||||
FlView* view; // not owned, for querying allocation size
|
||||
mpv::MpvPlayer* player; // not owned
|
||||
FlTextureRegistrar* registrar; // not owned
|
||||
FlView* view; // not owned, for querying allocation size
|
||||
|
||||
// mpv's FBO and texture (owned by mpv's isolated EGL context)
|
||||
GLuint mpv_fbo;
|
||||
@@ -84,19 +85,16 @@ static void ensure_textures(MpvTexture* self, int32_t w, int32_t h) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
glGenFramebuffers(1, &self->mpv_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->mpv_fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, self->mpv_texture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->mpv_texture, 0);
|
||||
|
||||
// Create EGLImage from mpv's texture for cross-context sharing
|
||||
EGLint image_attribs[] = { EGL_NONE };
|
||||
EGLint image_attribs[] = {EGL_NONE};
|
||||
self->egl_image = _eglCreateImageKHR(
|
||||
egl_display, egl_context, EGL_GL_TEXTURE_2D_KHR,
|
||||
(EGLClientBuffer)(uintptr_t)self->mpv_texture, image_attribs);
|
||||
egl_display, egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(uintptr_t)self->mpv_texture, image_attribs);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@@ -121,12 +119,8 @@ static void ensure_textures(MpvTexture* self, int32_t w, int32_t h) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
static gboolean mpv_texture_populate(FlTextureGL* gl_texture,
|
||||
uint32_t* target,
|
||||
uint32_t* name,
|
||||
uint32_t* width,
|
||||
uint32_t* height,
|
||||
GError** error) {
|
||||
static gboolean mpv_texture_populate(
|
||||
FlTextureGL* gl_texture, uint32_t* target, uint32_t* name, uint32_t* width, uint32_t* height, GError** error) {
|
||||
MpvTexture* self = MPV_TEXTURE(gl_texture);
|
||||
|
||||
if (!self->player) {
|
||||
@@ -137,8 +131,7 @@ static gboolean mpv_texture_populate(FlTextureGL* gl_texture,
|
||||
// since Flutter's GL context is current here.
|
||||
if (!self->player->HasRenderContext()) {
|
||||
if (!self->player->InitRenderContext()) {
|
||||
g_set_error(error, g_quark_from_static_string("mpv"), 0,
|
||||
"Failed to create mpv render context");
|
||||
g_set_error(error, g_quark_from_static_string("mpv"), 0, "Failed to create mpv render context");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -201,9 +194,7 @@ static void mpv_texture_init(MpvTexture* self) {
|
||||
self->height = 0;
|
||||
}
|
||||
|
||||
MpvTexture* mpv_texture_new(mpv::MpvPlayer* player,
|
||||
FlTextureRegistrar* registrar,
|
||||
FlView* view) {
|
||||
MpvTexture* mpv_texture_new(mpv::MpvPlayer* player, FlTextureRegistrar* registrar, FlView* view) {
|
||||
init_egl_image_extensions();
|
||||
MpvTexture* self = MPV_TEXTURE(g_object_new(MPV_TEXTURE_TYPE, nullptr));
|
||||
self->player = player;
|
||||
@@ -214,8 +205,7 @@ MpvTexture* mpv_texture_new(mpv::MpvPlayer* player,
|
||||
|
||||
void mpv_texture_mark_frame_available(MpvTexture* self) {
|
||||
if (self && self->registrar) {
|
||||
fl_texture_registrar_mark_texture_frame_available(
|
||||
self->registrar, FL_TEXTURE(self));
|
||||
fl_texture_registrar_mark_texture_frame_available(self->registrar, FL_TEXTURE(self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +258,4 @@ void mpv_texture_dispose(MpvTexture* self) {
|
||||
self->view = nullptr;
|
||||
}
|
||||
|
||||
int64_t mpv_texture_get_id(MpvTexture* self) {
|
||||
return fl_texture_get_id(FL_TEXTURE(self));
|
||||
}
|
||||
int64_t mpv_texture_get_id(MpvTexture* self) { return fl_texture_get_id(FL_TEXTURE(self)); }
|
||||
|
||||
@@ -12,9 +12,7 @@ G_BEGIN_DECLS
|
||||
G_DECLARE_FINAL_TYPE(MpvTexture, mpv_texture, MPV, TEXTURE, FlTextureGL)
|
||||
|
||||
/// Creates a new MpvTexture that renders mpv video to an offscreen FBO.
|
||||
MpvTexture* mpv_texture_new(mpv::MpvPlayer* player,
|
||||
FlTextureRegistrar* registrar,
|
||||
FlView* view);
|
||||
MpvTexture* mpv_texture_new(mpv::MpvPlayer* player, FlTextureRegistrar* registrar, FlView* view);
|
||||
|
||||
/// Notifies Flutter that a new frame is available.
|
||||
void mpv_texture_mark_frame_available(MpvTexture* self);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "my_application.h"
|
||||
|
||||
#include <flutter_linux/flutter_linux.h>
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
#include "mpv/mpv_plugin.h"
|
||||
|
||||
@@ -15,8 +16,7 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||
// Implements GApplication::activate.
|
||||
static void my_application_activate(GApplication* application) {
|
||||
MyApplication* self = MY_APPLICATION(application);
|
||||
GtkWindow* window =
|
||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||
|
||||
// Default to traditional titlebar. Set GTK_CSD=1 to use a header bar.
|
||||
gboolean use_header_bar = FALSE;
|
||||
@@ -38,8 +38,7 @@ static void my_application_activate(GApplication* application) {
|
||||
|
||||
// Create the Flutter view (opaque — no overlay needed).
|
||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||
fl_dart_project_set_dart_entrypoint_arguments(project,
|
||||
self->dart_entrypoint_arguments);
|
||||
fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
|
||||
|
||||
self->flutter_view = fl_view_new(project);
|
||||
gtk_widget_show(GTK_WIDGET(self->flutter_view));
|
||||
@@ -50,8 +49,7 @@ static void my_application_activate(GApplication* application) {
|
||||
|
||||
// Register the MPV plugin (uses FlTextureGL — no overlay/GtkGLArea needed).
|
||||
FlPluginRegistrar* registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(FL_PLUGIN_REGISTRY(self->flutter_view),
|
||||
"MpvPlugin");
|
||||
fl_plugin_registry_get_registrar_for_plugin(FL_PLUGIN_REGISTRY(self->flutter_view), "MpvPlugin");
|
||||
mpv_plugin_register_with_registrar(registrar);
|
||||
|
||||
gtk_widget_show(GTK_WIDGET(window));
|
||||
@@ -59,9 +57,7 @@ static void my_application_activate(GApplication* application) {
|
||||
}
|
||||
|
||||
// Implements GApplication::local_command_line.
|
||||
static gboolean my_application_local_command_line(GApplication* application,
|
||||
gchar*** arguments,
|
||||
int* exit_status) {
|
||||
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
|
||||
MyApplication* self = MY_APPLICATION(application);
|
||||
// Strip out the first argument as it is the binary name.
|
||||
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
||||
@@ -98,22 +94,17 @@ static void my_application_dispose(GObject* object) {
|
||||
|
||||
static void my_application_class_init(MyApplicationClass* klass) {
|
||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||
G_APPLICATION_CLASS(klass)->local_command_line =
|
||||
my_application_local_command_line;
|
||||
G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
|
||||
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||
}
|
||||
|
||||
static void my_application_init(MyApplication* self) {
|
||||
self->flutter_view = nullptr;
|
||||
}
|
||||
static void my_application_init(MyApplication* self) { self->flutter_view = nullptr; }
|
||||
|
||||
MyApplication* my_application_new() {
|
||||
g_set_prgname(APPLICATION_ID);
|
||||
|
||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||
"application-id", APPLICATION_ID,
|
||||
"flags", G_APPLICATION_NON_UNIQUE,
|
||||
nullptr));
|
||||
return MY_APPLICATION(g_object_new(
|
||||
my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, nullptr));
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
|
||||
GtkApplication)
|
||||
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication)
|
||||
|
||||
/**
|
||||
* my_application_new:
|
||||
|
||||
Reference in New Issue
Block a user