summaryrefslogtreecommitdiffstats
path: root/mplayer.c
diff options
context:
space:
mode:
authorUoti Urpala <uau@mplayer2.org>2011-07-02 09:22:32 +0300
committerUoti Urpala <uau@mplayer2.org>2011-07-02 09:22:32 +0300
commitc8b3088c1831ab5f698924ce75127caa55b50dbb (patch)
tree12ca3b7d7b53ff9458b80f2c83de2cf29d522862 /mplayer.c
parent746f9b004038e09392b69abb3ba26b1cc32a90d7 (diff)
downloadmpv-c8b3088c1831ab5f698924ce75127caa55b50dbb.tar.bz2
mpv-c8b3088c1831ab5f698924ce75127caa55b50dbb.tar.xz
audio: move ready-for-ao data buffer from decoder to AO
Move the buffer storing audio data ready to be fed to the audio output driver from the audio decoder object to the AO object. This will help encoding code deal with end of input, and may also be useful to improve other general gapless audio behavior (as AOs which do not accept chunks smaller than a certain size may keep them in the buffer while the decoder changes). Less data may be dropped now when changing audio filters or switching timeline parts.
Diffstat (limited to 'mplayer.c')
-rw-r--r--mplayer.c84
1 files changed, 37 insertions, 47 deletions
diff --git a/mplayer.c b/mplayer.c
index e65afe5b0f..90cf15c8b3 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1748,6 +1748,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
mp_tmsg(MSGT_CPLAYER,MSGL_ERR,"Could not open/initialize audio device -> no sound.\n");
goto init_error;
}
+ ao->buffer.start = talloc_new(ao);
mp_msg(MSGT_CPLAYER,MSGL_INFO,"AO: [%s] %dHz %dch %s (%d bytes per sample)\n",
ao->driver->info->short_name,
ao->samplerate, ao->channels,
@@ -1788,7 +1789,6 @@ static double written_audio_pts(struct MPContext *mpctx)
{
sh_audio_t *sh_audio = mpctx->sh_audio;
demux_stream_t *d_audio = mpctx->d_audio;
- double buffered_output;
// first calculate the end pts of audio that has been output by decoder
double a_pts = sh_audio->pts;
if (a_pts != MP_NOPTS_VALUE)
@@ -1822,11 +1822,11 @@ static double written_audio_pts(struct MPContext *mpctx)
a_pts -= sh_audio->a_buffer_len / (double)sh_audio->o_bps;
// Data buffered in audio filters, measured in bytes of "missing" output
- buffered_output = af_calc_delay(sh_audio->afilter);
+ double buffered_output = af_calc_delay(sh_audio->afilter);
// Data that was ready for ao but was buffered because ao didn't fully
// accept everything to internal buffers yet
- buffered_output += sh_audio->a_out_buffer_len;
+ buffered_output += mpctx->ao->buffer.len;
// Filters divide audio length by playback_speed, so multiply by it
// to get the length in original units without speedup or slowdown
@@ -2328,7 +2328,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
int res;
// Timing info may not be set without
- res = decode_audio(sh_audio, 1);
+ res = decode_audio(sh_audio, &ao->buffer, 1);
if (res < 0)
return res;
@@ -2345,7 +2345,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) {
if (!did_retry) {
// Try to read more data to see packets that have pts
- int res = decode_audio(sh_audio, ao->bps);
+ int res = decode_audio(sh_audio, &ao->buffer, ao->bps);
if (res < 0)
return res;
did_retry = true;
@@ -2362,19 +2362,17 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
mpctx->syncing_audio = false;
int a = FFMIN(-bytes, FFMAX(playsize, 20000));
- int res = decode_audio(sh_audio, a);
- bytes += sh_audio->a_out_buffer_len;
+ int res = decode_audio(sh_audio, &ao->buffer, a);
+ bytes += ao->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;
+ memmove(ao->buffer.start,
+ ao->buffer.start + ao->buffer.len - bytes, bytes);
+ ao->buffer.len = bytes;
if (res < 0)
return res;
- return decode_audio(sh_audio, playsize);
+ return decode_audio(sh_audio, &ao->buffer, playsize);
}
- sh_audio->a_out_buffer_len = 0;
+ ao->buffer.len = 0;
if (res < 0)
return res;
}
@@ -2394,8 +2392,8 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
return ASYNC_PLAY_DONE;
}
mpctx->syncing_audio = false;
- decode_audio_prepend_bytes(sh_audio, bytes, fillbyte);
- return decode_audio(sh_audio, playsize);
+ decode_audio_prepend_bytes(&ao->buffer, bytes, fillbyte);
+ return decode_audio(sh_audio, &ao->buffer, playsize);
}
static int fill_audio_out_buffers(struct MPContext *mpctx)
@@ -2408,7 +2406,6 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
int playflags=0;
bool audio_eof = false;
bool partial_fill = false;
- bool format_change = false;
sh_audio_t * const sh_audio = mpctx->sh_audio;
bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK);
int unitsize = ao->channels * af_fmt2bits(ao->format) / 8;
@@ -2435,11 +2432,17 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
if (mpctx->syncing_audio && mpctx->sh_video)
res = audio_start_sync(mpctx, playsize);
else
- res = decode_audio(sh_audio, playsize);
+ res = decode_audio(sh_audio, &ao->buffer, playsize);
if (res < 0) { // EOF, error or format change
- if (res == -2)
- format_change = true;
- else if (res == ASYNC_PLAY_DONE)
+ if (res == -2) {
+ /* The format change isn't handled too gracefully. A more precise
+ * implementation would require draining buffered old-format audio
+ * while displaying video, then doing the output format switch.
+ */
+ uninit_player(mpctx, INITIALIZED_AO);
+ reinit_audio_chain(mpctx);
+ return -1;
+ } else if (res == ASYNC_PLAY_DONE)
return 0;
else if (mpctx->d_audio->eof)
audio_eof = true;
@@ -2458,10 +2461,10 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
}
}
- assert(sh_audio->a_out_buffer_len % unitsize == 0);
- if (playsize > sh_audio->a_out_buffer_len) {
+ assert(ao->buffer.len % unitsize == 0);
+ if (playsize > ao->buffer.len) {
partial_fill = true;
- playsize = sh_audio->a_out_buffer_len;
+ playsize = ao->buffer.len;
if (audio_eof)
playflags |= AOPLAY_FINAL_CHUNK;
}
@@ -2476,29 +2479,18 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
// They're obviously badly broken in the way they handle av sync;
// would not having access to this make them more broken?
ao->pts = ((mpctx->sh_video?mpctx->sh_video->timer:0)+mpctx->delay)*90000.0;
- playsize = ao_play(ao, sh_audio->a_out_buffer, playsize, playflags);
- assert(playsize % unitsize == 0);
-
- if (playsize > 0) {
- sh_audio->a_out_buffer_len -= playsize;
- memmove(sh_audio->a_out_buffer, &sh_audio->a_out_buffer[playsize],
- sh_audio->a_out_buffer_len);
- mpctx->delay += opts->playback_speed*playsize/(double)ao->bps;
+ int played = ao_play(ao, ao->buffer.start, playsize, playflags);
+ assert(played % unitsize == 0);
+ ao->buffer_playable_size = playsize - played;
+
+ if (played > 0) {
+ ao->buffer.len -= played;
+ memmove(ao->buffer.start, ao->buffer.start + played, ao->buffer.len);
+ mpctx->delay += opts->playback_speed * played / ao->bps;
} else if (audio_eof && ao_get_delay(ao) < .04) {
// Sanity check to avoid hanging in case current ao doesn't output
// partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
- mp_msg(MSGT_CPLAYER, MSGL_WARN, "Audio output truncated at end.\n");
- sh_audio->a_out_buffer_len = 0;
- }
-
- /* The format change isn't handled too gracefully. A more precise
- * implementation would require draining buffered old-format audio
- * while displaying video, then doing the output format switch.
- */
- if (format_change) {
- uninit_player(mpctx, INITIALIZED_AO);
- reinit_audio_chain(mpctx);
- return -1;
+ return -2;
}
return -partial_fill;
@@ -3047,10 +3039,9 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
current_module = "seek_audio_reset";
resync_audio_stream(mpctx->sh_audio);
if (reset_ao)
- // stop audio, throwing away buffered data
ao_reset(mpctx->ao);
+ mpctx->ao->buffer.len = mpctx->ao->buffer_playable_size;
mpctx->sh_audio->a_buffer_len = 0;
- mpctx->sh_audio->a_out_buffer_len = 0;
if (!mpctx->sh_video)
update_subtitles(mpctx, mpctx->sh_audio->pts,
mpctx->video_offset, true);
@@ -3155,7 +3146,6 @@ static int seek(MPContext *mpctx, struct seek_params seek,
if (mpctx->sh_audio) {
ao_reset(mpctx->ao);
mpctx->sh_audio->a_buffer_len = 0;
- mpctx->sh_audio->a_out_buffer_len = 0;
}
return -1;
}