summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-02-28 21:17:55 +0100
committerwm4 <wm4@nowhere>2020-02-29 01:23:20 +0100
commitb0b5de306387f03f7f79a34ecc7d2aaf223f180a (patch)
tree40fa6a05b16e4e79829e0acc6434edf8100f046e
parenta8f4ca587dba1c1579e20b3361196c78babab7fa (diff)
downloadmpv-b0b5de306387f03f7f79a34ecc7d2aaf223f180a.tar.bz2
mpv-b0b5de306387f03f7f79a34ecc7d2aaf223f180a.tar.xz
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.
-rw-r--r--filters/f_decoder_wrapper.c109
-rw-r--r--filters/f_decoder_wrapper.h39
-rw-r--r--player/audio.c10
-rw-r--r--player/command.c21
-rw-r--r--player/osd.c3
-rw-r--r--player/playloop.c2
-rw-r--r--player/video.c9
7 files changed, 125 insertions, 68 deletions
diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c
index 6f90df04ad..23e796a6bc 100644
--- a/filters/f_decoder_wrapper.c
+++ b/filters/f_decoder_wrapper.c
@@ -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) {
diff --git a/filters/f_decoder_wrapper.h b/filters/f_decoder_wrapper.h
index 28d9b5cb7b..51badaaabd 100644
--- a/filters/f_decoder_wrapper.h
+++ b/filters/f_decoder_wrapper.h
@@ -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);
diff --git a/player/audio.c b/player/audio.c
index 8aba3d860b..cde444ffb4 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -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);
diff --git a/player/command.c b/player/command.c
index 9e0f4f64e9..fb28b285e1 100644
--- a/player/command.c
+++ b/player/command.c
@@ -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)
diff --git a/player/osd.c b/player/osd.c
index ff9bd9b429..0e8fd2a0e7 100644
--- a/player/osd.c
+++ b/player/osd.c
@@ -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)
diff --git a/player/playloop.c b/player/playloop.c
index c8c74edb64..9660a5b6ad 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -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);
}
diff --git a/player/video.c b/player/video.c
index d1e1554ef0..2e0c8f6460 100644
--- a/player/video.c
+++ b/player/video.c
@@ -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));
}
}