diff options
-rw-r--r-- | DOCS/man/en/mplayer.1 | 11 | ||||
-rw-r--r-- | cfg-mplayer.h | 1 | ||||
-rw-r--r-- | defaultopts.c | 1 | ||||
-rw-r--r-- | libmpcodecs/dec_audio.c | 27 | ||||
-rw-r--r-- | libmpcodecs/dec_audio.h | 1 | ||||
-rw-r--r-- | mp_core.h | 4 | ||||
-rw-r--r-- | mplayer.c | 103 | ||||
-rw-r--r-- | options.h | 1 |
8 files changed, 130 insertions, 19 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index 708fd10199..4f26e0e173 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -1036,6 +1036,17 @@ in a playlist or intend to read from stdin later on via the loadfile or loadlist slave commands. . .TP +.B \-noinitial-audio-sync +When starting a video file or after events such as seeking MPlayer will by +default modify the audio stream to make it start from the same timestamp as +video, by either inserting silence at the start or cutting away the first +samples. +This option disables that functionality and makes the player behave like +older MPlayer versions did: video and audio are both started immediately +even if their start timestamps differ, and then video timing is gradually +adjusted if necessary to reach correct synchronization later. +. +.TP .B \-nojoystick Turns off joystick support. . diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 95477edb33..21733912d5 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -309,6 +309,7 @@ const m_option_t mplayer_opts[]={ // a-v sync stuff: OPT_MAKE_FLAGS("correct-pts", user_correct_pts, 0), OPT_INTRANGE("pts-association-mode", user_pts_assoc_mode, 0, 0, 2), + OPT_MAKE_FLAGS("initial-audio-sync", initial_audio_sync, 0), {"noautosync", &autosync, CONF_TYPE_FLAG, 0, 0, -1, NULL}, {"autosync", &autosync, CONF_TYPE_INT, CONF_RANGE, 0, 10000, NULL}, diff --git a/defaultopts.c b/defaultopts.c index 1314e21f28..5b4e8f762f 100644 --- a/defaultopts.c +++ b/defaultopts.c @@ -28,6 +28,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .chapterrange = {-1, -1}, .edition_id = -1, .user_correct_pts = -1, + .initial_audio_sync = 1, .key_fifo_size = 7, .doubleclick_time = 300, .audio_id = -1, diff --git a/libmpcodecs/dec_audio.c b/libmpcodecs/dec_audio.c index 59abe398fb..7bbbdeb058 100644 --- a/libmpcodecs/dec_audio.c +++ b/libmpcodecs/dec_audio.c @@ -369,6 +369,16 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate, return 1; } +static void set_min_out_buffer_size(struct sh_audio *sh, int len) +{ + if (sh->a_out_buffer_size < len) { + mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size " + "from %d to %d\n", sh->a_out_buffer_size, len); + sh->a_out_buffer = realloc(sh->a_out_buffer, len); + sh->a_out_buffer_size = len; + } +} + static int filter_n_bytes(sh_audio_t *sh, int len) { assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size); @@ -408,13 +418,7 @@ static int filter_n_bytes(sh_audio_t *sh, int len) af_data_t *filter_output = af_play(sh->afilter, &filter_input); if (!filter_output) return -1; - if (sh->a_out_buffer_size < sh->a_out_buffer_len + filter_output->len) { - int newlen = sh->a_out_buffer_len + filter_output->len; - mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size " - "from %d to %d\n", sh->a_out_buffer_size, newlen); - sh->a_out_buffer = realloc(sh->a_out_buffer, newlen); - sh->a_out_buffer_size = newlen; - } + set_min_out_buffer_size(sh, sh->a_out_buffer_len + filter_output->len); memcpy(sh->a_out_buffer + sh->a_out_buffer_len, filter_output->audio, filter_output->len); sh->a_out_buffer_len += filter_output->len; @@ -479,6 +483,15 @@ int decode_audio(sh_audio_t *sh_audio, int minlen) return 0; } +void decode_audio_prepend_bytes(struct sh_audio *sh, int count, int byte) +{ + set_min_out_buffer_size(sh, sh->a_out_buffer_len + count); + memmove(sh->a_out_buffer + count, sh->a_out_buffer, sh->a_out_buffer_len); + memset(sh->a_out_buffer, byte, count); + sh->a_out_buffer_len += count; +} + + void resync_audio_stream(sh_audio_t *sh_audio) { sh_audio->a_in_buffer_len = 0; // clear audio input buffer diff --git a/libmpcodecs/dec_audio.h b/libmpcodecs/dec_audio.h index 3ec2cef8bf..c2b92c9818 100644 --- a/libmpcodecs/dec_audio.h +++ b/libmpcodecs/dec_audio.h @@ -25,6 +25,7 @@ void afm_help(void); int init_best_audio_codec(sh_audio_t *sh_audio, char** audio_codec_list, char** audio_fm_list); int decode_audio(sh_audio_t *sh_audio, int minlen); +void decode_audio_prepend_bytes(struct sh_audio *sh, int count, int byte); void resync_audio_stream(sh_audio_t *sh_audio); void skip_audio_frame(sh_audio_t *sh_audio); void uninit_audio(sh_audio_t *sh_audio); @@ -125,6 +125,10 @@ typedef struct MPContext { /* We're starting playback from scratch or after a seek. Show first * video frame immediately and reinitialize sync. */ bool restart_playback; + /* After playback restart (above) or audio stream change, adjust audio + * stream by cutting samples or adding silence at the beginning to make + * audio playback position match video position. */ + bool syncing_audio; // AV sync: the next frame should be shown when the audio out has this // much (in seconds) buffered data left. Increased when more data is // written to the ao, decreased when moving to the next frame. @@ -22,6 +22,8 @@ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> +#include <math.h> + #include "config.h" #include "talloc.h" @@ -1790,6 +1792,7 @@ void reinit_audio_chain(struct MPContext *mpctx) } mpctx->mixer.audio_out = mpctx->audio_out; mpctx->mixer.volstep = volstep; + mpctx->syncing_audio = true; return; init_error: @@ -2112,7 +2115,7 @@ static void adjust_sync(struct MPContext *mpctx, double frame_time) { current_module = "av_sync"; - if (!mpctx->sh_audio) + if (!mpctx->sh_audio || mpctx->syncing_audio) return; double a_pts = written_audio_pts(mpctx) - mpctx->delay; @@ -2133,6 +2136,67 @@ static void adjust_sync(struct MPContext *mpctx, double frame_time) mpctx->total_avsync_change += change; } +#define ASYNC_PLAY_DONE -3 +static int audio_start_sync(struct MPContext *mpctx, int playsize) +{ + struct MPOpts *opts = &mpctx->opts; + sh_audio_t * const sh_audio = mpctx->sh_audio; + int res; + + // Timing info may not be set without + res = decode_audio(sh_audio, 1); + if (res < 0) + return res; + double ptsdiff = written_audio_pts(mpctx) - mpctx->sh_video->pts - + mpctx->delay - audio_delay; + int bytes = ptsdiff * ao_data.bps / mpctx->opts.playback_speed; + bytes -= bytes % (ao_data.channels * af_fmt2bits(ao_data.format) / 8); + + if (fabs(ptsdiff) > 300) // pts reset or just broken? + bytes = 0; + + if (bytes <= 0) { + mpctx->syncing_audio = false; + while (1) { + int a = FFMIN(-bytes, FFMAX(playsize, 20000)); + int res = decode_audio(sh_audio, a); + bytes += sh_audio->a_out_buffer_len; + if (bytes >= 0) { + memmove(sh_audio->a_out_buffer, + sh_audio->a_out_buffer + + sh_audio->a_out_buffer_len - bytes, + bytes); + sh_audio->a_out_buffer_len = bytes; + if (res < 0) + return res; + return decode_audio(sh_audio, playsize); + } + sh_audio->a_out_buffer_len = 0; + if (res < 0) + return res; + } + } else { + int fillbyte = 0; + if ((ao_data.format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) + fillbyte = 0x80; + if (bytes >= playsize) { + /* This case could fall back to the one below with + * bytes = playsize, but then silence would keep accumulating + * in a_out_buffer if the AO accepts less data than it asks for + * in playsize. */ + char *p = malloc(playsize); + memset(p, fillbyte, playsize); + playsize = mpctx->audio_out->play(p, playsize, 0); + free(p); + mpctx->delay += opts->playback_speed*playsize/(double)ao_data.bps; + return ASYNC_PLAY_DONE; + } + mpctx->syncing_audio = false; + decode_audio_prepend_bytes(sh_audio, bytes, fillbyte); + return decode_audio(sh_audio, playsize); + } +} + static int fill_audio_out_buffers(struct MPContext *mpctx) { struct MPOpts *opts = &mpctx->opts; @@ -2167,10 +2231,20 @@ static int fill_audio_out_buffers(struct MPContext *mpctx) // Fill buffer if needed: current_module="decode_audio"; t = GetTimer(); - int res = decode_audio(sh_audio, playsize); + + if (!opts->initial_audio_sync || (ao_data.format & AF_FORMAT_SPECIAL_MASK)) + mpctx->syncing_audio = false; + + int res; + if (mpctx->syncing_audio && mpctx->sh_video) + res = audio_start_sync(mpctx, playsize); + else + res = decode_audio(sh_audio, playsize); if (res < 0) { // EOF, error or format change if (res == -2) format_change = true; + else if (res == ASYNC_PLAY_DONE) + return 1; else if (mpctx->d_audio->eof) { audio_eof = 1; int unitsize = ao_data.channels * af_fmt2bits(ao_data.format) / 8; @@ -4181,7 +4255,8 @@ if(!mpctx->sh_audio && mpctx->d_audio->sh) { /*========================== PLAY AUDIO ============================*/ -if (mpctx->sh_audio && !mpctx->paused) +if (mpctx->sh_audio && !mpctx->paused + && (!mpctx->restart_playback || !mpctx->sh_video)) if (!fill_audio_out_buffers(mpctx)) // at eof, all audio at least written to ao if (!mpctx->sh_video) @@ -4234,14 +4309,9 @@ if(!mpctx->sh_video) { } if (frame_time < 0) mpctx->stop_play = AT_END_OF_FILE; - else { - if (mpctx->restart_playback) { - // Show this frame immediately, rest normally - mpctx->restart_playback = false; - } else { - mpctx->time_frame += frame_time / opts->playback_speed; - adjust_sync(mpctx, frame_time); - } + else if (!mpctx->restart_playback) { + mpctx->time_frame += frame_time / opts->playback_speed; + adjust_sync(mpctx, frame_time); } } if (mpctx->timeline) { @@ -4287,7 +4357,8 @@ if(!mpctx->sh_video) { unsigned int pts_us = mpctx->last_time + mpctx->time_frame * 1e6; int duration = -1; double pts2 = mpctx->video_out->next_pts2; - if (pts2 != MP_NOPTS_VALUE && opts->correct_pts) { + if (pts2 != MP_NOPTS_VALUE && opts->correct_pts + && !mpctx->restart_playback) { // expected A/V sync correction is ignored double diff = (pts2 - mpctx->sh_video->pts); diff /= opts->playback_speed; @@ -4309,6 +4380,14 @@ if(!mpctx->sh_video) { // For print_status - VO call finishing early is OK for sync mpctx->time_frame -= get_relative_time(mpctx); } + if (mpctx->restart_playback) { + mpctx->syncing_audio = true; + if (mpctx->sh_audio && !mpctx->paused) + fill_audio_out_buffers(mpctx); + mpctx->restart_playback = false; + mpctx->time_frame = 0; + get_relative_time(mpctx); + } print_status(mpctx, MP_NOPTS_VALUE, true); } else @@ -42,6 +42,7 @@ typedef struct MPOpts { int correct_pts; int user_correct_pts; int user_pts_assoc_mode; + int initial_audio_sync; int key_fifo_size; int doubleclick_time; int audio_id; |