summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/mplayer.111
-rw-r--r--cfg-mplayer.h1
-rw-r--r--defaultopts.c1
-rw-r--r--libmpcodecs/dec_audio.c27
-rw-r--r--libmpcodecs/dec_audio.h1
-rw-r--r--mp_core.h4
-rw-r--r--mplayer.c103
-rw-r--r--options.h1
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);
diff --git a/mp_core.h b/mp_core.h
index ed90f4377b..206cbdacd3 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -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.
diff --git a/mplayer.c b/mplayer.c
index 83c6328b5d..77350cad73 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -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
diff --git a/options.h b/options.h
index a12038708c..86d524f57f 100644
--- a/options.h
+++ b/options.h
@@ -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;