summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/command.c50
-rw-r--r--player/core.h12
-rw-r--r--player/loadfile.c3
-rw-r--r--player/playloop.c5
-rw-r--r--player/sub.c3
-rw-r--r--player/video.c292
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, &params);
}
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, &params) < 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;
}