mirror of
https://github.com/mpv-player/mpv
synced 2025-03-20 10:17:31 +00:00
player, ao, vo: don't call mp_input_wakeup() directly
Currently, calling mp_input_wakeup() will wake up the core thread (also called the playloop). This seems odd, but currently the core indeed calls mp_input_wait() when it has nothing more to do. It's done this way because MPlayer used input_ctx as central "mainloop". This is probably going to change. Remove direct calls to this function, and replace it with mp_wakeup_core() calls. ao and vo are changed to use opaque callbacks and not use input_ctx for this purpose. Other code already uses opaque callbacks, or has legitimate reasons to use input_ctx directly (such as sending actual user input).
This commit is contained in:
parent
f845f64c2a
commit
b8ade7c99b
@ -28,7 +28,6 @@
|
||||
#include "audio/format.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
#include "input/input.h"
|
||||
#include "options/options.h"
|
||||
#include "options/m_config.h"
|
||||
#include "common/msg.h"
|
||||
@ -127,8 +126,11 @@ const struct m_obj_list ao_obj_list = {
|
||||
};
|
||||
|
||||
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx, char *name, char **args)
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
char *name, char **args)
|
||||
{
|
||||
assert(wakeup_cb);
|
||||
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
|
||||
struct m_obj_desc desc;
|
||||
@ -143,7 +145,8 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
.driver = desc.p,
|
||||
.probing = probing,
|
||||
.global = global,
|
||||
.input_ctx = input_ctx,
|
||||
.wakeup_cb = wakeup_cb,
|
||||
.wakeup_ctx = wakeup_ctx,
|
||||
.log = mp_log_new(ao, log, name),
|
||||
.def_buffer = opts->audio_buffer,
|
||||
.client_name = talloc_strdup(ao, opts->audio_client_name),
|
||||
@ -161,12 +164,12 @@ error:
|
||||
}
|
||||
|
||||
static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx, int flags,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *dev, char *name, char **args)
|
||||
{
|
||||
struct ao *ao = ao_alloc(probing, global, input_ctx, name, args);
|
||||
struct ao *ao = ao_alloc(probing, global, wakeup_cb, wakeup_ctx, name, args);
|
||||
if (!ao)
|
||||
return NULL;
|
||||
ao->samplerate = samplerate;
|
||||
@ -197,8 +200,9 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
return ao_init(probing, global, input_ctx, encode_lavc_ctx, flags,
|
||||
samplerate, format, channels, rdevice, redirect, NULL);
|
||||
return ao_init(probing, global, wakeup_cb, wakeup_ctx,
|
||||
encode_lavc_ctx, flags, samplerate, format, channels,
|
||||
rdevice, redirect, NULL);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
@ -248,7 +252,7 @@ static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
int init_flags,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels)
|
||||
{
|
||||
@ -304,8 +308,8 @@ struct ao *ao_init_best(struct mpv_global *global,
|
||||
dev = pref_dev;
|
||||
mp_verbose(log, "Using preferred device '%s'\n", dev);
|
||||
}
|
||||
ao = ao_init(probing, global, input_ctx, encode_lavc_ctx, init_flags,
|
||||
samplerate, format, channels, dev,
|
||||
ao = ao_init(probing, global, wakeup_cb, wakeup_ctx, encode_lavc_ctx,
|
||||
init_flags, samplerate, format, channels, dev,
|
||||
entry->name, entry->attribs);
|
||||
if (ao)
|
||||
break;
|
||||
@ -409,8 +413,7 @@ int ao_query_and_reset_events(struct ao *ao, int events)
|
||||
static void ao_add_events(struct ao *ao, int events)
|
||||
{
|
||||
atomic_fetch_or(&ao->events_, events);
|
||||
if (ao->input_ctx)
|
||||
mp_input_wakeup(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
}
|
||||
|
||||
// Request that the player core destroys and recreates the AO. Fully thread-safe.
|
||||
@ -494,7 +497,8 @@ bool ao_untimed(struct ao *ao)
|
||||
|
||||
struct ao_hotplug {
|
||||
struct mpv_global *global;
|
||||
struct input_ctx *input_ctx;
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
// A single AO instance is used to listen to hotplug events. It wouldn't
|
||||
// make much sense to allow multiple AO drivers; all sane platforms have
|
||||
// a single such audio API.
|
||||
@ -506,12 +510,14 @@ struct ao_hotplug {
|
||||
};
|
||||
|
||||
struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
|
||||
struct input_ctx *input_ctx)
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx)
|
||||
{
|
||||
struct ao_hotplug *hp = talloc_ptrtype(NULL, hp);
|
||||
*hp = (struct ao_hotplug){
|
||||
.global = global,
|
||||
.input_ctx = input_ctx,
|
||||
.wakeup_cb = wakeup_cb,
|
||||
.wakeup_ctx = wakeup_ctx,
|
||||
.needs_update = true,
|
||||
};
|
||||
return hp;
|
||||
@ -564,7 +570,7 @@ struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
|
||||
if (d == &audio_out_null)
|
||||
break; // don't add unsafe/special entries
|
||||
|
||||
struct ao *ao = ao_alloc(true, hp->global, hp->input_ctx,
|
||||
struct ao *ao = ao_alloc(true, hp->global, hp->wakeup_cb, hp->wakeup_ctx,
|
||||
(char *)d->name, NULL);
|
||||
if (!ao)
|
||||
continue;
|
||||
@ -605,9 +611,13 @@ void ao_hotplug_destroy(struct ao_hotplug *hp)
|
||||
talloc_free(hp);
|
||||
}
|
||||
|
||||
static void dummy_wakeup(void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void ao_print_devices(struct mpv_global *global, struct mp_log *log)
|
||||
{
|
||||
struct ao_hotplug *hp = ao_hotplug_create(global, NULL);
|
||||
struct ao_hotplug *hp = ao_hotplug_create(global, dummy_wakeup, NULL);
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(hp);
|
||||
mp_info(log, "List of detected audio devices:\n");
|
||||
for (int n = 0; n < list->num_devices; n++) {
|
||||
|
@ -85,7 +85,7 @@ struct mp_audio;
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
int init_flags,
|
||||
struct input_ctx *input_ctx,
|
||||
void (*wakeup_cb)(void *ctx), void *wakeup_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels);
|
||||
void ao_uninit(struct ao *ao);
|
||||
@ -108,7 +108,8 @@ void ao_hotplug_event(struct ao *ao);
|
||||
|
||||
struct ao_hotplug;
|
||||
struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
|
||||
struct input_ctx *input_ctx);
|
||||
void (*wakeup_cb)(void *ctx),
|
||||
void *wakeup_ctx);
|
||||
void ao_hotplug_destroy(struct ao_hotplug *hp);
|
||||
bool ao_hotplug_check_update(struct ao_hotplug *hp);
|
||||
const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp);
|
||||
|
@ -42,7 +42,8 @@ struct ao {
|
||||
void *priv;
|
||||
struct mpv_global *global;
|
||||
struct encode_lavc_context *encode_lavc_ctx;
|
||||
struct input_ctx *input_ctx;
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
struct mp_log *log; // Using e.g. "[ao/coreaudio]" as prefix
|
||||
int init_flags; // AO_INIT_* flags
|
||||
bool stream_silence; // if audio inactive, just play silence
|
||||
|
@ -151,7 +151,7 @@ int ao_read_data(struct ao *ao, void **data, int samples, int64_t out_time_us)
|
||||
end:
|
||||
|
||||
if (need_wakeup)
|
||||
mp_input_wakeup_nolock(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
|
||||
// pad with silence (underflow/paused/eof)
|
||||
for (int n = 0; n < ao->num_planes; n++)
|
||||
|
@ -305,7 +305,7 @@ static void ao_play_data(struct ao *ao)
|
||||
bool more = needed >= (r == space ? ao->device_buffer / 4 : 1) && !stuck &&
|
||||
!(flags & AOPLAY_FINAL_CHUNK);
|
||||
if (more)
|
||||
mp_input_wakeup(ao->input_ctx); // request more data
|
||||
ao->wakeup_cb(ao->wakeup_ctx); // request more data
|
||||
MP_TRACE(ao, "in=%d flags=%d space=%d r=%d wa/pl=%d/%d needed=%d more=%d\n",
|
||||
max, flags, space, r, p->wait_on_ao, p->still_playing, needed, more);
|
||||
}
|
||||
@ -347,7 +347,7 @@ static void *playthread(void *arg)
|
||||
}
|
||||
|
||||
if (was_playing && !p->still_playing)
|
||||
mp_input_wakeup(ao->input_ctx);
|
||||
ao->wakeup_cb(ao->wakeup_ctx);
|
||||
pthread_cond_signal(&p->wakeup); // for draining
|
||||
|
||||
if (p->still_playing && timeout > 0) {
|
||||
|
@ -397,8 +397,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
|
||||
|
||||
mp_audio_set_channels(&afs->output, &afs->output.channels);
|
||||
|
||||
mpctx->ao = ao_init_best(mpctx->global, ao_flags, mpctx->input,
|
||||
mpctx->encode_lavc_ctx, afs->output.rate,
|
||||
mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb,
|
||||
mpctx, mpctx->encode_lavc_ctx, afs->output.rate,
|
||||
afs->output.format, afs->output.channels);
|
||||
ao_c->ao = mpctx->ao;
|
||||
|
||||
|
@ -424,8 +424,7 @@ void mpv_detach_destroy(mpv_handle *ctx)
|
||||
ctx = NULL;
|
||||
// shutdown_clients() sleeps to avoid wasting CPU.
|
||||
// mp_hook_test_completion() also relies on this a bit.
|
||||
if (clients->mpctx->input)
|
||||
mp_input_wakeup(clients->mpctx->input);
|
||||
mp_wakeup_core(clients->mpctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -759,8 +758,8 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout)
|
||||
|
||||
pthread_mutex_lock(&ctx->lock);
|
||||
|
||||
if (!ctx->fuzzy_initialized && ctx->clients->mpctx->input)
|
||||
mp_input_wakeup(ctx->clients->mpctx->input);
|
||||
if (!ctx->fuzzy_initialized)
|
||||
mp_wakeup_core(ctx->clients->mpctx);
|
||||
ctx->fuzzy_initialized = true;
|
||||
|
||||
if (timeout < 0)
|
||||
|
@ -190,7 +190,7 @@ void mp_hook_run(struct MPContext *mpctx, char *client, char *type)
|
||||
next->active = true;
|
||||
if (!send_hook_msg(mpctx, next, "hook_run")) {
|
||||
hook_remove(mpctx, index);
|
||||
mp_input_wakeup(mpctx->input); // repeat next iteration to finish
|
||||
mp_wakeup_core(mpctx); // repeat next iteration to finish
|
||||
}
|
||||
}
|
||||
|
||||
@ -1742,14 +1742,24 @@ static void reload_audio_output(struct MPContext *mpctx)
|
||||
ao_request_reload(mpctx->ao);
|
||||
}
|
||||
|
||||
static void create_hotplug(struct MPContext *mpctx)
|
||||
{
|
||||
struct command_ctx *cmd = mpctx->command_ctx;
|
||||
|
||||
if (!cmd->hotplug) {
|
||||
cmd->hotplug = ao_hotplug_create(mpctx->global, mp_wakeup_core_cb,
|
||||
mpctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int mp_property_audio_device(void *ctx, struct m_property *prop,
|
||||
int action, void *arg)
|
||||
{
|
||||
struct MPContext *mpctx = ctx;
|
||||
struct command_ctx *cmd = mpctx->command_ctx;
|
||||
if (action == M_PROPERTY_PRINT) {
|
||||
if (!cmd->hotplug)
|
||||
cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input);
|
||||
create_hotplug(mpctx);
|
||||
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(cmd->hotplug);
|
||||
for (int n = 0; n < list->num_devices; n++) {
|
||||
struct ao_device_desc *dev = &list->devices[n];
|
||||
@ -1770,8 +1780,7 @@ static int mp_property_audio_devices(void *ctx, struct m_property *prop,
|
||||
{
|
||||
struct MPContext *mpctx = ctx;
|
||||
struct command_ctx *cmd = mpctx->command_ctx;
|
||||
if (!cmd->hotplug)
|
||||
cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input);
|
||||
create_hotplug(mpctx);
|
||||
|
||||
struct ao_device_list *list = ao_hotplug_get_device_list(cmd->hotplug);
|
||||
return m_property_read_list(action, arg, list->num_devices,
|
||||
@ -1790,8 +1799,7 @@ static int mp_property_ao_detected_device(void *ctx,struct m_property *prop,
|
||||
{
|
||||
struct MPContext *mpctx = ctx;
|
||||
struct command_ctx *cmd = mpctx->command_ctx;
|
||||
if (!cmd->hotplug)
|
||||
cmd->hotplug = ao_hotplug_create(mpctx->global, mpctx->input);
|
||||
create_hotplug(mpctx);
|
||||
|
||||
const char *d = ao_hotplug_get_detected_device(cmd->hotplug);
|
||||
return m_property_strdup_ro(action, arg, d);
|
||||
|
@ -511,6 +511,8 @@ void set_osd_bar_chapters(struct MPContext *mpctx, int type);
|
||||
|
||||
// playloop.c
|
||||
void mp_wait_events(struct MPContext *mpctx, double sleeptime);
|
||||
void mp_wakeup_core(struct MPContext *mpctx);
|
||||
void mp_wakeup_core_cb(void *ctx);
|
||||
void mp_process_input(struct MPContext *mpctx);
|
||||
double get_relative_time(struct MPContext *mpctx);
|
||||
void reset_playback_state(struct MPContext *mpctx);
|
||||
|
@ -204,7 +204,7 @@ void reselect_demux_stream(struct MPContext *mpctx, struct track *track)
|
||||
static void wakeup_demux(void *pctx)
|
||||
{
|
||||
struct MPContext *mpctx = pctx;
|
||||
mp_input_wakeup(mpctx->input);
|
||||
mp_wakeup_core(mpctx);
|
||||
}
|
||||
|
||||
static void enable_demux_thread(struct MPContext *mpctx, struct demuxer *demux)
|
||||
|
@ -971,7 +971,7 @@ static int script_set_osd_ass(lua_State *L)
|
||||
if (!text[0])
|
||||
text = " "; // force external OSD initialization
|
||||
osd_set_external(ctx->mpctx->osd, ctx->client, res_x, res_y, (char *)text);
|
||||
mp_input_wakeup(ctx->mpctx->input);
|
||||
mp_wakeup_core(ctx->mpctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ static int cfg_include(void *ctx, char *filename, int flags)
|
||||
void wakeup_playloop(void *ctx)
|
||||
{
|
||||
struct MPContext *mpctx = ctx;
|
||||
mp_input_wakeup(mpctx->input);
|
||||
mp_wakeup_core(mpctx);
|
||||
}
|
||||
|
||||
struct MPContext *mp_create(void)
|
||||
|
@ -267,7 +267,7 @@ static void *thread_wrapper(void *pctx)
|
||||
pthread_mutex_lock(&args->mutex);
|
||||
args->done = true;
|
||||
pthread_mutex_unlock(&args->mutex);
|
||||
mp_input_wakeup(args->mpctx->input); // this interrupts mp_idle()
|
||||
mp_wakeup_core(args->mpctx); // this interrupts mp_idle()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -50,13 +50,28 @@
|
||||
#include "client.h"
|
||||
#include "command.h"
|
||||
|
||||
// Wait until mp_input_wakeup(mpctx->input) is called, since the last time
|
||||
// Wait until mp_wakeup_core() is called, since the last time
|
||||
// mp_wait_events() was called. (But see mp_process_input().)
|
||||
void mp_wait_events(struct MPContext *mpctx, double sleeptime)
|
||||
{
|
||||
mp_input_wait(mpctx->input, sleeptime);
|
||||
}
|
||||
|
||||
// Cause the playloop to run. This can be called from any thread. If called
|
||||
// from within the playloop itself, it will be run immediately again, instead
|
||||
// of going to sleep in the next mp_wait_events().
|
||||
void mp_wakeup_core(struct MPContext *mpctx)
|
||||
{
|
||||
mp_input_wakeup(mpctx->input);
|
||||
}
|
||||
|
||||
// Opaque callback variant of mp_wakeup_core().
|
||||
void mp_wakeup_core_cb(void *ctx)
|
||||
{
|
||||
struct MPContext *mpctx = ctx;
|
||||
mp_wakeup_core(mpctx);
|
||||
}
|
||||
|
||||
// Process any queued input, whether it's user input, or requests from client
|
||||
// API threads. This also resets the "wakeup" flag used with mp_wait_events().
|
||||
void mp_process_input(struct MPContext *mpctx)
|
||||
@ -816,6 +831,8 @@ int handle_force_window(struct MPContext *mpctx, bool force)
|
||||
.osd = mpctx->osd,
|
||||
.encode_lavc_ctx = mpctx->encode_lavc_ctx,
|
||||
.opengl_cb_context = mpctx->gl_cb_ctx,
|
||||
.wakeup_cb = mp_wakeup_core_cb,
|
||||
.wakeup_ctx = mpctx,
|
||||
};
|
||||
mpctx->video_out = init_best_video_out(mpctx->global, &ex);
|
||||
if (!mpctx->video_out)
|
||||
|
@ -466,6 +466,8 @@ int reinit_video_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
|
||||
.osd = mpctx->osd,
|
||||
.encode_lavc_ctx = mpctx->encode_lavc_ctx,
|
||||
.opengl_cb_context = mpctx->gl_cb_ctx,
|
||||
.wakeup_cb = mp_wakeup_core_cb,
|
||||
.wakeup_ctx = mpctx,
|
||||
};
|
||||
mpctx->video_out = init_best_video_out(mpctx->global, &ex);
|
||||
if (!mpctx->video_out) {
|
||||
|
@ -213,6 +213,8 @@ static void dealloc_vo(struct vo *vo)
|
||||
static struct vo *vo_create(bool probing, struct mpv_global *global,
|
||||
struct vo_extra *ex, char *name, char **args)
|
||||
{
|
||||
assert(ex->wakeup_cb);
|
||||
|
||||
struct mp_log *log = mp_log_new(NULL, global->log, "vo");
|
||||
struct m_obj_desc desc;
|
||||
if (!m_obj_list_find(&desc, &vo_obj_list, bstr0(name))) {
|
||||
@ -313,6 +315,12 @@ void vo_destroy(struct vo *vo)
|
||||
dealloc_vo(vo);
|
||||
}
|
||||
|
||||
// Wakeup the playloop to queue new video frames etc.
|
||||
static void wakeup_core(struct vo *vo)
|
||||
{
|
||||
vo->extra.wakeup_cb(vo->extra.wakeup_ctx);
|
||||
}
|
||||
|
||||
// Drop timing information on discontinuities like seeking.
|
||||
// Always called locked.
|
||||
static void reset_vsync_timings(struct vo *vo)
|
||||
@ -477,7 +485,7 @@ static void update_display_fps(struct vo *vo)
|
||||
|
||||
// make sure to update the player
|
||||
in->queued_events |= VO_EVENT_WIN_STATE;
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
wakeup_core(vo);
|
||||
}
|
||||
|
||||
in->nominal_vsync_interval = in->display_fps > 0 ? 1e6 / in->display_fps : 0;
|
||||
@ -795,7 +803,7 @@ static bool render_frame(struct vo *vo)
|
||||
in->hasframe_rendered = true;
|
||||
int64_t prev_drop_count = vo->in->drop_count;
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
mp_input_wakeup(vo->input_ctx); // core can queue new video now
|
||||
wakeup_core(vo); // core can queue new video now
|
||||
|
||||
MP_STATS(vo, "start video");
|
||||
|
||||
@ -826,7 +834,7 @@ static bool render_frame(struct vo *vo)
|
||||
}
|
||||
|
||||
pthread_cond_broadcast(&in->wakeup); // for vo_wait_frame()
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
wakeup_core(vo);
|
||||
|
||||
got_frame = true;
|
||||
|
||||
@ -906,12 +914,12 @@ static void *vo_thread(void *ptr)
|
||||
wait_until = MPMIN(wait_until, in->wakeup_pts);
|
||||
} else {
|
||||
in->wakeup_pts = 0;
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
wakeup_core(vo);
|
||||
}
|
||||
}
|
||||
if (vo->want_redraw && !in->want_redraw) {
|
||||
in->want_redraw = true;
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
wakeup_core(vo);
|
||||
}
|
||||
bool redraw = in->request_redraw;
|
||||
bool send_reset = in->send_reset;
|
||||
@ -1159,7 +1167,7 @@ void vo_event(struct vo *vo, int event)
|
||||
struct vo_internal *in = vo->in;
|
||||
pthread_mutex_lock(&in->lock);
|
||||
if ((in->queued_events & event & VO_EVENTS_USER) != (event & VO_EVENTS_USER))
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
wakeup_core(vo);
|
||||
if (event)
|
||||
wakeup_locked(vo);
|
||||
in->queued_events |= event;
|
||||
|
@ -169,6 +169,8 @@ struct vo_extra {
|
||||
struct osd_state *osd;
|
||||
struct encode_lavc_context *encode_lavc_ctx;
|
||||
struct mpv_opengl_cb_context *opengl_cb_context;
|
||||
void (*wakeup_cb)(void *ctx);
|
||||
void *wakeup_ctx;
|
||||
};
|
||||
|
||||
struct vo_frame {
|
||||
|
Loading…
Reference in New Issue
Block a user