diff options
-rw-r--r-- | audio/decode/ad_lavc.c | 24 | ||||
-rw-r--r-- | filters/f_decoder_wrapper.c | 24 | ||||
-rw-r--r-- | filters/f_decoder_wrapper.h | 13 | ||||
-rw-r--r-- | input/sdl_gamepad.c | 4 | ||||
-rw-r--r-- | player/client.c | 239 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 59 | ||||
-rw-r--r-- | video/out/vo_drm.c | 1 |
7 files changed, 232 insertions, 132 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index fbd6ad32ac..a420021f4a 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -48,7 +48,7 @@ struct priv { bool preroll_done; double next_pts; AVRational codec_timebase; - bool eof_returned; + struct lavc_state state; struct mp_decoder public; }; @@ -159,10 +159,10 @@ static void reset(struct mp_filter *da) ctx->trim_samples = 0; ctx->preroll_done = false; ctx->next_pts = MP_NOPTS_VALUE; - ctx->eof_returned = false; + ctx->state = (struct lavc_state){0}; } -static bool send_packet(struct mp_filter *da, struct demux_packet *mpkt) +static int send_packet(struct mp_filter *da, struct demux_packet *mpkt) { struct priv *priv = da->priv; AVCodecContext *avctx = priv->avctx; @@ -177,16 +177,12 @@ static bool send_packet(struct mp_filter *da, struct demux_packet *mpkt) mp_set_av_packet(&pkt, mpkt, &priv->codec_timebase); int ret = avcodec_send_packet(avctx, mpkt ? &pkt : NULL); - - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - return false; - if (ret < 0) MP_ERR(da, "Error decoding audio.\n"); - return true; + return ret; } -static bool receive_frame(struct mp_filter *da, struct mp_frame *out) +static int receive_frame(struct mp_filter *da, struct mp_frame *out) { struct priv *priv = da->priv; AVCodecContext *avctx = priv->avctx; @@ -198,7 +194,7 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out) // over in case we get new packets at some point in the future. // (Dont' reset the filter itself, we want to keep other state.) avcodec_flush_buffers(priv->avctx); - return false; + return ret; } else if (ret < 0 && ret != AVERROR(EAGAIN)) { MP_ERR(da, "Error decoding audio.\n"); } @@ -209,14 +205,14 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out) #endif if (!priv->avframe->buf[0]) - return true; + return ret; double out_pts = mp_pts_from_av(priv->avframe->pts, &priv->codec_timebase); struct mp_aframe *mpframe = mp_aframe_from_avframe(priv->avframe); if (!mpframe) { MP_ERR(da, "Converting libavcodec frame to mpv frame failed.\n"); - return true; + return ret; } if (priv->force_channel_map.num) @@ -264,14 +260,14 @@ static bool receive_frame(struct mp_filter *da, struct mp_frame *out) av_frame_unref(priv->avframe); - return true; + return ret; } static void process(struct mp_filter *ad) { struct priv *priv = ad->priv; - lavc_process(ad, &priv->eof_returned, send_packet, receive_frame); + lavc_process(ad, &priv->state, send_packet, receive_frame); } static const struct mp_filter_info ad_lavc_filter = { diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c index f18247abaf..4347917152 100644 --- a/filters/f_decoder_wrapper.c +++ b/filters/f_decoder_wrapper.c @@ -22,6 +22,7 @@ #include <assert.h> #include <libavutil/buffer.h> +#include <libavutil/common.h> #include <libavutil/rational.h> #include "config.h" @@ -814,22 +815,23 @@ error: return NULL; } -void lavc_process(struct mp_filter *f, bool *eof_flag, - bool (*send)(struct mp_filter *f, struct demux_packet *pkt), - bool (*receive)(struct mp_filter *f, struct mp_frame *res)) +void lavc_process(struct mp_filter *f, struct lavc_state *state, + int (*send)(struct mp_filter *f, struct demux_packet *pkt), + int (*receive)(struct mp_filter *f, struct mp_frame *res)) { if (!mp_pin_in_needs_data(f->ppins[1])) return; struct mp_frame frame = {0}; - if (!receive(f, &frame)) { - if (!*eof_flag) + int ret_recv = receive(f, &frame); + if (ret_recv == AVERROR_EOF) { + if (!state->eof_returned) mp_pin_in_write(f->ppins[1], MP_EOF_FRAME); - *eof_flag = true; + state->eof_returned = true; } else if (frame.type) { - *eof_flag = false; + state->eof_returned = false; mp_pin_in_write(f->ppins[1], frame); - } else { + } else if (ret_recv == AVERROR(EAGAIN)) { // Need to feed a packet. frame = mp_pin_out_read(f->ppins[0]); struct demux_packet *pkt = NULL; @@ -843,7 +845,8 @@ void lavc_process(struct mp_filter *f, bool *eof_flag, } return; } - if (!send(f, pkt)) { + int ret_send = send(f, pkt); + if (ret_send == AVERROR(EAGAIN)) { // Should never happen, but can happen with broken decoders. MP_WARN(f, "could not consume packet\n"); mp_pin_out_unread(f->ppins[0], frame); @@ -852,5 +855,8 @@ void lavc_process(struct mp_filter *f, bool *eof_flag, } talloc_free(pkt); mp_filter_internal_mark_progress(f); + } else { + // Just try again. + mp_filter_internal_mark_progress(f); } } diff --git a/filters/f_decoder_wrapper.h b/filters/f_decoder_wrapper.h index b69c0c7680..28d9b5cb7b 100644 --- a/filters/f_decoder_wrapper.h +++ b/filters/f_decoder_wrapper.h @@ -109,11 +109,14 @@ extern const struct mp_decoder_fns vd_lavc; extern const struct mp_decoder_fns ad_lavc; extern const struct mp_decoder_fns ad_spdif; -// Convenience wrapper for lavc based decoders. eof_flag must be set to false -// on init and resets. -void lavc_process(struct mp_filter *f, bool *eof_flag, - bool (*send)(struct mp_filter *f, struct demux_packet *pkt), - bool (*receive)(struct mp_filter *f, struct mp_frame *res)); +// Convenience wrapper for lavc based decoders. Treat lavc_state as private; +// init to all-0 on init and resets. +struct lavc_state { + bool eof_returned; +}; +void lavc_process(struct mp_filter *f, struct lavc_state *state, + int (*send)(struct mp_filter *f, struct demux_packet *pkt), + int (*receive)(struct mp_filter *f, struct mp_frame *res)); // ad_spdif.c struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref); diff --git a/input/sdl_gamepad.c b/input/sdl_gamepad.c index 23997bfa07..96b8409b49 100644 --- a/input/sdl_gamepad.c +++ b/input/sdl_gamepad.c @@ -29,7 +29,7 @@ struct gamepad_priv { static Uint32 gamepad_cancel_wakeup; -static void initalize_events() +static void initialize_events(void) { gamepad_cancel_wakeup = SDL_RegisterEvents(1); } @@ -204,7 +204,7 @@ static void read_gamepad_thread(struct mp_input_src *src, void *param) return; }; - pthread_once(&events_initialized, initalize_events); + pthread_once(&events_initialized, initialize_events); if (gamepad_cancel_wakeup == (Uint32)-1) { MP_ERR(src, "Can't register SDL custom events\n"); diff --git a/player/client.c b/player/client.c index a1ce20fd74..3462845aed 100644 --- a/player/client.c +++ b/player/client.c @@ -39,6 +39,7 @@ #include "options/m_property.h" #include "options/path.h" #include "options/parse_configfile.h" +#include "osdep/atomic.h" #include "osdep/threads.h" #include "osdep/timer.h" #include "osdep/io.h" @@ -65,6 +66,8 @@ struct mp_client_api { pthread_mutex_t lock; + atomic_bool uses_vo_libmpv; + // -- protected by lock struct mpv_handle **clients; @@ -81,19 +84,23 @@ struct mp_client_api { }; struct observe_property { + struct mpv_handle *owner; char *name; int id; // ==mp_get_property_id(name) uint64_t event_mask; // ==mp_get_property_event_mask(name) int64_t reply_id; mpv_format format; + const struct m_option *type; bool changed; // property change should be signaled to user - bool need_new_value; // a new value should be retrieved - bool updating; // a new value is being retrieved - bool updated; // a new value was successfully retrieved bool dead; // property unobserved while retrieving value - bool new_value_valid, user_value_valid; - union m_option_value new_value, user_value; - struct mpv_handle *client; + bool value_valid; + union m_option_value value; + // Only if async. update is used. + uint64_t async_change_ts; // logical timestamp incremented on each change + uint64_t async_value_ts; // logical timestamp for async_value contents + bool async_updating; // if true, updating async_value_ts to change_ts + bool async_value_valid; + union m_option_value async_value; }; struct mpv_handle { @@ -129,12 +136,12 @@ struct mpv_handle { int first_event; // events[first_event] is the first readable event int num_events; // number of readable events int reserved_events; // number of entries reserved for replies + size_t async_counter; // pending other async events bool choked; // recovering from queue overflow struct observe_property **properties; int num_properties; int lowest_changed; // attempt at making change processing incremental - int properties_updating; uint64_t property_event_masks; // or-ed together event masks of all properties bool fuzzy_initialized; // see scripting.c wait_loaded() @@ -143,7 +150,7 @@ struct mpv_handle { }; static bool gen_log_message_event(struct mpv_handle *ctx); -static bool gen_property_change_event(struct mpv_handle *ctx); +static bool gen_property_change_event(struct mpv_handle *ctx, bool *unlocked); static void notify_property_events(struct mpv_handle *ctx, uint64_t event_mask); void mp_clients_init(struct MPContext *mpctx) @@ -359,7 +366,7 @@ static void unlock_core(mpv_handle *ctx) void mpv_wait_async_requests(mpv_handle *ctx) { pthread_mutex_lock(&ctx->lock); - while (ctx->reserved_events || ctx->properties_updating) + while (ctx->reserved_events || ctx->async_counter) wait_wakeup(ctx, INT64_MAX); pthread_mutex_unlock(&ctx->lock); } @@ -838,12 +845,15 @@ mpv_event *mpv_wait_event(mpv_handle *ctx, double timeout) talloc_steal(event, event->data); break; } + bool unlocked = false; // If there's a changed property, generate change event (never queued). - if (gen_property_change_event(ctx)) + if (gen_property_change_event(ctx, &unlocked)) break; // Pop item from message queue, and return as event. if (gen_log_message_event(ctx)) break; + if (unlocked) + continue; int r = wait_wakeup(ctx, deadline); if (r == ETIMEDOUT) break; @@ -1417,17 +1427,20 @@ int mpv_get_property_async(mpv_handle *ctx, uint64_t ud, const char *name, static void property_free(void *p) { struct observe_property *prop = p; - const struct m_option *type = get_mp_type_get(prop->format); - if (type) { - m_option_free(type, &prop->new_value); - m_option_free(type, &prop->user_value); + + assert(!prop->async_updating); + + if (prop->type) { + m_option_free(prop->type, &prop->value); + m_option_free(prop->type, &prop->async_value); } } int mpv_observe_property(mpv_handle *ctx, uint64_t userdata, const char *name, mpv_format format) { - if (format != MPV_FORMAT_NONE && !get_mp_type_get(format)) + const struct m_option *type = get_mp_type_get(format); + if (format != MPV_FORMAT_NONE && !type) return MPV_ERROR_PROPERTY_FORMAT; // Explicitly disallow this, because it would require a special code path. if (format == MPV_FORMAT_OSD_STRING) @@ -1437,15 +1450,14 @@ int mpv_observe_property(mpv_handle *ctx, uint64_t userdata, struct observe_property *prop = talloc_ptrtype(ctx, prop); talloc_set_destructor(prop, property_free); *prop = (struct observe_property){ - .client = ctx, + .owner = ctx, .name = talloc_strdup(prop, name), .id = mp_get_property_id(ctx->mpctx, name), .event_mask = mp_get_property_event_mask(name), .reply_id = userdata, .format = format, + .type = type, .changed = true, - .updating = false, - .updated = false, }; MP_TARRAY_APPEND(ctx, ctx->properties, ctx->num_properties, prop); ctx->property_event_masks |= prop->event_mask; @@ -1458,33 +1470,24 @@ static void mark_property_changed(struct mpv_handle *client, int index) { struct observe_property *prop = client->properties[index]; prop->changed = true; + prop->async_change_ts += 1; client->lowest_changed = MPMIN(client->lowest_changed, index); } int mpv_unobserve_property(mpv_handle *ctx, uint64_t userdata) { pthread_mutex_lock(&ctx->lock); - ctx->property_event_masks = 0; int count = 0; - for (int n = ctx->num_properties - 1; n >= 0; n--) { + for (int n = 0; n < ctx->num_properties; n++) { struct observe_property *prop = ctx->properties[n]; - if (prop->reply_id == userdata) { - if (prop->updating) { - prop->dead = true; - } else { - // In case mpv_unobserve_property() is called after mpv_wait_event() - // returned, and the mpv_event still references the name somehow, - // make sure it's not freed while in use. The same can happen - // with the value update mechanism. - talloc_steal(ctx->cur_event, prop); - } - MP_TARRAY_REMOVE_AT(ctx->properties, ctx->num_properties, n); + // Perform actual removal of the property lazily to avoid creating + // dangling pointers and such. + if (prop->reply_id == userdata && !prop->dead) { + mark_property_changed(ctx, n); + prop->dead = true; count++; } - if (!prop->dead) - ctx->property_event_masks |= prop->event_mask; } - ctx->lowest_changed = 0; pthread_mutex_unlock(&ctx->lock); return count; } @@ -1524,13 +1527,19 @@ static void notify_property_events(struct mpv_handle *ctx, uint64_t event_mask) wakeup_client(ctx); } -static void update_prop(void *p) +static void update_prop_async(void *p) { struct observe_property *prop = p; - struct mpv_handle *ctx = prop->client; + struct mpv_handle *ctx = prop->owner; - const struct m_option *type = get_mp_type_get(prop->format); union m_option_value val = {0}; + bool val_valid = false; + uint64_t value_ts; + + pthread_mutex_lock(&ctx->lock); + value_ts = prop->async_change_ts; + assert(prop->async_updating); + pthread_mutex_unlock(&ctx->lock); struct getproperty_request req = { .mpctx = ctx->mpctx, @@ -1538,72 +1547,153 @@ static void update_prop(void *p) .format = prop->format, .data = &val, }; - getproperty_fn(&req); + val_valid = req.status >= 0; pthread_mutex_lock(&ctx->lock); - ctx->properties_updating--; - prop->updating = false; - m_option_free(type, &prop->new_value); - prop->new_value_valid = req.status >= 0; - if (prop->new_value_valid) - memcpy(&prop->new_value, &val, type->type->size); - if (prop->user_value_valid != prop->new_value_valid) { - prop->updated = true; - } else if (prop->user_value_valid && prop->new_value_valid) { - if (!equal_mpv_value(&prop->user_value, &prop->new_value, prop->format)) - prop->updated = true; - } - if (prop->dead) - talloc_steal(ctx->cur_event, prop); + + assert(prop->async_updating); + + // Move to prop->async_value + m_option_free(prop->type, &prop->async_value); + memcpy(&prop->async_value, &val, prop->type->type->size); + prop->async_value_valid = val_valid; + + prop->async_value_ts = value_ts; + prop->async_updating = false; + + // Cause it to re-check the property. + prop->changed = true; + ctx->lowest_changed = 0; + + ctx->async_counter -= 1; wakeup_client(ctx); + pthread_mutex_unlock(&ctx->lock); } +static bool update_prop(struct mpv_handle *ctx, struct observe_property *prop) +{ + if (!prop->type) + return true; + + union m_option_value val = {0}; + bool val_valid = false; + + // With vo_libmpv, we can't lock the core for stupid reasons. + // Yes, that's FUCKING HORRIBLE. On the other hand, might be useful for + // true async. properties in the future. + if (atomic_load_explicit(&ctx->clients->uses_vo_libmpv, memory_order_relaxed)) { + if (prop->async_change_ts > prop->async_value_ts) { + if (!prop->async_updating) { + prop->async_updating = true; + ctx->async_counter += 1; + mp_dispatch_enqueue(ctx->mpctx->dispatch, update_prop_async, prop); + } + return false; // re-update later when the changed value comes in + } + + m_option_copy(prop->type, &val, &prop->async_value); + val_valid = prop->async_value_valid; + } else { + pthread_mutex_unlock(&ctx->lock); + + struct getproperty_request req = { + .mpctx = ctx->mpctx, + .name = prop->name, + .format = prop->format, + .data = &val, + }; + run_locked(ctx, getproperty_fn, &req); + val_valid = req.status >= 0; + + pthread_mutex_lock(&ctx->lock); + } + + bool changed = prop->value_valid != val_valid; + if (prop->value_valid && val_valid) + changed = !equal_mpv_value(&prop->value, &val, prop->format); + + if (changed) { + prop->value_valid = val_valid; + if (val_valid) { + // move val to prop->value + m_option_free(prop->type, &prop->value); + memcpy(&prop->value, &val, prop->type->type->size); + val_valid = false; + } + } + + if (val_valid) + m_option_free(prop->type, &val); + + return changed; +} + // Set ctx->cur_event to a generated property change event, if there is any // outstanding property. -static bool gen_property_change_event(struct mpv_handle *ctx) +static bool gen_property_change_event(struct mpv_handle *ctx, bool *unlocked) { if (!ctx->mpctx->initialized) return false; + + *ctx->cur_event = (struct mpv_event){ + .event_id = MPV_EVENT_NONE, + }; + + bool need_gc = false; int start = ctx->lowest_changed; ctx->lowest_changed = ctx->num_properties; for (int n = start; n < ctx->num_properties; n++) { struct observe_property *prop = ctx->properties[n]; - if ((prop->changed || prop->updating || prop->updated) && n < ctx->lowest_changed) + if (prop->changed && n < ctx->lowest_changed) ctx->lowest_changed = n; - if (prop->changed) { + + bool updated = false; + if (prop->changed && !prop->dead) { prop->changed = false; - if (prop->format != MPV_FORMAT_NONE) { - ctx->properties_updating++; - prop->updating = true; - mp_dispatch_enqueue(ctx->mpctx->dispatch, update_prop, prop); - } else { - prop->updated = true; - } + updated = update_prop(ctx, prop); + *unlocked = true; // not always; but good enough } - bool updated = prop->updated; - prop->updated = false; - if (updated) { - const struct m_option *type = get_mp_type_get(prop->format); - prop->user_value_valid = prop->new_value_valid; - if (prop->new_value_valid) - m_option_copy(type, &prop->user_value, &prop->new_value); + + if (prop->dead) { + need_gc = true; + } else if (updated) { ctx->cur_property_event = (struct mpv_event_property){ .name = prop->name, - .format = prop->user_value_valid ? prop->format : 0, + .format = prop->value_valid ? prop->format : 0, + .data = prop->value_valid ? &prop->value : NULL, }; - if (prop->user_value_valid) - ctx->cur_property_event.data = &prop->user_value; *ctx->cur_event = (struct mpv_event){ .event_id = MPV_EVENT_PROPERTY_CHANGE, .reply_userdata = prop->reply_id, .data = &ctx->cur_property_event, }; - return true; + break; } } - return false; + + if (need_gc) { + // Remove entries which have the .dead flag set. The point of doing this + // here is to ensure that this does not conflict with update_prop(), + // and that a previously returned mpv_event struct pointing to removed + // property entries does not result in dangling pointers. + ctx->property_event_masks = 0; + ctx->lowest_changed = 0; + for (int n = ctx->num_properties - 1; n >= 0; n--) { + struct observe_property *prop = ctx->properties[n]; + if (prop->dead) { + if (!prop->async_updating) { + MP_TARRAY_REMOVE_AT(ctx->properties, ctx->num_properties, n); + talloc_free(prop); + } + } else { + ctx->property_event_masks |= prop->event_mask; + } + } + } + + return !!ctx->cur_event->event_id; } int mpv_hook_add(mpv_handle *ctx, uint64_t reply_userdata, @@ -1828,6 +1918,7 @@ bool mp_set_main_render_context(struct mp_client_api *client_api, if (res) client_api->render_context = active ? ctx : NULL; pthread_mutex_unlock(&client_api->lock); + atomic_store(&client_api->uses_vo_libmpv, active); return res; } diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 6c356e2e01..93cb261766 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -172,7 +172,7 @@ typedef struct lavc_ctx { AVRational codec_timebase; enum AVDiscard skip_frame; bool flushing; - bool eof_returned; + struct lavc_state state; const char *decoder; bool hwdec_requested; bool hwdec_failed; @@ -974,17 +974,17 @@ static bool do_send_packet(struct mp_filter *vd, struct demux_packet *pkt) AVCodecContext *avctx = ctx->avctx; if (!prepare_decoding(vd)) - return false; + return AVERROR_UNKNOWN; if (avctx->skip_frame == AVDISCARD_ALL) - return true; + return AVERROR(EAGAIN); AVPacket avpkt; mp_set_av_packet(&avpkt, pkt, &ctx->codec_timebase); int ret = avcodec_send_packet(avctx, pkt ? &avpkt : NULL); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - return false; + return ret; if (ctx->hw_probing && ctx->num_sent_packets < 32) { pkt = pkt ? demux_copy_packet(pkt) : NULL; @@ -993,38 +993,41 @@ static bool do_send_packet(struct mp_filter *vd, struct demux_packet *pkt) if (ret < 0) handle_err(vd); - return true; + return ret; } -static bool send_queued(struct mp_filter *vd) +static int send_queued(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - while (ctx->num_requeue_packets && do_send_packet(vd, ctx->requeue_packets[0])) - { + while (ctx->num_requeue_packets) { + int ret = do_send_packet(vd, ctx->requeue_packets[0]); + if (ret < 0) + return ret; talloc_free(ctx->requeue_packets[0]); MP_TARRAY_REMOVE_AT(ctx->requeue_packets, ctx->num_requeue_packets, 0); } - return ctx->num_requeue_packets == 0; + return 0; } -static bool send_packet(struct mp_filter *vd, struct demux_packet *pkt) +static int send_packet(struct mp_filter *vd, struct demux_packet *pkt) { - if (!send_queued(vd)) + int ret = send_queued(vd); + if (ret < 0) return false; return do_send_packet(vd, pkt); } // Returns whether decoder is still active (!EOF state). -static bool decode_frame(struct mp_filter *vd) +static int decode_frame(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; if (!prepare_decoding(vd)) - return true; + return AVERROR(EAGAIN); int ret = avcodec_receive_frame(avctx, ctx->pic); if (ret == AVERROR_EOF) { @@ -1034,20 +1037,20 @@ static bool decode_frame(struct mp_filter *vd) // the delay queue has been drained. if (!ctx->num_delay_queue) reset_avctx(vd); - return false; + return ret; } else if (ret < 0 && ret != AVERROR(EAGAIN)) { handle_err(vd); } if (!ctx->pic->buf[0]) - return true; + return ret; ctx->hwdec_fail_count = 0; struct mp_image *mpi = mp_image_from_av_frame(ctx->pic); if (!mpi) { av_frame_unref(ctx->pic); - return true; + return ret; } assert(mpi->planes[0] || mpi->planes[3]); mpi->pts = mp_pts_from_av(ctx->pic->pts, &ctx->codec_timebase); @@ -1061,14 +1064,14 @@ static bool decode_frame(struct mp_filter *vd) av_frame_unref(ctx->pic); MP_TARRAY_APPEND(ctx, ctx->delay_queue, ctx->num_delay_queue, mpi); - return true; + return ret; } -static bool receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) +static int receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) { vd_ffmpeg_ctx *ctx = vd->priv; - bool progress = decode_frame(vd); + int ret = decode_frame(vd); if (ctx->hwdec_failed) { // Failed hardware decoding? Try again in software. @@ -1083,21 +1086,21 @@ static bool receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) ctx->num_requeue_packets = num_pkts; send_queued(vd); - progress = decode_frame(vd); + ret = decode_frame(vd); } if (!ctx->num_delay_queue) - return progress; + return ret; - if (ctx->num_delay_queue <= ctx->max_delay_queue && progress) - return true; + if (ctx->num_delay_queue <= ctx->max_delay_queue && ret >= 0) + return AVERROR(EAGAIN); struct mp_image *res = ctx->delay_queue[0]; MP_TARRAY_REMOVE_AT(ctx->delay_queue, ctx->num_delay_queue, 0); res = res ? mp_img_swap_to_native(res) : NULL; if (!res) - return progress; + return ret; if (ctx->use_hwdec && ctx->hwdec.copying && res->hwctx) { struct mp_image *sw = mp_image_hw_download(res, ctx->hwdec_swpool); @@ -1107,7 +1110,7 @@ static bool receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) MP_ERR(vd, "Could not copy back hardware decoded frame.\n"); ctx->hwdec_fail_count = INT_MAX - 1; // force fallback handle_err(vd); - return true; + return ret; } } @@ -1129,7 +1132,7 @@ static bool receive_frame(struct mp_filter *vd, struct mp_frame *out_frame) } *out_frame = MAKE_FRAME(MP_FRAME_VIDEO, res); - return true; + return ret; } static int control(struct mp_filter *vd, enum dec_ctrl cmd, void *arg) @@ -1169,7 +1172,7 @@ static void process(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - lavc_process(vd, &ctx->eof_returned, send_packet, receive_frame); + lavc_process(vd, &ctx->state, send_packet, receive_frame); } static void reset(struct mp_filter *vd) @@ -1178,7 +1181,7 @@ static void reset(struct mp_filter *vd) flush_all(vd); - ctx->eof_returned = false; + ctx->state = (struct lavc_state){0}; ctx->framedrop_flags = 0; } diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index ce48779a82..83dede468c 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -304,6 +304,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) int h = p->dst.y1 - p->dst.y0; mp_sws_set_from_cmdline(p->sws, vo->global); + p->sws->allow_zimg = true; p->sws->src = *params; p->sws->dst = (struct mp_image_params) { .imgfmt = p->imgfmt, |