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)); } }