diff options
Diffstat (limited to 'player')
-rw-r--r-- | player/command.c | 50 | ||||
-rw-r--r-- | player/core.h | 12 | ||||
-rw-r--r-- | player/loadfile.c | 3 | ||||
-rw-r--r-- | player/playloop.c | 5 | ||||
-rw-r--r-- | player/sub.c | 3 | ||||
-rw-r--r-- | player/video.c | 292 |
6 files changed, 126 insertions, 239 deletions
diff --git a/player/command.c b/player/command.c index 4c03c7579e..9020ffe158 100644 --- a/player/command.c +++ b/player/command.c @@ -50,7 +50,6 @@ #include "options/m_option.h" #include "options/m_property.h" #include "options/m_config.h" -#include "video/filter/vf.h" #include "video/decode/vd.h" #include "video/out/vo.h" #include "video/csputils.h" @@ -1432,12 +1431,25 @@ static int mp_property_filter_metadata(void *ctx, struct m_property *prop, char *rem; m_property_split_path(ka->key, &key, &rem); struct mp_tags metadata = {0}; + void *metadata_mem = NULL; int res = CONTROL_UNKNOWN; if (strcmp(type, "vf") == 0) { if (!mpctx->vo_chain) return M_PROPERTY_UNAVAILABLE; - struct vf_chain *vf = mpctx->vo_chain->vf; - res = vf_control_by_label(vf, VFCTRL_GET_METADATA, &metadata, key); + + struct mp_tags *metadata_ptr = NULL; + struct mp_filter_command cmd = { + .type = MP_FILTER_COMMAND_GET_META, + .res = &metadata_ptr, + }; + char *key0 = mp_tprintf(80, "%.*s", BSTR_P(key)); + mp_output_chain_command(mpctx->vo_chain->filter, key0, &cmd); + + if (metadata_ptr) { + metadata = *metadata_ptr; + metadata_mem = metadata_ptr; + res = CONTROL_OK; + } } else if (strcmp(type, "af") == 0) { #if HAVE_LIBAF if (!(mpctx->ao_chain && mpctx->ao_chain->af)) @@ -1454,11 +1466,12 @@ static int mp_property_filter_metadata(void *ctx, struct m_property *prop, if (strlen(rem)) { struct m_property_action_arg next_ka = *ka; next_ka.key = rem; - return tag_property(M_PROPERTY_KEY_ACTION, &next_ka, &metadata); + res = tag_property(M_PROPERTY_KEY_ACTION, &next_ka, &metadata); } else { - return tag_property(ka->action, ka->arg, &metadata); + res = tag_property(ka->action, ka->arg, &metadata); } - return M_PROPERTY_OK; + talloc_free(metadata_mem); + return res; default: return M_PROPERTY_ERROR; } @@ -2601,10 +2614,10 @@ static int property_imgparams(struct mp_image_params p, int action, void *arg) static struct mp_image_params get_video_out_params(struct MPContext *mpctx) { - if (!mpctx->vo_chain || mpctx->vo_chain->vf->initialized < 1) + if (!mpctx->vo_chain) return (struct mp_image_params){0}; - return mpctx->vo_chain->vf->output_params; + return mpctx->vo_chain->filter->output_params; } static int mp_property_vo_imgparams(void *ctx, struct m_property *prop, @@ -2636,8 +2649,8 @@ static int mp_property_vd_imgparams(void *ctx, struct m_property *prop, struct track *track = mpctx->current_track[0][STREAM_VIDEO]; struct mp_codec_params *c = track && track->stream ? track->stream->codec : NULL; - if (vo_c->vf->input_params.imgfmt) { - return property_imgparams(vo_c->vf->input_params, action, arg); + if (vo_c->filter->input_params.imgfmt) { + return property_imgparams(vo_c->filter->input_params, action, arg); } else if (c && c->disp_w && c->disp_h) { // Simplistic fallback for stupid scripts querying "width"/"height" // before the first frame is decoded. @@ -2975,7 +2988,7 @@ static int mp_property_aspect(void *ctx, struct m_property *prop, float aspect = mpctx->opts->movie_aspect; if (mpctx->vo_chain && aspect <= 0) { - struct mp_image_params *params = &mpctx->vo_chain->vf->input_params; + struct mp_image_params *params = &mpctx->vo_chain->filter->input_params; if (params && params->p_w > 0 && params->p_h > 0) { int d_w, d_h; mp_image_params_get_dsize(params, &d_w, &d_h); @@ -5470,11 +5483,17 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re return edit_filters_osd(mpctx, STREAM_VIDEO, cmd->args[0].v.s, cmd->args[1].v.s, msg_osd); - case MP_CMD_VF_COMMAND: + case MP_CMD_VF_COMMAND: { if (!mpctx->vo_chain) return -1; - return vf_send_command(mpctx->vo_chain->vf, cmd->args[0].v.s, - cmd->args[1].v.s, cmd->args[2].v.s); + struct mp_filter_command filter_cmd = { + .type = MP_FILTER_COMMAND_TEXT, + .cmd = cmd->args[1].v.s, + .arg = cmd->args[2].v.s, + }; + return mp_output_chain_command(mpctx->vo_chain->filter, cmd->args[0].v.s, + &filter_cmd) ? 0 : -1; + } #if HAVE_LIBAF case MP_CMD_AF_COMMAND: @@ -5785,9 +5804,6 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags) if (flags & UPDATE_TERM) mp_update_logging(mpctx, false); - if (flags & UPDATE_DEINT) - recreate_auto_filters(mpctx); - if (flags & UPDATE_OSD) { for (int n = 0; n < NUM_PTRACKS; n++) { struct track *track = mpctx->current_track[n][STREAM_SUB]; diff --git a/player/core.h b/player/core.h index f2fed55366..c980e068fe 100644 --- a/player/core.h +++ b/player/core.h @@ -26,6 +26,8 @@ #include "libmpv/client.h" #include "common/common.h" +#include "filters/filter.h" +#include "filters/f_output_chain.h" #include "options/options.h" #include "sub/osd.h" #include "audio/aframe.h" @@ -172,15 +174,14 @@ struct vo_chain { struct mp_hwdec_devices *hwdec_devs; double container_fps; - struct vf_chain *vf; + struct mp_output_chain *filter; + + //struct vf_chain *vf; struct vo *vo; // 1-element input frame queue. struct mp_image *input_mpi; - // Last known input_mpi format (so vf can be reinitialized any time). - struct mp_image_params input_format; - struct track *track; struct lavfi_pad *filter_src; struct dec_video *video_src; @@ -319,6 +320,8 @@ typedef struct MPContext { struct lavfi *lavfi; + struct mp_filter *filter_root; + struct ao *ao; struct mp_aframe *ao_decoder_fmt; // for weak gapless audio check struct ao_chain *ao_chain; @@ -631,6 +634,5 @@ void uninit_video_out(struct MPContext *mpctx); void uninit_video_chain(struct MPContext *mpctx); double calc_average_frame_duration(struct MPContext *mpctx); int init_video_decoder(struct MPContext *mpctx, struct track *track); -void recreate_auto_filters(struct MPContext *mpctx); #endif /* MPLAYER_MP_CORE_H */ diff --git a/player/loadfile.c b/player/loadfile.c index 4a886ff156..aa35d38ddf 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -1175,6 +1175,8 @@ static void play_current_file(struct MPContext *mpctx) mpctx->display_sync_error = 0.0; mpctx->display_sync_active = false; mpctx->seek = (struct seek_params){ 0 }; + mpctx->filter_root = mp_filter_create_root(mpctx->global); + mp_filter_root_set_wakeup_cb(mpctx->filter_root, mp_wakeup_core_cb, mpctx); reset_playback_state(mpctx); @@ -1405,6 +1407,7 @@ terminate_playback: uninit_demuxer(mpctx); if (!opts->gapless_audio && !mpctx->encode_lavc_ctx) uninit_audio_out(mpctx); + TA_FREEP(&mpctx->filter_root); mpctx->playback_initialized = false; diff --git a/player/playloop.c b/player/playloop.c index 535bff883f..610bbcdcbf 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -43,7 +43,6 @@ #include "demux/demux.h" #include "stream/stream.h" #include "sub/osd.h" -#include "video/filter/vf.h" #include "video/decode/dec_video.h" #include "video/out/vo.h" @@ -223,6 +222,8 @@ void reset_playback_state(struct MPContext *mpctx) audio_reset_decoding(mpctx->tracks[n]->d_audio); } + mp_filter_reset(mpctx->filter_root); + reset_video_state(mpctx); reset_audio_state(mpctx); reset_subtitle_state(mpctx); @@ -1159,6 +1160,8 @@ void run_playloop(struct MPContext *mpctx) handle_osd_redraw(mpctx); + if (mp_filter_run(mpctx->filter_root)) + mp_wakeup_core(mpctx); mp_wait_events(mpctx); handle_pause_on_low_cache(mpctx); diff --git a/player/sub.c b/player/sub.c index 0de02ea61b..2d644e3e00 100644 --- a/player/sub.c +++ b/player/sub.c @@ -34,7 +34,6 @@ #include "demux/demux.h" #include "video/mp_image.h" #include "video/decode/dec_video.h" -#include "video/filter/vf.h" #include "core.h" @@ -90,7 +89,7 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, return true; if (mpctx->vo_chain) { - struct mp_image_params params = mpctx->vo_chain->vf->input_params; + struct mp_image_params params = mpctx->vo_chain->filter->input_params; if (params.imgfmt) sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms); } diff --git a/player/video.c b/player/video.c index ef1423c8a5..8cf193368c 100644 --- a/player/video.c +++ b/player/video.c @@ -39,7 +39,6 @@ #include "stream/stream.h" #include "sub/osd.h" #include "video/hwdec.h" -#include "video/filter/vf.h" #include "video/decode/dec_video.h" #include "video/decode/vd.h" #include "video/out/vo.h" @@ -49,8 +48,6 @@ #include "command.h" #include "screenshot.h" -#define VF_DEINTERLACE_LABEL "deinterlace" - enum { // update_video() - code also uses: <0 error, 0 eof, >0 progress VD_ERROR = -1, @@ -68,129 +65,13 @@ static const char av_desync_help_text[] = "position will not match to the video (see A-V status field).\n" "\n"; -static void set_allowed_vo_formats(struct vo_chain *vo_c) -{ - vo_query_formats(vo_c->vo, vo_c->vf->allowed_output_formats); -} - -static int try_filter(struct vo_chain *vo_c, char *name, char *label, char **args) -{ - struct vf_instance *vf = vf_append_filter(vo_c->vf, name, args); - if (!vf) - return -1; - - vf->label = talloc_strdup(vf, label); - - if (vf_reconfig(vo_c->vf, &vo_c->input_format) < 0) { - vf_remove_filter(vo_c->vf, vf); - // restore - vf_reconfig(vo_c->vf, &vo_c->input_format); - return -1; - } - return 0; -} - -static bool check_output_format(struct vo_chain *vo_c, int imgfmt) -{ - return vo_c->vf->output_params.imgfmt == imgfmt; -} - -static int probe_deint_filters(struct vo_chain *vo_c) -{ - if (check_output_format(vo_c, IMGFMT_VDPAU)) { - char *args[5] = {"deint", "yes"}; - int pref = 0; - vo_control(vo_c->vo, VOCTRL_GET_PREF_DEINT, &pref); - pref = pref < 0 ? -pref : pref; - if (pref > 0 && pref <= 4) { - const char *types[] = - {"", "first-field", "bob", "temporal", "temporal-spatial"}; - args[2] = "deint-mode"; - args[3] = (char *)types[pref]; - } - - return try_filter(vo_c, "vdpaupp", VF_DEINTERLACE_LABEL, args); - } - if (check_output_format(vo_c, IMGFMT_VAAPI)) - return try_filter(vo_c, "vavpp", VF_DEINTERLACE_LABEL, NULL); - if (check_output_format(vo_c, IMGFMT_D3D11VA) || - check_output_format(vo_c, IMGFMT_D3D11NV12)) - return try_filter(vo_c, "d3d11vpp", VF_DEINTERLACE_LABEL, NULL); - char *args[] = {"mode", "send_field", "deint", "interlaced", NULL}; - return try_filter(vo_c, "yadif", VF_DEINTERLACE_LABEL, args); -} - -// Reconfigure the filter chain according to the new input format. -static void filter_reconfig(struct MPContext *mpctx, struct vo_chain *vo_c) -{ - struct mp_image_params params = vo_c->input_format; - if (!params.imgfmt) - return; - - set_allowed_vo_formats(vo_c); - - char *filters[] = {"autorotate", "deinterlace", NULL}; - for (int n = 0; filters[n]; n++) { - struct vf_instance *vf = vf_find_by_label(vo_c->vf, filters[n]); - if (vf) - vf_remove_filter(vo_c->vf, vf); - } - - if (vo_c->vf->initialized < 1) { - if (vf_reconfig(vo_c->vf, ¶ms) < 0) - return; - } - - if (params.rotate) { - if (!(vo_c->vo->driver->caps & VO_CAP_ROTATE90) || params.rotate % 90) { - // Try to insert a rotation filter. - double angle = params.rotate / 360.0 * M_PI * 2; - char *args[] = {"angle", mp_tprintf(30, "%f", angle), - "ow", mp_tprintf(30, "rotw(%f)", angle), - "oh", mp_tprintf(30, "roth(%f)", angle), - NULL}; - if (try_filter(vo_c, "rotate", "autorotate", args) < 0) - MP_ERR(vo_c, "Can't insert rotation filter.\n"); - } - } - - if (mpctx->opts->deinterlace) - probe_deint_filters(vo_c); -} - -void recreate_auto_filters(struct MPContext *mpctx) -{ - if (!mpctx->vo_chain) - return; - - filter_reconfig(mpctx, mpctx->vo_chain); - - mp_force_video_refresh(mpctx); - - mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL); -} - -static void recreate_video_filters(struct MPContext *mpctx) +static bool recreate_video_filters(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; struct vo_chain *vo_c = mpctx->vo_chain; assert(vo_c); - vf_destroy(vo_c->vf); - vo_c->vf = vf_new(mpctx->global); - vo_c->vf->hwdec_devs = vo_c->hwdec_devs; - vo_c->vf->wakeup_callback = mp_wakeup_core_cb; - vo_c->vf->wakeup_callback_ctx = mpctx; - vo_c->vf->container_fps = vo_c->container_fps; - vo_control(vo_c->vo, VOCTRL_GET_DISPLAY_FPS, &vo_c->vf->display_fps); - - vf_append_filter_list(vo_c->vf, opts->vf_settings); - - // for vf_sub - osd_set_render_subs_in_filter(mpctx->osd, - vf_control_any(vo_c->vf, VFCTRL_INIT_OSD, mpctx->osd) > 0); - - set_allowed_vo_formats(vo_c); + return mp_output_chain_update_filters(vo_c->filter, opts->vf_settings); } int reinit_video_filters(struct MPContext *mpctx) @@ -199,25 +80,20 @@ int reinit_video_filters(struct MPContext *mpctx) if (!vo_c) return 0; - bool need_reconfig = vo_c->vf->initialized != 0; - - recreate_video_filters(mpctx); - if (need_reconfig) - filter_reconfig(mpctx, vo_c); + if (!recreate_video_filters(mpctx)) + return -1; mp_force_video_refresh(mpctx); mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL); - return vo_c->vf->initialized; + return 0; } static void vo_chain_reset_state(struct vo_chain *vo_c) { mp_image_unrefp(&vo_c->input_mpi); - if (vo_c->vf->initialized == 1) - vf_seek_reset(vo_c->vf); vo_seek_reset(vo_c->vo); if (vo_c->video_src) @@ -280,7 +156,7 @@ static void vo_chain_uninit(struct vo_chain *vo_c) mp_image_unrefp(&vo_c->input_mpi); mp_image_unrefp(&vo_c->cached_coverart); - vf_destroy(vo_c->vf); + talloc_free(vo_c->filter->f); talloc_free(vo_c); // this does not free the VO } @@ -384,7 +260,10 @@ void reinit_video_chain_src(struct MPContext *mpctx, struct track *track) mpctx->vo_chain = vo_c; vo_c->log = mpctx->log; vo_c->vo = mpctx->video_out; - vo_c->vf = vf_new(mpctx->global); + vo_c->filter = + mp_output_chain_create(mpctx->filter_root, MP_OUTPUT_CHAIN_VIDEO); + vo_c->filter->container_fps = vo_c->container_fps; + mp_output_chain_set_vo(vo_c->filter, vo_c->vo); vo_c->hwdec_devs = vo_c->vo->hwdec_devs; @@ -407,7 +286,8 @@ void reinit_video_chain_src(struct MPContext *mpctx, struct track *track) encode_lavc_set_video_fps(mpctx->encode_lavc_ctx, vo_c->container_fps); #endif - recreate_video_filters(mpctx); + if (!recreate_video_filters(mpctx)) + goto err_out; update_screensaver_state(mpctx); @@ -435,7 +315,7 @@ void mp_force_video_refresh(struct MPContext *mpctx) struct MPOpts *opts = mpctx->opts; struct vo_chain *vo_c = mpctx->vo_chain; - if (!vo_c || !vo_c->input_format.imgfmt) + if (!vo_c) return; // If not paused, the next frame should come soon enough. @@ -499,68 +379,27 @@ static int decode_image(struct MPContext *mpctx) } } -// Feed newly decoded frames to the filter, take care of format changes. -// If eof=true, drain the filter chain, and return VD_EOF if empty. static int video_filter(struct MPContext *mpctx, bool eof) { struct vo_chain *vo_c = mpctx->vo_chain; - struct vf_chain *vf = vo_c->vf; - - if (vf->initialized < 0) - return VD_ERROR; - - // There is already a filtered frame available. - // If vf_needs_input() returns > 0, the filter wants input anyway. - if (vf_output_frame(vf, eof) > 0 && vf_needs_input(vf) < 1) - return VD_PROGRESS; - - // Decoder output is different from filter input? - bool need_vf_reconfig = !vf->input_params.imgfmt || vf->initialized < 1 || - !mp_image_params_equal(&vo_c->input_format, &vf->input_params); - - // (If imgfmt==0, nothing was decoded yet, and the format is unknown.) - if (need_vf_reconfig && vo_c->input_format.imgfmt) { - // Drain the filter chain. - if (vf_output_frame(vf, true) > 0) - return VD_PROGRESS; - // The filter chain is drained; execute the filter format change. - vf->initialized = 0; - filter_reconfig(mpctx, mpctx->vo_chain); - - mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL); - - // Most video filters don't work with hardware decoding, so this - // might be the reason why filter reconfig failed. - if (vf->initialized < 0 && vo_c->video_src && - video_vd_control(vo_c->video_src, VDCTRL_FORCE_HWDEC_FALLBACK, NULL) - == CONTROL_OK) - { - // Fallback active; decoder will return software format next - // time. Don't abort video decoding. - vf->initialized = 0; - mp_image_unrefp(&vo_c->input_mpi); - vo_c->input_format = (struct mp_image_params){0}; - MP_VERBOSE(mpctx, "hwdec fallback due to filters.\n"); - return VD_PROGRESS; // try again + if (vo_c->input_mpi || eof) { + struct mp_frame frame = {MP_FRAME_VIDEO, vo_c->input_mpi}; + if (!vo_c->input_mpi) { + frame = MP_EOF_FRAME; + if (vo_c->filter->got_input_eof) + return vo_c->filter->got_output_eof ? VD_EOF : VD_WAIT; } - if (vf->initialized < 1) { - MP_FATAL(mpctx, "Cannot initialize video filters.\n"); - return VD_ERROR; + if (mp_pin_in_needs_data(vo_c->filter->f->pins[0])) { + if (osd_get_render_subs_in_filter(mpctx->osd)) + update_subtitles(mpctx, vo_c->input_mpi->pts); + mp_pin_in_write(vo_c->filter->f->pins[0], frame); + vo_c->input_mpi = NULL; + return VD_PROGRESS; } - return VD_RECONFIG; } - // If something was decoded, and the filter chain is ready, filter it. - if (!need_vf_reconfig && vo_c->input_mpi) { - if (osd_get_render_subs_in_filter(mpctx->osd)) - update_subtitles(mpctx, vo_c->input_mpi->pts); - vf_filter_frame(vf, vo_c->input_mpi); - vo_c->input_mpi = NULL; - return VD_PROGRESS; - } - - return eof ? VD_EOF : VD_PROGRESS; + return VD_WAIT; } // Make sure at least 1 filtered image is available, decode new video if needed. @@ -589,33 +428,15 @@ static int video_decode_and_filter(struct MPContext *mpctx) } if (vo_c->input_mpi) { - vo_c->input_format = vo_c->input_mpi->params; - vf_set_proto_frame(vo_c->vf, vo_c->input_mpi); - if (vo_c->is_coverart && !vo_c->cached_coverart) vo_c->cached_coverart = mp_image_new_ref(vo_c->input_mpi); + } else if (r == VD_EOF) { + r = video_filter(mpctx, true); } - bool eof = !vo_c->input_mpi && (r == VD_EOF || r < 0); - r = video_filter(mpctx, eof); - if (r == VD_RECONFIG) // retry feeding decoded image - r = video_filter(mpctx, eof); return r; } -static int video_feed_async_filter(struct MPContext *mpctx) -{ - struct vf_chain *vf = mpctx->vo_chain->vf; - - if (vf->initialized < 0) - return VD_ERROR; - - if (vf_needs_input(vf) < 1) - return 0; - mp_wakeup_core(mpctx); // retry until done - return video_decode_and_filter(mpctx); -} - /* Modify video timing to match the audio timeline. There are two main * reasons this is needed. First, video and audio can start from different * positions at beginning of file or after a seek (MPlayer starts both @@ -749,16 +570,33 @@ static int video_output_image(struct MPContext *mpctx) int r = VD_PROGRESS; if (needs_new_frame(mpctx)) { // Filter a new frame. - r = video_decode_and_filter(mpctx); - if (r < 0) - return r; // error - struct mp_image *img = vf_read_output_frame(vo_c->vf); + if (!mp_pin_out_request_data(vo_c->filter->f->pins[1])) { + r = video_decode_and_filter(mpctx); + if (r < 0) + return r; // error + } + struct mp_image *img = NULL; + struct mp_frame frame = mp_pin_out_read(vo_c->filter->f->pins[1]); + if (frame.type == MP_FRAME_NONE && vo_c->filter->got_output_eof) + frame = MP_EOF_FRAME; + if (frame.type == MP_FRAME_NONE) + return video_decode_and_filter(mpctx); + if (frame.type == MP_FRAME_EOF) { + r = VD_EOF; + } else if (frame.type == MP_FRAME_VIDEO) { + img = frame.data; + } else { + MP_ERR(mpctx, "unexpected frame type %s\n", + mp_frame_type_str(frame.type)); + mp_frame_unref(&frame); + return VD_ERROR; + } if (img) { double endpts = get_play_end_pts(mpctx); if ((endpts != MP_NOPTS_VALUE && img->pts >= endpts) || mpctx->max_frames == 0) { - vf_unread_output_frame(vo_c->vf, img); + mp_pin_out_unread(vo_c->filter->f->pins[1], frame); img = NULL; r = VD_EOF; } else if (hrseek && mpctx->hrseek_lastframe) { @@ -799,6 +637,21 @@ static int video_output_image(struct MPContext *mpctx) return have_new_frame(mpctx, r <= 0) ? VD_NEW_FRAME : r; } +static bool check_for_hwdec_fallback(struct MPContext *mpctx) +{ + struct vo_chain *vo_c = mpctx->vo_chain; + + if (!vo_c->filter->failed_output_conversion || !vo_c->video_src) + return false; + + if (video_vd_control(vo_c->video_src, VDCTRL_FORCE_HWDEC_FALLBACK, NULL) + != CONTROL_OK) + return false; + + mp_output_chain_reset_harder(vo_c->filter); + return true; +} + /* Update avsync before a new video frame is displayed. Actually, this can be * called arbitrarily often before the actual display. * This adjusts the time of the next video frame */ @@ -1228,7 +1081,13 @@ void write_video(struct MPContext *mpctx) if (!mpctx->vo_chain) return; struct track *track = mpctx->vo_chain->track; - struct vo *vo = mpctx->vo_chain->vo; + struct vo_chain *vo_c = mpctx->vo_chain; + struct vo *vo = vo_c->vo; + + if (vo_c->filter->reconfig_happened) { + mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL); + vo_c->filter->reconfig_happened = false; + } // Actual playback starts when both audio and video are ready. if (mpctx->video_status == STATUS_READY) @@ -1247,6 +1106,11 @@ void write_video(struct MPContext *mpctx) return; if (r == VD_EOF) { + if (check_for_hwdec_fallback(mpctx)) + return; + if (vo_c->filter->failed_output_conversion) + goto error; + mpctx->delay = 0; mpctx->last_av_difference = 0; @@ -1334,7 +1198,7 @@ void write_video(struct MPContext *mpctx) // (NB: in theory, the 1st frame after display sync mode change uses the // wrong waiting mode) if (!vo_is_ready_for_frame(vo, mpctx->display_sync_active ? -1 : pts)) { - if (video_feed_async_filter(mpctx) < 0) + if (video_decode_and_filter(mpctx) < 0) goto error; return; } |