f_decoder_wrapper: replace most public fields with setters/getters

I may (optionally) move decoding to a separate thread in a future
change. It's a bit attractive to move the entire decoder wrapper to
there, so if the demuxer has a new packet, it doesn't have to wake up
the main thread, and can directly wake up the decoder. (Although that's
bullshit, since there's a queue in between, and libavcodec's
multi-threaded decoding plays cross-threads ping pong with packets
anyway. On the other hand, the main thread would still have to shuffle
the packets around, so whatever, just seems like better design.)

As preparation, there shouldn't be any mutable state exposed by the
wrapper. But there's still a large number of corner-caseish crap, so
just use setters/getters for them. This recorder thing will inherently
not work, so it'll have to be disabled if threads are used.

This is a bit painful, but probably still the right thing. Like
speculatively pulling teeth.
This commit is contained in:
wm4 2020-02-28 21:17:55 +01:00
parent a8f4ca587d
commit b0b5de3063
7 changed files with 125 additions and 68 deletions

View File

@ -57,6 +57,8 @@ struct priv {
struct mp_codec_params *codec;
struct mp_decoder *decoder;
char *decoder_desc;
bool try_spdif;
// Demuxer output.
struct mp_pin *demux;
@ -86,6 +88,8 @@ struct priv {
struct mp_image_params dec_format, last_format, fixed_format;
double fps;
double start_pts;
double start, end;
struct demux_packet *new_segment;
@ -100,6 +104,11 @@ struct priv {
struct mp_frame decoded_coverart;
int coverart_returned; // 0: no, 1: coverart frame itself, 2: EOF returned
int attempt_framedrops; // try dropping this many frames
int dropped_frames; // total frames _probably_ dropped
bool pts_reset;
int play_dir;
struct mp_decoder_wrapper public;
};
@ -134,9 +143,9 @@ static void reset(struct mp_filter *f)
p->pts = MP_NOPTS_VALUE;
p->last_format = p->fixed_format = (struct mp_image_params){0};
p->public.dropped_frames = 0;
p->public.attempt_framedrops = 0;
p->public.pts_reset = false;
p->dropped_frames = 0;
p->attempt_framedrops = 0;
p->pts_reset = false;
p->coverart_returned = 0;
@ -196,6 +205,9 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
reset_decoder(p);
p->has_broken_packet_pts = -10; // needs 10 packets to reach decision
talloc_free(p->decoder_desc);
p->decoder_desc = NULL;
const struct mp_decoder_fns *driver = NULL;
struct mp_decoder_list *list = NULL;
char *user_list = NULL;
@ -210,7 +222,7 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
user_list = opts->audio_decoders;
fallback = "aac";
if (p->public.try_spdif && p->codec->codec) {
if (p->try_spdif && p->codec->codec) {
struct mp_decoder_list *spdif =
select_spdif_codec(p->codec->codec, opts->audio_spdif);
if (spdif->num_entries) {
@ -241,9 +253,9 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
p->decoder = driver->create(p->f, p->codec, sel->decoder);
if (p->decoder) {
p->public.decoder_desc =
p->decoder_desc =
talloc_asprintf(p, "%s (%s)", sel->decoder, sel->desc);
MP_VERBOSE(p, "Selected codec: %s\n", p->public.decoder_desc);
MP_VERBOSE(p, "Selected codec: %s\n", p->decoder_desc);
break;
}
@ -259,6 +271,49 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
return !!p->decoder;
}
void mp_decoder_wrapper_get_desc(struct mp_decoder_wrapper *d,
char *buf, size_t buf_size)
{
struct priv *p = d->f->priv;
snprintf(buf, buf_size, "%s", p->decoder_desc ? p->decoder_desc : "");
}
void mp_decoder_wrapper_set_frame_drops(struct mp_decoder_wrapper *d, int num)
{
struct priv *p = d->f->priv;
p->attempt_framedrops = num;
}
int mp_decoder_wrapper_get_frames_dropped(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
return p->dropped_frames;
}
double mp_decoder_wrapper_get_container_fps(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
return p->fps;
}
void mp_decoder_wrapper_set_spdif_flag(struct mp_decoder_wrapper *d, bool spdif)
{
struct priv *p = d->f->priv;
p->try_spdif = spdif;
}
bool mp_decoder_wrapper_get_pts_reset(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
return p->pts_reset;
}
void mp_decoder_wrapper_set_play_dir(struct mp_decoder_wrapper *d, int dir)
{
struct priv *p = d->f->priv;
p->play_dir = dir;
}
static bool is_valid_peak(float sig_peak)
{
return !sig_peak || (sig_peak >= 1 && sig_peak <= 100);
@ -371,11 +426,11 @@ static void crazy_video_pts_stuff(struct priv *p, struct mp_image *mpi)
// Compensate for incorrectly using mpeg-style DTS for avi timestamps.
if (p->decoder && p->decoder->control && p->codec->avi_dts &&
mpi->pts != MP_NOPTS_VALUE && p->public.fps > 0)
mpi->pts != MP_NOPTS_VALUE && p->fps > 0)
{
int delay = -1;
p->decoder->control(p->decoder->f, VDCTRL_GET_BFRAMES, &delay);
mpi->pts -= MPMAX(delay, 0) / p->public.fps;
mpi->pts -= MPMAX(delay, 0) / p->fps;
}
}
@ -441,10 +496,10 @@ static void correct_video_pts(struct priv *p, struct mp_image *mpi)
{
struct MPOpts *opts = p->opt_cache->opts;
mpi->pts *= p->public.play_dir;
mpi->pts *= p->play_dir;
if (!opts->correct_pts || mpi->pts == MP_NOPTS_VALUE) {
double fps = p->public.fps > 0 ? p->public.fps : 25;
double fps = p->fps > 0 ? p->fps : 25;
if (opts->correct_pts) {
if (p->has_broken_decoded_pts <= 1) {
@ -471,7 +526,7 @@ static void correct_video_pts(struct priv *p, struct mp_image *mpi)
static void correct_audio_pts(struct priv *p, struct mp_aframe *aframe)
{
double dir = p->public.play_dir;
double dir = p->play_dir;
double frame_pts = mp_aframe_get_pts(aframe);
double frame_len = mp_aframe_duration(aframe);
@ -491,7 +546,7 @@ static void correct_audio_pts(struct priv *p, struct mp_aframe *aframe)
if (p->pts != MP_NOPTS_VALUE && diff > 0.1) {
MP_WARN(p, "Invalid audio PTS: %f -> %f\n", p->pts, frame_pts);
if (diff >= 5)
p->public.pts_reset = true;
p->pts_reset = true;
}
// Keep the interpolated timestamp if it doesn't deviate more
@ -520,11 +575,11 @@ static void process_output_frame(struct priv *p, struct mp_frame frame)
fix_image_params(p, &mpi->params);
mpi->params = p->fixed_format;
mpi->nominal_fps = p->public.fps;
mpi->nominal_fps = p->fps;
} else if (frame.type == MP_FRAME_AUDIO) {
struct mp_aframe *aframe = frame.data;
if (p->public.play_dir < 0 && !mp_aframe_reverse(aframe))
if (p->play_dir < 0 && !mp_aframe_reverse(aframe))
MP_ERR(p, "Couldn't reverse audio frame.\n");
correct_audio_pts(p, aframe);
@ -544,7 +599,7 @@ static bool is_new_segment(struct priv *p, struct mp_frame frame)
struct demux_packet *pkt = frame.data;
return (pkt->segmented && (pkt->start != p->start || pkt->end != p->end ||
pkt->codec != p->codec)) ||
(p->public.play_dir < 0 && pkt->back_restart && p->packet_fed);
(p->play_dir < 0 && pkt->back_restart && p->packet_fed);
}
static void feed_packet(struct priv *p)
@ -590,10 +645,10 @@ static void feed_packet(struct priv *p)
int framedrop_type = 0;
if (p->public.attempt_framedrops)
if (p->attempt_framedrops)
framedrop_type = 1;
if (start_pts != MP_NOPTS_VALUE && packet && p->public.play_dir > 0 &&
if (start_pts != MP_NOPTS_VALUE && packet && p->play_dir > 0 &&
packet->pts < start_pts - .005 && !p->has_broken_packet_pts)
framedrop_type = 2;
@ -695,11 +750,10 @@ static void read_frame(struct priv *p)
return;
}
if (p->public.attempt_framedrops) {
if (p->attempt_framedrops) {
int dropped = MPMAX(0, p->packets_without_output - 1);
p->public.attempt_framedrops =
MPMAX(0, p->public.attempt_framedrops - dropped);
p->public.dropped_frames += dropped;
p->attempt_framedrops = MPMAX(0, p->attempt_framedrops - dropped);
p->dropped_frames += dropped;
}
p->packets_without_output = 0;
@ -715,7 +769,7 @@ static void read_frame(struct priv *p)
bool segment_ended = process_decoded_frame(p, &frame);
if (p->public.play_dir < 0 && frame.type) {
if (p->play_dir < 0 && frame.type) {
enqueue_backward_frame(p, frame);
frame = MP_NO_FRAME;
}
@ -786,10 +840,9 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
p->f = f;
p->header = src;
p->codec = p->header->codec;
p->play_dir = 1;
w->f = f;
w->play_dir = 1;
struct MPOpts *opts = p->opt_cache->opts;
mp_filter_add_pin(f, MP_PIN_OUT, "out");
@ -797,13 +850,13 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
if (p->header->type == STREAM_VIDEO) {
p->log = f->log = mp_log_new(f, parent->log, "!vd");
p->public.fps = src->codec->fps;
p->fps = src->codec->fps;
MP_VERBOSE(p, "Container reported FPS: %f\n", p->public.fps);
MP_VERBOSE(p, "Container reported FPS: %f\n", p->fps);
if (opts->force_fps) {
p->public.fps = opts->force_fps;
MP_INFO(p, "FPS forced to %5.3f.\n", p->public.fps);
p->fps = opts->force_fps;
MP_INFO(p, "FPS forced to %5.3f.\n", p->fps);
MP_INFO(p, "Use --no-correct-pts to force FPS based timing.\n");
}
} else if (p->header->type == STREAM_AUDIO) {

View File

@ -32,29 +32,8 @@ struct mp_decoder_wrapper {
// Filter with no input and 1 output, which returns the decoded data.
struct mp_filter *f;
// For informational purposes.
char *decoder_desc;
// Can be set by user.
struct mp_recorder_sink *recorder_sink;
int play_dir;
// --- for STREAM_VIDEO
// FPS from demuxer or from user override
float fps;
// Framedrop control for playback (not used for hr seek etc.)
int attempt_framedrops; // try dropping this many frames
int dropped_frames; // total frames _probably_ dropped
// --- for STREAM_AUDIO
// Prefer spdif wrapper over real decoders.
bool try_spdif;
// A pts reset was observed (audio only, heuristic).
bool pts_reset;
};
// Create the decoder wrapper for the given stream, plus underlying decoder.
@ -63,6 +42,24 @@ struct mp_decoder_wrapper {
struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
struct sh_stream *src);
// For informational purposes.
void mp_decoder_wrapper_get_desc(struct mp_decoder_wrapper *d,
char *buf, size_t buf_size);
// Legacy decoder framedrop control.
void mp_decoder_wrapper_set_frame_drops(struct mp_decoder_wrapper *d, int num);
int mp_decoder_wrapper_get_frames_dropped(struct mp_decoder_wrapper *d);
double mp_decoder_wrapper_get_container_fps(struct mp_decoder_wrapper *d);
// Whether to prefer spdif wrapper over real decoders on next reinit.
void mp_decoder_wrapper_set_spdif_flag(struct mp_decoder_wrapper *d, bool spdif);
// True if a pts reset was observed (audio only, heuristic).
bool mp_decoder_wrapper_get_pts_reset(struct mp_decoder_wrapper *d);
void mp_decoder_wrapper_set_play_dir(struct mp_decoder_wrapper *d, int dir);
struct mp_decoder_list *video_decoder_list(void);
struct mp_decoder_list *audio_decoder_list(void);

View File

@ -190,7 +190,7 @@ void reset_audio_state(struct MPContext *mpctx)
ao_chain_reset_state(mpctx->ao_chain);
struct track *t = mpctx->ao_chain->track;
if (t && t->dec)
t->dec->play_dir = mpctx->play_dir;
mp_decoder_wrapper_set_play_dir(t->dec, mpctx->play_dir);
}
mpctx->audio_status = mpctx->ao_chain ? STATUS_SYNCING : STATUS_EOF;
mpctx->delay = 0;
@ -389,7 +389,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
MP_VERBOSE(mpctx, "Falling back to PCM output.\n");
ao_c->spdif_passthrough = false;
ao_c->spdif_failed = true;
ao_c->track->dec->try_spdif = false;
mp_decoder_wrapper_set_spdif_flag(ao_c->track->dec, false);
if (!mp_decoder_wrapper_reinit(ao_c->track->dec))
goto init_error;
reset_audio_state(mpctx);
@ -441,7 +441,7 @@ int init_audio_decoder(struct MPContext *mpctx, struct track *track)
goto init_error;
if (track->ao_c)
track->dec->try_spdif = true;
mp_decoder_wrapper_set_spdif_flag(track->dec, true);
if (!mp_decoder_wrapper_reinit(track->dec))
goto init_error;
@ -776,7 +776,7 @@ void reload_audio_output(struct MPContext *mpctx)
if (dec && ao_c->spdif_failed) {
ao_c->spdif_passthrough = true;
ao_c->spdif_failed = false;
dec->try_spdif = true;
mp_decoder_wrapper_set_spdif_flag(ao_c->track->dec, true);
if (!mp_decoder_wrapper_reinit(dec)) {
MP_ERR(mpctx, "Error reinitializing audio.\n");
error_on_track(mpctx, ao_c->track);
@ -836,7 +836,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
}
if (mpctx->vo_chain && ao_c->track && ao_c->track->dec &&
ao_c->track->dec->pts_reset)
mp_decoder_wrapper_get_pts_reset(ao_c->track->dec))
{
MP_WARN(mpctx, "Reset playback due to audio timestamp reset.\n");
reset_playback_state(mpctx);

View File

@ -674,7 +674,8 @@ static int mp_property_frame_drop_dec(void *ctx, struct m_property *prop,
if (!dec)
return M_PROPERTY_UNAVAILABLE;
return m_property_int_ro(action, arg, dec->dropped_frames);
return m_property_int_ro(action, arg,
mp_decoder_wrapper_get_frames_dropped(dec));
}
static int mp_property_mistimed_frame_count(void *ctx, struct m_property *prop,
@ -1753,8 +1754,10 @@ static int mp_property_audio_codec(void *ctx, struct m_property *prop,
{
MPContext *mpctx = ctx;
struct track *track = mpctx->current_track[0][STREAM_AUDIO];
const char *c = track && track->dec ? track->dec->decoder_desc : NULL;
return m_property_strdup_ro(action, arg, c);
char desc[256] = "";
if (track && track->dec)
mp_decoder_wrapper_get_desc(track->dec, desc, sizeof(desc));
return m_property_strdup_ro(action, arg, desc[0] ? desc : NULL);
}
static int property_audiofmt(struct mp_aframe *fmt, int action, void *arg)
@ -1904,9 +1907,9 @@ static int get_track_entry(int item, int action, void *arg, void *ctx)
struct mp_codec_params p =
track->stream ? *track->stream->codec : (struct mp_codec_params){0};
const char *decoder_desc = NULL;
char decoder_desc[256];
if (track->dec)
decoder_desc = track->dec->decoder_desc;
mp_decoder_wrapper_get_desc(track->dec, decoder_desc, sizeof(decoder_desc));
bool has_rg = track->stream && track->stream->codec->replaygain_data;
struct replaygain_data rg = has_rg ? *track->stream->codec->replaygain_data
@ -1940,7 +1943,7 @@ static int get_track_entry(int item, int action, void *arg, void *ctx)
.unavailable = !track->external_filename},
{"ff-index", SUB_PROP_INT(track->ff_index)},
{"decoder-desc", SUB_PROP_STR(decoder_desc),
.unavailable = !decoder_desc},
.unavailable = !decoder_desc[0]},
{"codec", SUB_PROP_STR(p.codec),
.unavailable = !p.codec},
{"demux-w", SUB_PROP_INT(p.disp_w), .unavailable = !p.disp_w},
@ -2106,8 +2109,10 @@ static int mp_property_video_codec(void *ctx, struct m_property *prop,
{
MPContext *mpctx = ctx;
struct track *track = mpctx->current_track[0][STREAM_VIDEO];
const char *c = track && track->dec ? track->dec->decoder_desc : NULL;
return m_property_strdup_ro(action, arg, c);
char desc[256] = "";
if (track && track->dec)
mp_decoder_wrapper_get_desc(track->dec, desc, sizeof(desc));
return m_property_strdup_ro(action, arg, desc[0] ? desc : NULL);
}
static int property_imgparams(struct mp_image_params p, int action, void *arg)

View File

@ -220,7 +220,8 @@ static char *get_term_status_msg(struct MPContext *mpctx)
int64_t c = vo_get_drop_count(mpctx->video_out);
struct mp_decoder_wrapper *dec = mpctx->vo_chain->track
? mpctx->vo_chain->track->dec : NULL;
int dropped_frames = dec ? dec->dropped_frames : 0;
int dropped_frames =
dec ? mp_decoder_wrapper_get_frames_dropped(dec) : 0;
if (c > 0 || dropped_frames > 0) {
saddf(&line, " Dropped: %"PRId64, c);
if (dropped_frames)

View File

@ -229,7 +229,7 @@ void reset_playback_state(struct MPContext *mpctx)
struct track *t = mpctx->tracks[n];
// (Often, but not always, this is redundant and also done elsewhere.)
if (t->dec)
t->dec->play_dir = mpctx->play_dir;
mp_decoder_wrapper_set_play_dir(t->dec, mpctx->play_dir);
if (t->d_sub)
sub_set_play_dir(t->d_sub, mpctx->play_dir);
}

View File

@ -101,7 +101,7 @@ void reset_video_state(struct MPContext *mpctx)
vo_chain_reset_state(mpctx->vo_chain);
struct track *t = mpctx->vo_chain->track;
if (t && t->dec)
t->dec->play_dir = mpctx->play_dir;
mp_decoder_wrapper_set_play_dir(t->dec, mpctx->play_dir);
}
for (int n = 0; n < mpctx->num_next_frames; n++)
@ -259,7 +259,8 @@ void reinit_video_chain_src(struct MPContext *mpctx, struct track *track)
goto err_out;
vo_c->dec_src = track->dec->f->pins[0];
vo_c->filter->container_fps = track->dec->fps;
vo_c->filter->container_fps =
mp_decoder_wrapper_get_container_fps(track->dec);
vo_c->is_coverart = !!track->stream->attached_picture;
vo_c->is_sparse = track->stream->still_image || vo_c->is_coverart;
@ -323,8 +324,8 @@ static void check_framedrop(struct MPContext *mpctx, struct vo_chain *vo_c)
return;
double frame_time = 1.0 / fps;
// try to drop as many frames as we appear to be behind
vo_c->track->dec->attempt_framedrops =
MPCLAMP((mpctx->last_av_difference - 0.010) / frame_time, 0, 100);
mp_decoder_wrapper_set_frame_drops(vo_c->track->dec,
MPCLAMP((mpctx->last_av_difference - 0.010) / frame_time, 0, 100));
}
}