diff options
author | Martin Herkt <lachs0r@srsfckn.biz> | 2016-02-28 23:31:51 +0100 |
---|---|---|
committer | Martin Herkt <lachs0r@srsfckn.biz> | 2016-02-28 23:31:51 +0100 |
commit | 21cd4ff05bb46b375a9ad38c9f0b7f8e71a5d979 (patch) | |
tree | b9679cc1d2c7c3cab0f88c370015f34f6d0b27ca /player | |
parent | d1d6257731866934717353fce484f5f472f845d1 (diff) | |
parent | 1f436f65f2ee4df6419ca68bd6426b8283db6d22 (diff) | |
download | mpv-21cd4ff05bb46b375a9ad38c9f0b7f8e71a5d979.tar.bz2 mpv-21cd4ff05bb46b375a9ad38c9f0b7f8e71a5d979.tar.xz |
Merge branch 'master' into release/current
Diffstat (limited to 'player')
-rw-r--r-- | player/audio.c | 463 | ||||
-rw-r--r-- | player/client.c | 6 | ||||
-rw-r--r-- | player/command.c | 170 | ||||
-rw-r--r-- | player/core.h | 88 | ||||
-rw-r--r-- | player/lavfi.c | 740 | ||||
-rw-r--r-- | player/lavfi.h | 32 | ||||
-rw-r--r-- | player/loadfile.c | 510 | ||||
-rw-r--r-- | player/lua.c | 14 | ||||
-rw-r--r-- | player/lua/osc.lua | 82 | ||||
-rw-r--r-- | player/main.c | 5 | ||||
-rw-r--r-- | player/misc.c | 51 | ||||
-rw-r--r-- | player/osd.c | 24 | ||||
-rw-r--r-- | player/playloop.c | 265 | ||||
-rw-r--r-- | player/screenshot.c | 14 | ||||
-rw-r--r-- | player/screenshot.h | 14 | ||||
-rw-r--r-- | player/scripting.c | 14 | ||||
-rw-r--r-- | player/sub.c | 21 | ||||
-rw-r--r-- | player/video.c | 220 |
18 files changed, 1913 insertions, 820 deletions
diff --git a/player/audio.c b/player/audio.c index a7a5f727c7..f17587a1ca 100644 --- a/player/audio.c +++ b/player/audio.c @@ -43,6 +43,15 @@ #include "core.h" #include "command.h" +enum { + AD_OK = 0, + AD_ERR = -1, + AD_EOF = -2, + AD_NEW_FMT = -3, + AD_WAIT = -4, + AD_NO_PROGRESS = -5, +}; + // Use pitch correction only for speed adjustments by the user, not minor sync // correction ones. static int get_speed_method(struct MPContext *mpctx) @@ -55,7 +64,7 @@ static int get_speed_method(struct MPContext *mpctx) // return true; if filter recreation is needed, return false. static bool update_speed_filters(struct MPContext *mpctx) { - struct af_stream *afs = mpctx->d_audio->afilter; + struct af_stream *afs = mpctx->ao_chain->af; double speed = mpctx->audio_speed; if (afs->initialized < 1) @@ -81,7 +90,7 @@ static bool update_speed_filters(struct MPContext *mpctx) // Update speed, and insert/remove filters if necessary. static void recreate_speed_filters(struct MPContext *mpctx) { - struct af_stream *afs = mpctx->d_audio->afilter; + struct af_stream *afs = mpctx->ao_chain->af; if (update_speed_filters(mpctx)) return; @@ -113,9 +122,9 @@ fail: static int recreate_audio_filters(struct MPContext *mpctx) { - assert(mpctx->d_audio); + assert(mpctx->ao_chain); - struct af_stream *afs = mpctx->d_audio->afilter; + struct af_stream *afs = mpctx->ao_chain->af; if (afs->initialized < 1 && af_init(afs) < 0) goto fail; @@ -134,12 +143,27 @@ fail: int reinit_audio_filters(struct MPContext *mpctx) { - struct dec_audio *d_audio = mpctx->d_audio; - if (!d_audio) + struct ao_chain *ao_c = mpctx->ao_chain; + if (!ao_c) return 0; - af_uninit(mpctx->d_audio->afilter); - return recreate_audio_filters(mpctx) < 0 ? -1 : 1; + double delay = 0; + if (ao_c->af->initialized > 0) + delay = af_calc_delay(ao_c->af); + + af_uninit(ao_c->af); + if (recreate_audio_filters(mpctx) < 0) + return -1; + + // Only force refresh if the amount of dropped buffered data is going to + // cause "issues" for the A/V sync logic. + if (mpctx->audio_status == STATUS_PLAYING && + mpctx->playback_pts != MP_NOPTS_VALUE && delay > 0.2) + { + queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->playback_pts, + MPSEEK_EXACT, true); + } + return 1; } // Call this if opts->playback_speed or mpctx->speed_factor_* change. @@ -148,20 +172,31 @@ void update_playback_speed(struct MPContext *mpctx) mpctx->audio_speed = mpctx->opts->playback_speed * mpctx->speed_factor_a; mpctx->video_speed = mpctx->opts->playback_speed * mpctx->speed_factor_v; - if (!mpctx->d_audio || mpctx->d_audio->afilter->initialized < 1) + if (!mpctx->ao_chain || mpctx->ao_chain->af->initialized < 1) return; if (!update_speed_filters(mpctx)) recreate_audio_filters(mpctx); } +static void ao_chain_reset_state(struct ao_chain *ao_c) +{ + ao_c->pts = MP_NOPTS_VALUE; + ao_c->pts_reset = false; + talloc_free(ao_c->input_frame); + ao_c->input_frame = NULL; + af_seek_reset(ao_c->af); + mp_audio_buffer_clear(ao_c->ao_buffer); + + if (ao_c->audio_src) + audio_reset_decoding(ao_c->audio_src); +} + void reset_audio_state(struct MPContext *mpctx) { - if (mpctx->d_audio) - audio_reset_decoding(mpctx->d_audio); - if (mpctx->ao_buffer) - mp_audio_buffer_clear(mpctx->ao_buffer); - mpctx->audio_status = mpctx->d_audio ? STATUS_SYNCING : STATUS_EOF; + if (mpctx->ao_chain) + ao_chain_reset_state(mpctx->ao_chain); + mpctx->audio_status = mpctx->ao_chain ? STATUS_SYNCING : STATUS_EOF; mpctx->delay = 0; mpctx->audio_drop_throttle = 0; mpctx->audio_stat_start = 0; @@ -183,57 +218,51 @@ void uninit_audio_out(struct MPContext *mpctx) mpctx->ao_decoder_fmt = NULL; } +static void ao_chain_uninit(struct ao_chain *ao_c) +{ + struct track *track = ao_c->track; + if (track) { + assert(track->ao_c == ao_c); + track->ao_c = NULL; + assert(track->d_audio == ao_c->audio_src); + track->d_audio = NULL; + audio_uninit(ao_c->audio_src); + } + + if (ao_c->filter_src) + lavfi_set_connected(ao_c->filter_src, false); + + af_destroy(ao_c->af); + talloc_free(ao_c->input_frame); + talloc_free(ao_c->ao_buffer); + talloc_free(ao_c); +} + void uninit_audio_chain(struct MPContext *mpctx) { - if (mpctx->d_audio) { + if (mpctx->ao_chain) { mixer_uninit_audio(mpctx->mixer); - audio_uninit(mpctx->d_audio); - mpctx->d_audio = NULL; - talloc_free(mpctx->ao_buffer); - mpctx->ao_buffer = NULL; + ao_chain_uninit(mpctx->ao_chain); + mpctx->ao_chain = NULL; + mpctx->audio_status = STATUS_EOF; - reselect_demux_streams(mpctx); mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL); } } -void reinit_audio_chain(struct MPContext *mpctx) +static void reinit_audio_filters_and_output(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; - struct track *track = mpctx->current_track[0][STREAM_AUDIO]; - struct sh_stream *sh = track ? track->stream : NULL; - if (!sh) { - uninit_audio_out(mpctx); - goto no_audio; - } + struct ao_chain *ao_c = mpctx->ao_chain; + assert(ao_c); + struct track *track = ao_c->track; + struct af_stream *afs = ao_c->af; - mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL); - - if (!mpctx->d_audio) { - mpctx->d_audio = talloc_zero(NULL, struct dec_audio); - mpctx->d_audio->log = mp_log_new(mpctx->d_audio, mpctx->log, "!ad"); - mpctx->d_audio->global = mpctx->global; - mpctx->d_audio->opts = opts; - mpctx->d_audio->header = sh; - mpctx->d_audio->pool = mp_audio_pool_create(mpctx->d_audio); - mpctx->d_audio->afilter = af_new(mpctx->global); - mpctx->d_audio->afilter->replaygain_data = sh->codec->replaygain_data; - mpctx->d_audio->spdif_passthrough = true; - mpctx->ao_buffer = mp_audio_buffer_create(NULL); - if (!audio_init_best_codec(mpctx->d_audio)) - goto init_error; - reset_audio_state(mpctx); - - if (mpctx->ao) { - struct mp_audio fmt; - ao_get_format(mpctx->ao, &fmt); - mp_audio_buffer_reinit(mpctx->ao_buffer, &fmt); - } - } - assert(mpctx->d_audio); + if (ao_c->input_frame) + mp_audio_copy_config(&ao_c->input_format, ao_c->input_frame); - struct mp_audio in_format = mpctx->d_audio->decode_format; + struct mp_audio in_format = ao_c->input_format; if (!mp_audio_config_valid(&in_format)) { // We don't know the audio format yet - so configure it later as we're @@ -249,7 +278,8 @@ void reinit_audio_chain(struct MPContext *mpctx) uninit_audio_out(mpctx); } - struct af_stream *afs = mpctx->d_audio->afilter; + if (mpctx->ao && mp_audio_config_equals(&in_format, &afs->input)) + return; afs->output = (struct mp_audio){0}; if (mpctx->ao) { @@ -273,7 +303,7 @@ void reinit_audio_chain(struct MPContext *mpctx) if (!mpctx->ao) { bool spdif_fallback = af_fmt_is_spdif(afs->output.format) && - mpctx->d_audio->spdif_passthrough; + ao_c->spdif_passthrough; bool ao_null_fallback = opts->ao_null_fallback && !spdif_fallback; mp_chmap_remove_useless_channels(&afs->output.channels, @@ -283,6 +313,7 @@ void reinit_audio_chain(struct MPContext *mpctx) mpctx->ao = ao_init_best(mpctx->global, ao_null_fallback, mpctx->input, mpctx->encode_lavc_ctx, afs->output.rate, afs->output.format, afs->output.channels); + ao_c->ao = mpctx->ao; struct mp_audio fmt = {0}; if (mpctx->ao) @@ -294,18 +325,22 @@ void reinit_audio_chain(struct MPContext *mpctx) MP_ERR(mpctx, "Passthrough format unsupported.\n"); ao_uninit(mpctx->ao); mpctx->ao = NULL; + ao_c->ao = NULL; } } if (!mpctx->ao) { // If spdif was used, try to fallback to PCM. - if (spdif_fallback) { - mpctx->d_audio->spdif_passthrough = false; - mpctx->d_audio->spdif_failed = true; - if (!audio_init_best_codec(mpctx->d_audio)) + if (spdif_fallback && ao_c->audio_src) { + MP_VERBOSE(mpctx, "Falling back to PCM output.\n"); + ao_c->spdif_passthrough = false; + ao_c->spdif_failed = true; + ao_c->audio_src->try_spdif = false; + if (!audio_init_best_codec(ao_c->audio_src)) goto init_error; reset_audio_state(mpctx); - reinit_audio_chain(mpctx); + ao_c->input_format = (struct mp_audio){0}; + mpctx->sleeptime = 0; // reinit with new format next time return; } @@ -314,7 +349,7 @@ void reinit_audio_chain(struct MPContext *mpctx) goto init_error; } - mp_audio_buffer_reinit(mpctx->ao_buffer, &fmt); + mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt); afs->output = fmt; if (!mp_audio_config_equals(&afs->output, &afs->filter_output)) afs->initialized = 0; @@ -338,48 +373,125 @@ void reinit_audio_chain(struct MPContext *mpctx) init_error: uninit_audio_chain(mpctx); uninit_audio_out(mpctx); + error_on_track(mpctx, track); +} + +int init_audio_decoder(struct MPContext *mpctx, struct track *track) +{ + assert(!track->d_audio); + if (!track->stream) + goto init_error; + + track->d_audio = talloc_zero(NULL, struct dec_audio); + struct dec_audio *d_audio = track->d_audio; + d_audio->log = mp_log_new(d_audio, mpctx->log, "!ad"); + d_audio->global = mpctx->global; + d_audio->opts = mpctx->opts; + d_audio->header = track->stream; + d_audio->codec = track->stream->codec; + + d_audio->try_spdif = true; + + if (!audio_init_best_codec(d_audio)) + goto init_error; + + return 1; + +init_error: + if (track->sink) + lavfi_set_connected(track->sink, false); + track->sink = NULL; + audio_uninit(track->d_audio); + track->d_audio = NULL; + error_on_track(mpctx, track); + return 0; +} + +void reinit_audio_chain(struct MPContext *mpctx) +{ + reinit_audio_chain_src(mpctx, NULL); +} + +void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src) +{ + struct track *track = NULL; + struct sh_stream *sh = NULL; + if (!src) { + track = mpctx->current_track[0][STREAM_AUDIO]; + if (!track) + return; + sh = track->stream; + if (!sh) { + uninit_audio_out(mpctx); + goto no_audio; + } + } + assert(!mpctx->ao_chain); + + mp_notify(mpctx, MPV_EVENT_AUDIO_RECONFIG, NULL); + + struct ao_chain *ao_c = talloc_zero(NULL, struct ao_chain); + mpctx->ao_chain = ao_c; + ao_c->log = mpctx->log; + ao_c->af = af_new(mpctx->global); + if (sh) + ao_c->af->replaygain_data = sh->codec->replaygain_data; + ao_c->spdif_passthrough = true; + ao_c->pts = MP_NOPTS_VALUE; + ao_c->ao_buffer = mp_audio_buffer_create(NULL); + ao_c->ao = mpctx->ao; + + ao_c->filter_src = src; + if (!ao_c->filter_src) { + ao_c->track = track; + track->ao_c = ao_c; + if (!init_audio_decoder(mpctx, track)) + goto init_error; + ao_c->audio_src = track->d_audio; + } + + reset_audio_state(mpctx); + + if (mpctx->ao) { + struct mp_audio fmt; + ao_get_format(mpctx->ao, &fmt); + mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt); + } + + mpctx->sleeptime = 0; + return; + +init_error: + uninit_audio_chain(mpctx); + uninit_audio_out(mpctx); no_audio: - if (track) - error_on_track(mpctx, track); + error_on_track(mpctx, track); } // Return pts value corresponding to the end point of audio written to the // ao so far. double written_audio_pts(struct MPContext *mpctx) { - struct dec_audio *d_audio = mpctx->d_audio; - if (!d_audio) + struct ao_chain *ao_c = mpctx->ao_chain; + if (!ao_c) return MP_NOPTS_VALUE; - struct mp_audio in_format = d_audio->decode_format; + struct mp_audio in_format = ao_c->input_format; - if (!mp_audio_config_valid(&in_format) || d_audio->afilter->initialized < 1) + if (!mp_audio_config_valid(&in_format) || ao_c->af->initialized < 1) return MP_NOPTS_VALUE; // first calculate the end pts of audio that has been output by decoder - double a_pts = d_audio->pts; + double a_pts = ao_c->pts; if (a_pts == MP_NOPTS_VALUE) return MP_NOPTS_VALUE; - // d_audio->pts is the timestamp of the first sample of the latest frame - // the with a known pts that the decoder has returned. d_audio->pts_offset - // is the amount of samples the decoder has returned after that timestamp - // (includes the frame size). - a_pts += d_audio->pts_offset / (double)in_format.rate; - - // Now a_pts hopefully holds the pts for end of audio from decoder. - // Subtract data in buffers between decoder and audio out. - - // Decoded but not filtered - if (d_audio->waiting) - a_pts -= d_audio->waiting->samples / (double)in_format.rate; - // Data buffered in audio filters, measured in seconds of "missing" output - double buffered_output = af_calc_delay(d_audio->afilter); + double buffered_output = af_calc_delay(ao_c->af); // Data that was ready for ao but was buffered because ao didn't fully // accept everything to internal buffers yet - buffered_output += mp_audio_buffer_seconds(mpctx->ao_buffer); + buffered_output += mp_audio_buffer_seconds(ao_c->ao_buffer); // Filters divide audio length by audio_speed, so multiply by it // to get the length in original units without speedup or slowdown @@ -465,18 +577,19 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip) } double written_pts = written_audio_pts(mpctx); - if (written_pts == MP_NOPTS_VALUE && !mp_audio_buffer_samples(mpctx->ao_buffer)) + if (written_pts == MP_NOPTS_VALUE && + !mp_audio_buffer_samples(mpctx->ao_chain->ao_buffer)) return false; // no audio read yet - bool sync_to_video = mpctx->vo_chain && mpctx->sync_audio_to_video && + bool sync_to_video = mpctx->vo_chain && !mpctx->vo_chain->is_coverart && mpctx->video_status != STATUS_EOF; double sync_pts = MP_NOPTS_VALUE; if (sync_to_video) { if (mpctx->video_status < STATUS_READY) return false; // wait until we know a video PTS - if (mpctx->video_next_pts != MP_NOPTS_VALUE) - sync_pts = mpctx->video_next_pts - opts->audio_delay; + if (mpctx->video_pts != MP_NOPTS_VALUE) + sync_pts = mpctx->video_pts - opts->audio_delay; } else if (mpctx->hrseek_active) { sync_pts = mpctx->hrseek_pts; } @@ -499,23 +612,125 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip) return true; } -void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) + +static bool copy_output(struct af_stream *afs, struct mp_audio_buffer *outbuf, + int minsamples, bool eof) +{ + while (mp_audio_buffer_samples(outbuf) < minsamples) { + if (af_output_frame(afs, eof) < 0) + return true; // error, stop doing stuff + struct mp_audio *mpa = af_read_output_frame(afs); + if (!mpa) + return false; // out of data + mp_audio_buffer_append(outbuf, mpa); + talloc_free(mpa); + } + return true; +} + +static int decode_new_frame(struct ao_chain *ao_c) +{ + if (ao_c->input_frame) + return AD_OK; + + int res = DATA_EOF; + if (ao_c->filter_src) { + res = lavfi_request_frame_a(ao_c->filter_src, &ao_c->input_frame); + } else if (ao_c->audio_src) { + audio_work(ao_c->audio_src); + res = audio_get_frame(ao_c->audio_src, &ao_c->input_frame); + } + + switch (res) { + case DATA_OK: return AD_OK; + case DATA_WAIT: return AD_WAIT; + case DATA_AGAIN: return AD_NO_PROGRESS; + case DATA_EOF: return AD_EOF; + default: abort(); + } +} + +/* Try to get at least minsamples decoded+filtered samples in outbuf + * (total length including possible existing data). + * Return 0 on success, or negative AD_* error code. + * In the former case outbuf has at least minsamples buffered on return. + * In case of EOF/error it might or might not be. */ +static int filter_audio(struct ao_chain *ao_c, struct mp_audio_buffer *outbuf, + int minsamples) +{ + struct af_stream *afs = ao_c->af; + if (afs->initialized < 1) + return AD_ERR; + + MP_STATS(ao_c, "start audio"); + + int res; + while (1) { + res = 0; + + if (copy_output(afs, outbuf, minsamples, false)) + break; + + res = decode_new_frame(ao_c); + if (res == AD_NO_PROGRESS) + break; + if (res < 0) { + // drain filters first (especially for true EOF case) + copy_output(afs, outbuf, minsamples, true); + break; + } + + // On format change, make sure to drain the filter chain. + if (!mp_audio_config_equals(&afs->input, ao_c->input_frame)) { + copy_output(afs, outbuf, minsamples, true); + res = AD_NEW_FMT; + break; + } + + struct mp_audio *mpa = ao_c->input_frame; + ao_c->input_frame = NULL; + if (mpa->pts == MP_NOPTS_VALUE) { + ao_c->pts = MP_NOPTS_VALUE; + } else { + // Attempt to detect jumps in PTS. Even for the lowest sample rates + // and with worst container rounded timestamp, this should be a + // margin more than enough. + double desync = fabs(mpa->pts - ao_c->pts); + if (ao_c->pts != MP_NOPTS_VALUE && desync > 0.1) { + MP_WARN(ao_c, "Invalid audio PTS: %f -> %f\n", + ao_c->pts, mpa->pts); + if (desync >= 5) + ao_c->pts_reset = true; + } + ao_c->pts = mpa->pts + mpa->samples / (double)mpa->rate; + } + if (af_filter_frame(afs, mpa) < 0) + return AD_ERR; + } + + MP_STATS(ao_c, "end audio"); + + return res; +} + +void fill_audio_out_buffers(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; - struct dec_audio *d_audio = mpctx->d_audio; + struct ao_chain *ao_c = mpctx->ao_chain; dump_audio_stats(mpctx); if (mpctx->ao && ao_query_and_reset_events(mpctx->ao, AO_EVENT_RELOAD)) { ao_reset(mpctx->ao); uninit_audio_out(mpctx); - if (d_audio) { - if (mpctx->d_audio->spdif_failed) { - mpctx->d_audio->spdif_failed = false; - mpctx->d_audio->spdif_passthrough = true; - if (!audio_init_best_codec(mpctx->d_audio)) { + if (ao_c) { + struct dec_audio *d_audio = ao_c->audio_src; + if (d_audio && ao_c->spdif_failed) { + ao_c->spdif_failed = false; + d_audio->try_spdif = true; + if (!audio_init_best_codec(d_audio)) { MP_ERR(mpctx, "Error reinitializing audio.\n"); - error_on_track(mpctx, mpctx->current_track[0][STREAM_AUDIO]); + error_on_track(mpctx, ao_c->track); return; } } @@ -523,29 +738,25 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } } - if (!d_audio) + if (!ao_c) return; - if (d_audio->afilter->initialized < 1 || !mpctx->ao) { + if (ao_c->af->initialized < 1 || !mpctx->ao) { // Probe the initial audio format. Returns AD_OK (and does nothing) if // the format is already known. - int r = initial_audio_decode(mpctx->d_audio); + int r = decode_new_frame(mpctx->ao_chain); if (r == AD_WAIT) return; // continue later when new data is available - if (r != AD_OK) { - mpctx->d_audio->init_retries += 1; - if (mpctx->d_audio->init_retries >= 50) { - MP_ERR(mpctx, "Error initializing audio.\n"); - error_on_track(mpctx, mpctx->current_track[0][STREAM_AUDIO]); - return; - } + if (r == AD_EOF) { + mpctx->audio_status = STATUS_EOF; + return; } - reinit_audio_chain(mpctx); + reinit_audio_filters_and_output(mpctx); mpctx->sleeptime = 0; return; // try again next iteration } - if (mpctx->vo_chain && d_audio->pts_reset) { + if (mpctx->vo_chain && ao_c->pts_reset) { MP_VERBOSE(mpctx, "Reset playback due to audio timestamp reset.\n"); reset_playback_state(mpctx); mpctx->sleeptime = 0; @@ -594,10 +805,14 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) int status = AD_OK; bool working = false; - if (playsize > mp_audio_buffer_samples(mpctx->ao_buffer)) { - status = audio_decode(d_audio, mpctx->ao_buffer, playsize); + if (playsize > mp_audio_buffer_samples(ao_c->ao_buffer)) { + status = filter_audio(mpctx->ao_chain, ao_c->ao_buffer, playsize); if (status == AD_WAIT) return; + if (status == AD_NO_PROGRESS) { + mpctx->sleeptime = 0; + return; + } if (status == AD_NEW_FMT) { /* The format change isn't handled too gracefully. A more precise * implementation would require draining buffered old-format audio @@ -605,7 +820,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) */ if (mpctx->opts->gapless_audio < 1) uninit_audio_out(mpctx); - reinit_audio_chain(mpctx); + reinit_audio_filters_and_output(mpctx); mpctx->sleeptime = 0; return; // retry on next iteration } @@ -624,10 +839,11 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) bool end_sync = false; if (skip >= 0) { - int max = mp_audio_buffer_samples(mpctx->ao_buffer); - mp_audio_buffer_skip(mpctx->ao_buffer, MPMIN(skip, max)); + int max = mp_audio_buffer_samples(ao_c->ao_buffer); + mp_audio_buffer_skip(ao_c->ao_buffer, MPMIN(skip, max)); // If something is left, we definitely reached the target time. end_sync |= sync_known && skip < max; + working |= skip > 0; } else if (skip < 0) { if (-skip > playsize) { // heuristic against making the buffer too large ao_reset(mpctx->ao); // some AOs repeat data on underflow @@ -635,20 +851,20 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) mpctx->delay = 0; return; } - mp_audio_buffer_prepend_silence(mpctx->ao_buffer, -skip); + mp_audio_buffer_prepend_silence(ao_c->ao_buffer, -skip); end_sync = true; } if (skip_duplicate) { - int max = mp_audio_buffer_samples(mpctx->ao_buffer); + int max = mp_audio_buffer_samples(ao_c->ao_buffer); if (abs(skip_duplicate) > max) skip_duplicate = skip_duplicate >= 0 ? max : -max; mpctx->last_av_difference += skip_duplicate / play_samplerate; if (skip_duplicate >= 0) { - mp_audio_buffer_skip(mpctx->ao_buffer, skip_duplicate); + mp_audio_buffer_skip(ao_c->ao_buffer, skip_duplicate); MP_STATS(mpctx, "drop-audio"); } else { - mp_audio_buffer_duplicate(mpctx->ao_buffer, -skip_duplicate); + mp_audio_buffer_duplicate(ao_c->ao_buffer, -skip_duplicate); MP_STATS(mpctx, "duplicate-audio"); } MP_VERBOSE(mpctx, "audio skip_duplicate=%d\n", skip_duplicate); @@ -657,7 +873,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) if (mpctx->audio_status == STATUS_SYNCING) { if (end_sync) mpctx->audio_status = STATUS_FILLING; - if (status != AD_OK && !mp_audio_buffer_samples(mpctx->ao_buffer)) + if (status != AD_OK && !mp_audio_buffer_samples(ao_c->ao_buffer)) mpctx->audio_status = STATUS_EOF; if (working || end_sync) mpctx->sleeptime = 0; @@ -668,8 +884,8 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) // Even if we're done decoding and syncing, let video start first - this is // required, because sending audio to the AO already starts playback. - if (mpctx->audio_status == STATUS_FILLING && mpctx->sync_audio_to_video && - mpctx->video_status <= STATUS_READY) + if (mpctx->audio_status == STATUS_FILLING && mpctx->vo_chain && + !mpctx->vo_chain->is_coverart && mpctx->video_status <= STATUS_READY) { mpctx->audio_status = STATUS_READY; return; @@ -679,6 +895,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) bool partial_fill = false; int playflags = 0; + double endpts = get_play_end_pts(mpctx); if (endpts != MP_NOPTS_VALUE) { double samples = (endpts - written_audio_pts(mpctx) - opts->audio_delay) * play_samplerate; @@ -689,8 +906,8 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) } } - if (playsize > mp_audio_buffer_samples(mpctx->ao_buffer)) { - playsize = mp_audio_buffer_samples(mpctx->ao_buffer); + if (playsize > mp_audio_buffer_samples(ao_c->ao_buffer)) { + playsize = mp_audio_buffer_samples(ao_c->ao_buffer); partial_fill = true; } @@ -702,13 +919,13 @@ void fill_audio_out_buffers(struct MPContext *mpctx, double endpts) playflags |= AOPLAY_FINAL_CHUNK; struct mp_audio data; - mp_audio_buffer_peek(mpctx->ao_buffer, &data); + mp_audio_buffer_peek(ao_c->ao_buffer, &data); if (audio_eof || data.samples >= align) data.samples = data.samples / align * align; data.samples = MPMIN(data.samples, mpctx->paused ? 0 : playsize); int played = write_to_ao(mpctx, &data, playflags); assert(played >= 0 && played <= data.samples); - mp_audio_buffer_skip(mpctx->ao_buffer, played); + mp_audio_buffer_skip(ao_c->ao_buffer, played); mpctx->audio_drop_throttle = MPMAX(0, mpctx->audio_drop_throttle - played / play_samplerate); @@ -730,6 +947,4 @@ void clear_audio_output_buffers(struct MPContext *mpctx) { if (mpctx->ao) ao_reset(mpctx->ao); - if (mpctx->ao_buffer) - mp_audio_buffer_clear(mpctx->ao_buffer); } diff --git a/player/client.c b/player/client.c index 3abc8d8086..d3b0567a97 100644 --- a/player/client.c +++ b/player/client.c @@ -458,7 +458,7 @@ void mpv_terminate_destroy(mpv_handle *ctx) static bool check_locale(void) { char *name = setlocale(LC_NUMERIC, NULL); - return strcmp(name, "C") == 0; + return !name || strcmp(name, "C") == 0; } mpv_handle *mpv_create(void) @@ -833,8 +833,10 @@ static bool conv_node_to_format(void *dst, mpv_format dst_fmt, mpv_node *src) return true; } if (dst_fmt == MPV_FORMAT_INT64 && src->format == MPV_FORMAT_DOUBLE) { - if (src->u.double_ >= INT64_MIN && src->u.double_ <= INT64_MAX) + if (src->u.double_ >= INT64_MIN && src->u.double_ <= INT64_MAX) { *(int64_t *)dst = src->u.double_; + return true; + } } return false; } diff --git a/player/command.c b/player/command.c index 3c7cfb282d..642330e34f 100644 --- a/player/command.c +++ b/player/command.c @@ -350,7 +350,7 @@ static int mp_property_stream_open_filename(void *ctx, struct m_property *prop, return M_PROPERTY_UNAVAILABLE; switch (action) { case M_PROPERTY_SET: { - if (mpctx->stream) + if (mpctx->demuxer) return M_PROPERTY_ERROR; mpctx->stream_open_filename = talloc_strdup(mpctx->stream_open_filename, *(char **)arg); @@ -390,14 +390,14 @@ static int mp_property_media_title(void *ctx, struct m_property *prop, name = mpctx->opts->media_title; if (name && name[0]) return m_property_strdup_ro(action, arg, name); - if (mpctx->master_demuxer) { - name = mp_tags_get_str(mpctx->master_demuxer->metadata, "service_name"); + if (mpctx->demuxer) { + name = mp_tags_get_str(mpctx->demuxer->metadata, "service_name"); if (name && name[0]) return m_property_strdup_ro(action, arg, name); - name = mp_tags_get_str(mpctx->master_demuxer->metadata, "title"); + name = mp_tags_get_str(mpctx->demuxer->metadata, "title"); if (name && name[0]) return m_property_strdup_ro(action, arg, name); - name = mp_tags_get_str(mpctx->master_demuxer->metadata, "icy-title"); + name = mp_tags_get_str(mpctx->demuxer->metadata, "icy-title"); if (name && name[0]) return m_property_strdup_ro(action, arg, name); } @@ -439,7 +439,7 @@ static int mp_property_demuxer(void *ctx, struct m_property *prop, int action, void *arg) { MPContext *mpctx = ctx; - struct demuxer *demuxer = mpctx->master_demuxer; + struct demuxer *demuxer = mpctx->demuxer; |