mirror of https://github.com/mpv-player/mpv
video: refactor: handle video format fixups closer to decoder
Instead of handling this on filter chain reinit, do it directly after the decoder. This makes the code less entangled. In particular, this gets rid of the really weird "override params" concept in the video filter code. The last_format/fixed_formats have some redundance with decoder_output, but unfortunately the latter has a slightly different use.
This commit is contained in:
parent
dd973da108
commit
bf13bd0d47
|
@ -2512,8 +2512,8 @@ static int mp_property_vd_imgparams(void *ctx, struct m_property *prop,
|
|||
if (!vd)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
struct mp_codec_params *c = vd->header->codec;
|
||||
if (vd->vfilter->override_params.imgfmt) {
|
||||
return property_imgparams(vd->vfilter->override_params, action, arg);
|
||||
if (vd->vfilter->input_params.imgfmt) {
|
||||
return property_imgparams(vd->vfilter->input_params, action, arg);
|
||||
} else if (c->disp_w && c->disp_h) {
|
||||
// Simplistic fallback for stupid scripts querying "width"/"height"
|
||||
// before the first frame is decoded.
|
||||
|
@ -2779,7 +2779,7 @@ static int mp_property_aspect(void *ctx, struct m_property *prop,
|
|||
if (mpctx->d_video && aspect <= 0) {
|
||||
struct dec_video *d_video = mpctx->d_video;
|
||||
struct mp_codec_params *c = d_video->header->codec;
|
||||
struct mp_image_params *params = &d_video->vfilter->override_params;
|
||||
struct mp_image_params *params = &d_video->vfilter->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);
|
||||
|
|
|
@ -78,7 +78,7 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts, int order
|
|||
return true;
|
||||
|
||||
if (mpctx->d_video) {
|
||||
struct mp_image_params params = mpctx->d_video->vfilter->override_params;
|
||||
struct mp_image_params params = mpctx->d_video->vfilter->input_params;
|
||||
if (params.imgfmt)
|
||||
sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, ¶ms);
|
||||
}
|
||||
|
|
|
@ -84,10 +84,10 @@ static int try_filter(struct MPContext *mpctx, struct mp_image_params params,
|
|||
|
||||
vf->label = talloc_strdup(vf, label);
|
||||
|
||||
if (video_reconfig_filters(d_video, ¶ms) < 0) {
|
||||
if (vf_reconfig(d_video->vfilter, ¶ms) < 0) {
|
||||
vf_remove_filter(d_video->vfilter, vf);
|
||||
// restore
|
||||
video_reconfig_filters(d_video, ¶ms);
|
||||
vf_reconfig(d_video->vfilter, ¶ms);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -107,7 +107,7 @@ static void filter_reconfig(struct MPContext *mpctx,
|
|||
|
||||
set_allowed_vo_formats(d_video->vfilter, mpctx->video_out);
|
||||
|
||||
if (video_reconfig_filters(d_video, ¶ms) < 0) {
|
||||
if (vf_reconfig(d_video->vfilter, ¶ms) < 0) {
|
||||
// Most video filters don't work with hardware decoding, so this
|
||||
// might be the reason why filter reconfig failed.
|
||||
if (!probe_only &&
|
||||
|
@ -119,6 +119,8 @@ static void filter_reconfig(struct MPContext *mpctx,
|
|||
mp_image_unrefp(&d_video->waiting_decoded_mpi);
|
||||
d_video->decoder_output = (struct mp_image_params){0};
|
||||
MP_VERBOSE(mpctx, "hwdec falback due to filters.\n");
|
||||
} else {
|
||||
MP_FATAL(mpctx, "Cannot initialize video filters.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ void video_reset_decoding(struct dec_video *d_video)
|
|||
d_video->decoded_pts = MP_NOPTS_VALUE;
|
||||
d_video->codec_pts = MP_NOPTS_VALUE;
|
||||
d_video->codec_dts = MP_NOPTS_VALUE;
|
||||
d_video->last_format = d_video->fixed_format = (struct mp_image_params){0};
|
||||
}
|
||||
|
||||
int video_vd_control(struct dec_video *d_video, int cmd, void *arg)
|
||||
|
@ -209,6 +210,65 @@ bool video_init_best_codec(struct dec_video *d_video, char* video_decoders)
|
|||
return !!d_video->vd_driver;
|
||||
}
|
||||
|
||||
static void fix_image_params(struct dec_video *d_video,
|
||||
struct mp_image_params *params)
|
||||
{
|
||||
struct MPOpts *opts = d_video->opts;
|
||||
struct mp_image_params p = *params;
|
||||
struct mp_codec_params *c = d_video->header->codec;
|
||||
|
||||
MP_VERBOSE(d_video, "Decoder format: %s\n", mp_image_params_to_str(params));
|
||||
|
||||
// While mp_image_params normally always have to have d_w/d_h set, the
|
||||
// decoder signals unknown bitstream aspect ratio with both set to 0.
|
||||
float dec_aspect = p.p_w > 0 && p.p_h > 0 ? p.p_w / (float)p.p_h : 0;
|
||||
if (d_video->initial_decoder_aspect == 0)
|
||||
d_video->initial_decoder_aspect = dec_aspect;
|
||||
|
||||
bool use_container = true;
|
||||
switch (opts->aspect_method) {
|
||||
case 0:
|
||||
// We normally prefer the container aspect, unless the decoder aspect
|
||||
// changes at least once.
|
||||
if (dec_aspect > 0 && d_video->initial_decoder_aspect != dec_aspect) {
|
||||
MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n");
|
||||
// Even if the aspect switches back, don't use container aspect again.
|
||||
d_video->initial_decoder_aspect = -1;
|
||||
use_container = false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
use_container = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_container && c->par_w > 0 && c->par_h) {
|
||||
MP_VERBOSE(d_video, "Using container aspect ratio.\n");
|
||||
p.p_w = c->par_w;
|
||||
p.p_h = c->par_h;
|
||||
}
|
||||
|
||||
if (opts->movie_aspect >= 0) {
|
||||
MP_VERBOSE(d_video, "Forcing user-set aspect ratio.\n");
|
||||
if (opts->movie_aspect == 0) {
|
||||
p.p_w = p.p_h = 1;
|
||||
} else {
|
||||
AVRational a = av_d2q(opts->movie_aspect, INT_MAX);
|
||||
mp_image_params_set_dsize(&p, a.num, a.den);
|
||||
}
|
||||
}
|
||||
|
||||
// Assume square pixels if no aspect ratio is set at all.
|
||||
if (p.p_w <= 0 || p.p_h <= 0)
|
||||
p.p_w = p.p_h = 1;
|
||||
|
||||
// Detect colorspace from resolution.
|
||||
mp_image_params_guess_csp(&p);
|
||||
|
||||
d_video->last_format = *params;
|
||||
d_video->fixed_format = p;
|
||||
}
|
||||
|
||||
static void add_avi_pts(struct dec_video *d_video, double pts)
|
||||
{
|
||||
if (pts != MP_NOPTS_VALUE) {
|
||||
|
@ -329,72 +389,16 @@ struct mp_image *video_decode(struct dec_video *d_video,
|
|||
if (d_video->num_codec_pts_problems || pkt_pts == MP_NOPTS_VALUE)
|
||||
d_video->has_broken_packet_pts = 1;
|
||||
|
||||
if (!mp_image_params_equal(&d_video->last_format, &mpi->params))
|
||||
fix_image_params(d_video, &mpi->params);
|
||||
|
||||
mpi->params = d_video->fixed_format;
|
||||
|
||||
mpi->pts = pts;
|
||||
d_video->decoded_pts = pts;
|
||||
return mpi;
|
||||
}
|
||||
|
||||
int video_reconfig_filters(struct dec_video *d_video,
|
||||
const struct mp_image_params *params)
|
||||
{
|
||||
struct MPOpts *opts = d_video->opts;
|
||||
struct mp_image_params p = *params;
|
||||
struct mp_codec_params *c = d_video->header->codec;
|
||||
|
||||
// While mp_image_params normally always have to have d_w/d_h set, the
|
||||
// decoder signals unknown bitstream aspect ratio with both set to 0.
|
||||
float dec_aspect = p.p_w > 0 && p.p_h > 0 ? p.p_w / (float)p.p_h : 0;
|
||||
if (d_video->initial_decoder_aspect == 0)
|
||||
d_video->initial_decoder_aspect = dec_aspect;
|
||||
|
||||
bool use_container = true;
|
||||
switch (opts->aspect_method) {
|
||||
case 0:
|
||||
// We normally prefer the container aspect, unless the decoder aspect
|
||||
// changes at least once.
|
||||
if (dec_aspect > 0 && d_video->initial_decoder_aspect != dec_aspect) {
|
||||
MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n");
|
||||
// Even if the aspect switches back, don't use container aspect again.
|
||||
d_video->initial_decoder_aspect = -1;
|
||||
use_container = false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
use_container = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_container && c->par_w > 0 && c->par_h) {
|
||||
MP_VERBOSE(d_video, "Using container aspect ratio.\n");
|
||||
p.p_w = c->par_w;
|
||||
p.p_h = c->par_h;
|
||||
}
|
||||
|
||||
if (opts->movie_aspect >= 0) {
|
||||
MP_VERBOSE(d_video, "Forcing user-set aspect ratio.\n");
|
||||
if (opts->movie_aspect == 0) {
|
||||
p.p_w = p.p_h = 1;
|
||||
} else {
|
||||
AVRational a = av_d2q(opts->movie_aspect, INT_MAX);
|
||||
mp_image_params_set_dsize(&p, a.num, a.den);
|
||||
}
|
||||
}
|
||||
|
||||
// Assume square pixels if no aspect ratio is set at all.
|
||||
if (p.p_w <= 0 || p.p_h <= 0)
|
||||
p.p_w = p.p_h = 1;
|
||||
|
||||
// Detect colorspace from resolution.
|
||||
mp_image_params_guess_csp(&p);
|
||||
|
||||
if (vf_reconfig(d_video->vfilter, params, &p) < 0) {
|
||||
MP_FATAL(d_video, "Cannot initialize video filters.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send a VCTRL, or if it doesn't work, translate it to a VOCTRL and try the VO.
|
||||
int video_vf_vo_control(struct dec_video *d_video, int vf_cmd, void *data)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,8 @@ struct dec_video {
|
|||
double decoded_pts;
|
||||
|
||||
float fps; // FPS from demuxer or from user override
|
||||
|
||||
struct mp_image_params last_format, fixed_format;
|
||||
float initial_decoder_aspect;
|
||||
|
||||
// State used only by player/video.c
|
||||
|
@ -90,9 +92,6 @@ int video_set_colors(struct dec_video *d_video, const char *item, int value);
|
|||
void video_reset_decoding(struct dec_video *d_video);
|
||||
int video_vd_control(struct dec_video *d_video, int cmd, void *arg);
|
||||
|
||||
int video_reconfig_filters(struct dec_video *d_video,
|
||||
const struct mp_image_params *params);
|
||||
|
||||
int video_vf_vo_control(struct dec_video *d_video, int vf_cmd, void *data);
|
||||
|
||||
#endif /* MPLAYER_DEC_VIDEO_H */
|
||||
|
|
|
@ -211,13 +211,8 @@ void vf_print_filter_chain(struct vf_chain *c, int msglevel,
|
|||
if (!mp_msg_test(c->log, msglevel))
|
||||
return;
|
||||
|
||||
char b[128] = {0};
|
||||
|
||||
mp_snprintf_cat(b, sizeof(b), "%s", mp_image_params_to_str(&c->input_params));
|
||||
mp_msg(c->log, msglevel, " [vd] %s\n", b);
|
||||
|
||||
for (vf_instance_t *f = c->first; f; f = f->next) {
|
||||
b[0] = '\0';
|
||||
char b[128] = {0};
|
||||
mp_snprintf_cat(b, sizeof(b), " [%s] ", f->info->name);
|
||||
mp_snprintf_cat(b, sizeof(b), "%s", mp_image_params_to_str(&f->fmt_out));
|
||||
if (f->autoinserted)
|
||||
|
@ -392,7 +387,6 @@ int vf_filter_frame(struct vf_chain *c, struct mp_image *img)
|
|||
return -1;
|
||||
}
|
||||
assert(mp_image_params_equal(&img->params, &c->input_params));
|
||||
vf_fix_img_params(img, &c->override_params);
|
||||
return vf_do_filter(c->first, img);
|
||||
}
|
||||
|
||||
|
@ -585,10 +579,7 @@ static int vf_reconfig_wrapper(struct vf_instance *vf,
|
|||
return r;
|
||||
}
|
||||
|
||||
// override_params is used to forcibly change the parameters of input images,
|
||||
// while params has to match the input images exactly.
|
||||
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params,
|
||||
const struct mp_image_params *override_params)
|
||||
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params)
|
||||
{
|
||||
int r = 0;
|
||||
vf_seek_reset(c);
|
||||
|
@ -599,9 +590,8 @@ int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params,
|
|||
vf = next;
|
||||
}
|
||||
c->input_params = *params;
|
||||
c->first->fmt_in = *override_params;
|
||||
c->override_params = *override_params;
|
||||
struct mp_image_params cur = c->override_params;
|
||||
c->first->fmt_in = *params;
|
||||
struct mp_image_params cur = *params;
|
||||
|
||||
uint8_t unused[IMGFMT_END - IMGFMT_START];
|
||||
update_formats(c, c->first, unused);
|
||||
|
@ -621,10 +611,8 @@ int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params,
|
|||
MP_ERR(c, "Image formats incompatible or invalid.\n");
|
||||
mp_msg(c->log, loglevel, "Video filter chain:\n");
|
||||
vf_print_filter_chain(c, loglevel, failing);
|
||||
if (r < 0) {
|
||||
c->input_params = c->override_params = c->output_params =
|
||||
(struct mp_image_params){0};
|
||||
}
|
||||
if (r < 0)
|
||||
c->input_params = c->output_params = (struct mp_image_params){0};
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ struct vf_chain {
|
|||
struct vf_instance *first, *last;
|
||||
|
||||
struct mp_image_params input_params;
|
||||
struct mp_image_params override_params; // input to first filter
|
||||
struct mp_image_params output_params;
|
||||
uint8_t allowed_output_formats[IMGFMT_END - IMGFMT_START];
|
||||
|
||||
|
@ -149,8 +148,7 @@ enum vf_ctrl {
|
|||
|
||||
struct vf_chain *vf_new(struct mpv_global *global);
|
||||
void vf_destroy(struct vf_chain *c);
|
||||
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params,
|
||||
const struct mp_image_params *override_params);
|
||||
int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params);
|
||||
int vf_control_any(struct vf_chain *c, int cmd, void *arg);
|
||||
int vf_control_by_label(struct vf_chain *c, int cmd, void *arg, bstr label);
|
||||
int vf_filter_frame(struct vf_chain *c, struct mp_image *img);
|
||||
|
|
Loading…
Reference in New Issue