diff options
Diffstat (limited to 'player/audio.c')
-rw-r--r-- | player/audio.c | 87 |
1 files changed, 61 insertions, 26 deletions
diff --git a/player/audio.c b/player/audio.c index 50c0faaf09..da91dd4340 100644 --- a/player/audio.c +++ b/player/audio.c @@ -22,7 +22,6 @@ #include <math.h> #include <assert.h> -#include "config.h" #include "mpv_talloc.h" #include "common/msg.h" @@ -64,9 +63,17 @@ static void update_speed_filters(struct MPContext *mpctx) speed = 1.0; } - if (mpctx->display_sync_active && mpctx->opts->video_sync == VS_DISP_ADROP) { - drop *= speed * resample; - resample = speed = 1.0; + if (mpctx->display_sync_active) { + switch (mpctx->video_out->opts->video_sync) { + case VS_DISP_ADROP: + drop *= speed * resample; + resample = speed = 1.0; + break; + case VS_DISP_TEMPO: + speed = mpctx->audio_speed; + resample = 1.0; + break; + } } mp_output_chain_set_audio_speed(ao_c->filter, speed, resample, drop); @@ -168,6 +175,7 @@ void audio_update_volume(struct MPContext *mpctx) float gain = MPMAX(opts->softvol_volume / 100.0, 0); gain = pow(gain, 3); gain *= compute_replaygain(mpctx); + gain *= db_gain(opts->softvol_gain); if (opts->softvol_mute == 1) gain = 0.0; @@ -183,11 +191,24 @@ void update_playback_speed(struct MPContext *mpctx) update_speed_filters(mpctx); } +static bool has_video_track(struct MPContext *mpctx) +{ + if (mpctx->vo_chain && mpctx->vo_chain->is_coverart) + return false; + + for (int n = 0; n < mpctx->num_tracks; n++) { + struct track *track = mpctx->tracks[n]; + if (track->type == STREAM_VIDEO && !track->attached_picture && !track->image) + return true; + } + + return false; +} + static void ao_chain_reset_state(struct ao_chain *ao_c) { ao_c->last_out_pts = MP_NOPTS_VALUE; ao_c->out_eof = false; - ao_c->underrun = false; ao_c->start_pts_known = false; ao_c->start_pts = MP_NOPTS_VALUE; ao_c->untimed_throttle = false; @@ -281,8 +302,7 @@ static bool keep_weak_gapless_format(struct mp_aframe *old, struct mp_aframe* ne { bool res = false; struct mp_aframe *new_mod = mp_aframe_new_ref(new); - if (!new_mod) - abort(); + MP_HANDLE_OOM(new_mod); // If the sample formats are compatible (== libswresample generally can // convert them), keep the AO. On other changes, recreate it. @@ -314,6 +334,7 @@ static void ao_chain_set_ao(struct ao_chain *ao_c, struct ao *ao) mp_async_queue_set_notifier(ao_c->queue_filter, ao_c->ao_filter); // Make sure filtering never stops with frames stuck in access filter. mp_filter_set_high_priority(ao_c->queue_filter, true); + audio_update_volume(ao_c->mpctx); } if (ao_c->filter->ao_needs_update) @@ -322,7 +343,7 @@ static void ao_chain_set_ao(struct ao_chain *ao_c, struct ao *ao) mp_filter_wakeup(ao_c->ao_filter); } -static void reinit_audio_filters_and_output(struct MPContext *mpctx) +static int reinit_audio_filters_and_output(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; struct ao_chain *ao_c = mpctx->ao_chain; @@ -333,8 +354,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) // The "ideal" filter output format struct mp_aframe *out_fmt = mp_aframe_new_ref(ao_c->filter->output_aformat); - if (!out_fmt) - abort(); + MP_HANDLE_OOM(out_fmt); if (!mp_aframe_config_is_valid(out_fmt)) { talloc_free(out_fmt); @@ -359,13 +379,13 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) { ao_chain_set_ao(ao_c, mpctx->ao); talloc_free(out_fmt); - return; + return 0; } // Wait until all played. if (mpctx->ao && ao_is_playing(mpctx->ao)) { talloc_free(out_fmt); - return; + return 0; } // Format change during syncing. Force playback start early, then wait. if (ao_c->ao_queue && mp_async_queue_get_frames(ao_c->ao_queue) && @@ -374,11 +394,11 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) mpctx->audio_status = STATUS_READY; mp_wakeup_core(mpctx); talloc_free(out_fmt); - return; + return 0; } if (mpctx->audio_status == STATUS_READY) { talloc_free(out_fmt); - return; + return 0; } uninit_audio_out(mpctx); @@ -411,6 +431,9 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) opts->audio_output_channels.num_chmaps); } + if (!has_video_track(mpctx)) + ao_flags |= AO_INIT_MEDIA_ROLE_MUSIC; + mpctx->ao_filter_fmt = out_fmt; mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb, @@ -446,7 +469,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) reset_audio_state(mpctx); mp_output_chain_reset_harder(ao_c->filter); mp_wakeup_core(mpctx); // reinit with new format next time - return; + return 0; } MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n"); @@ -464,7 +487,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) ao_c->ao_resume_time = opts->audio_wait_open > 0 ? mp_time_sec() + opts->audio_wait_open : 0; - ao_set_paused(mpctx->ao, get_internal_paused(mpctx)); + bool eof = mpctx->audio_status == STATUS_EOF; + ao_set_paused(mpctx->ao, get_internal_paused(mpctx), eof); ao_chain_set_ao(ao_c, mpctx->ao); @@ -477,12 +501,13 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx) mp_wakeup_core(mpctx); mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL); - return; + return 0; init_error: uninit_audio_chain(mpctx); uninit_audio_out(mpctx); error_on_track(mpctx, track); + return -1; } int init_audio_decoder(struct MPContext *mpctx, struct track *track) @@ -516,7 +541,8 @@ void reinit_audio_chain(struct MPContext *mpctx) struct track *track = NULL; track = mpctx->current_track[0][STREAM_AUDIO]; if (!track || !track->stream) { - uninit_audio_out(mpctx); + if (!mpctx->encode_lavc_ctx) + uninit_audio_out(mpctx); error_on_track(mpctx, track); return; } @@ -592,7 +618,7 @@ double playing_audio_pts(struct MPContext *mpctx) double pts = written_audio_pts(mpctx); if (pts == MP_NOPTS_VALUE || !mpctx->ao) return pts; - return pts - mpctx->audio_speed * ao_get_delay(mpctx->ao); + return pts - ao_get_delay(mpctx->ao); } // This garbage is needed for untimed AOs. These consume audio infinitely fast, @@ -634,7 +660,7 @@ static void ao_process(struct mp_filter *f) return; } - // Due to mp_async_queue_set_notifier() thhis function is called when the + // Due to mp_async_queue_set_notifier() this function is called when the // queue becomes full. This affects state changes in the normal playloop, // so wake it up. But avoid redundant wakeups during normal playback. if (mpctx->audio_status != STATUS_PLAYING && @@ -698,7 +724,8 @@ static void ao_process(struct mp_filter *f) mpctx->shown_aframes += samples; double real_samplerate = mp_aframe_get_rate(af) / mpctx->audio_speed; - mpctx->delay += samples / real_samplerate; + if (mpctx->video_status != STATUS_EOF) + mpctx->delay += samples / real_samplerate; ao_c->last_out_pts = mp_aframe_end_pts(af); update_throttle(mpctx); @@ -802,7 +829,8 @@ void audio_start_ao(struct MPContext *mpctx) double pts = MP_NOPTS_VALUE; if (!get_sync_pts(mpctx, &pts)) return; - double apts = playing_audio_pts(mpctx); // (basically including mpctx->delay) + double apts = written_audio_pts(mpctx); + apts -= apts != MP_NOPTS_VALUE ? mpctx->audio_speed * ao_get_delay(mpctx->ao) : 0; if (pts != MP_NOPTS_VALUE && apts != MP_NOPTS_VALUE && pts < apts && mpctx->video_status != STATUS_EOF) { @@ -818,10 +846,13 @@ void audio_start_ao(struct MPContext *mpctx) } MP_VERBOSE(mpctx, "starting audio playback\n"); + ao_c->audio_started = true; ao_start(ao_c->ao); mpctx->audio_status = STATUS_PLAYING; - if (ao_c->out_eof) + if (ao_c->out_eof) { mpctx->audio_status = STATUS_DRAINING; + MP_VERBOSE(mpctx, "audio draining\n"); + } ao_c->underrun = false; mpctx->logged_async_diff = -1; mp_wakeup_core(mpctx); @@ -849,8 +880,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx) return; } - if (ao_c->filter->ao_needs_update) - reinit_audio_filters_and_output(mpctx); + if (ao_c->filter->ao_needs_update) { + if (reinit_audio_filters_and_output(mpctx) < 0) + return; + } if (mpctx->vo_chain && ao_c->track && ao_c->track->dec && mp_decoder_wrapper_get_pts_reset(ao_c->track->dec)) @@ -870,8 +903,10 @@ void fill_audio_out_buffers(struct MPContext *mpctx) // until the old audio is fully played. // (Buggy if AO underruns.) if (mpctx->ao && ao_is_playing(mpctx->ao) && - mpctx->video_status != STATUS_EOF) + mpctx->video_status != STATUS_EOF) { + MP_VERBOSE(mpctx, "blocked, waiting for old audio to play\n"); ok = false; + } if (ao_c->start_pts_known != ok || ao_c->start_pts != pts) { ao_c->start_pts_known = ok; |