diff options
Diffstat (limited to 'filters')
-rw-r--r-- | filters/f_decoder_wrapper.c | 80 | ||||
-rw-r--r-- | filters/f_decoder_wrapper.h | 11 | ||||
-rw-r--r-- | filters/f_output_chain.c | 9 |
3 files changed, 92 insertions, 8 deletions
diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c index e85621957f..7e948faebb 100644 --- a/filters/f_decoder_wrapper.c +++ b/filters/f_decoder_wrapper.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> +#include <math.h> #include <assert.h> #include <libavutil/buffer.h> @@ -36,6 +37,7 @@ #include "common/global.h" #include "common/recorder.h" +#include "audio/aframe.h" #include "video/out/vo.h" #include "video/csputils.h" @@ -149,6 +151,13 @@ struct mp_decoder_list *video_decoder_list(void) return list; } +struct mp_decoder_list *audio_decoder_list(void) +{ + struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); + ad_lavc.add_decoders(list); + return list; +} + bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d) { struct priv *p = d->f->priv; @@ -161,13 +170,36 @@ 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 - const struct mp_decoder_fns *driver = &vd_lavc; + const struct mp_decoder_fns *driver = NULL; + struct mp_decoder_list *list = NULL; + char *user_list = NULL; + + if (p->codec->type == STREAM_VIDEO) { + driver = &vd_lavc; + user_list = opts->video_decoders; + } else if (p->codec->type == STREAM_AUDIO) { + driver = &ad_lavc; + user_list = opts->audio_decoders; + + if (p->public.try_spdif && p->codec->codec) { + struct mp_decoder_list *spdif = + select_spdif_codec(p->codec->codec, opts->audio_spdif); + if (spdif->num_entries) { + driver = &ad_spdif; + list = spdif; + } else { + talloc_free(spdif); + } + } + } - struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list); - driver->add_decoders(full); - struct mp_decoder_list *list = - mp_select_decoders(p->log, full, p->codec->codec, opts->video_decoders); - talloc_free(full); + if (!list) { + struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list); + if (driver) + driver->add_decoders(full); + list = mp_select_decoders(p->log, full, p->codec->codec, user_list); + talloc_free(full); + } mp_print_decoders(p->log, MSGL_V, "Codec list:", list); @@ -363,6 +395,29 @@ void mp_decoder_wrapper_get_video_dec_params(struct mp_decoder_wrapper *d, *m = p->dec_format; } +static void process_audio_frame(struct priv *p, struct mp_aframe *aframe) +{ + double frame_pts = mp_aframe_get_pts(aframe); + if (frame_pts != MP_NOPTS_VALUE) { + if (p->pts != MP_NOPTS_VALUE) + MP_STATS(p, "value %f audio-pts-err", p->pts - frame_pts); + + // Keep the interpolated timestamp if it doesn't deviate more + // than 1 ms from the real one. (MKV rounded timestamps.) + if (p->pts == MP_NOPTS_VALUE || fabs(p->pts - frame_pts) > 0.001) + p->pts = frame_pts; + } + + if (p->pts == MP_NOPTS_VALUE && p->header->missing_timestamps) + p->pts = 0; + + mp_aframe_set_pts(aframe, p->pts); + + if (p->pts != MP_NOPTS_VALUE) + p->pts += mp_aframe_duration(aframe); +} + + // Frames before the start timestamp can be dropped. (Used for hr-seek.) void mp_decoder_wrapper_set_start_pts(struct mp_decoder_wrapper *d, double pts) { @@ -470,6 +525,17 @@ static bool process_decoded_frame(struct priv *p, struct mp_frame *frame) if ((p->start != MP_NOPTS_VALUE && vpts < p->start) || segment_ended) mp_frame_unref(frame); } + } else if (frame->type == MP_FRAME_AUDIO) { + struct mp_aframe *aframe = frame->data; + + process_audio_frame(p, aframe); + + mp_aframe_clip_timestamps(aframe, p->start, p->end); + double pts = mp_aframe_get_pts(aframe); + if (pts != MP_NOPTS_VALUE && p->start != MP_NOPTS_VALUE) + segment_ended = pts >= p->end; + if (mp_aframe_get_size(aframe) == 0) + mp_frame_unref(frame); } else { MP_ERR(p, "unknown frame type from decoder\n"); } @@ -588,6 +654,8 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent, MP_INFO(p, "FPS forced to %5.3f.\n", p->public.fps); MP_INFO(p, "Use --no-correct-pts to force FPS based timing.\n"); } + } else if (p->header->type == STREAM_AUDIO) { + p->log = f->log = mp_log_new(f, parent->log, "!ad"); } struct mp_filter *demux = mp_demux_in_create(f, p->header); diff --git a/filters/f_decoder_wrapper.h b/filters/f_decoder_wrapper.h index 4d970bd79a..e6601052a2 100644 --- a/filters/f_decoder_wrapper.h +++ b/filters/f_decoder_wrapper.h @@ -46,6 +46,11 @@ struct mp_decoder_wrapper { // 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; }; // Create the decoder wrapper for the given stream, plus underlying decoder. @@ -55,6 +60,7 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent, struct sh_stream *src); struct mp_decoder_list *video_decoder_list(void); +struct mp_decoder_list *audio_decoder_list(void); // For precise seeking: if possible, try to drop frames up until the given PTS. // This is automatically unset if the target is reached, or on reset. @@ -96,9 +102,14 @@ struct mp_decoder_fns { }; extern const struct mp_decoder_fns vd_lavc; +extern const struct mp_decoder_fns ad_lavc; +extern const struct mp_decoder_fns ad_spdif; // Convenience wrapper for lavc based decoders. eof_flag must be set to false // on init and resets. void lavc_process(struct mp_filter *f, bool *eof_flag, bool (*send)(struct mp_filter *f, struct demux_packet *pkt), bool (*receive)(struct mp_filter *f, struct mp_frame *res)); + +// ad_spdif.c +struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref); diff --git a/filters/f_output_chain.c b/filters/f_output_chain.c index e53f9eafaa..ea6a0a3981 100644 --- a/filters/f_output_chain.c +++ b/filters/f_output_chain.c @@ -452,8 +452,13 @@ void mp_output_chain_reset_harder(struct mp_output_chain *c) mp_filter_reset(p->f); p->public.failed_output_conversion = false; - for (int n = 0; n < p->num_all_filters; n++) - p->all_filters[n]->failed = false; + for (int n = 0; n < p->num_all_filters; n++) { + struct mp_user_filter *u = p->all_filters[n]; + + u->failed = false; + u->last_out_params = (struct mp_image_params){0}; + mp_aframe_reset(u->last_out_aformat); + } } static void destroy(struct mp_filter *f) |