summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libao2/audio_out.c6
-rw-r--r--libao2/audio_out.h4
-rw-r--r--libmpcodecs/dec_audio.c58
-rw-r--r--libmpcodecs/dec_audio.h6
-rw-r--r--libmpdemux/stheader.h5
-rw-r--r--mplayer.c84
6 files changed, 77 insertions, 86 deletions
diff --git a/libao2/audio_out.c b/libao2/audio_out.c
index 14cab9b285..bd06c8fd5f 100644
--- a/libao2/audio_out.c
+++ b/libao2/audio_out.c
@@ -221,8 +221,12 @@ void ao_init(struct ao *ao, char **ao_list)
void ao_uninit(struct ao *ao, bool cut_audio)
{
+ assert(ao->buffer.len >= ao->buffer_playable_size);
+ ao->buffer.len = ao->buffer_playable_size;
if (ao->initialized)
ao->driver->uninit(ao, cut_audio);
+ if (!cut_audio && ao->buffer.len)
+ mp_msg(MSGT_AO, MSGL_WARN, "Audio output truncated at end.\n");
talloc_free(ao);
}
@@ -254,6 +258,8 @@ int ao_get_space(struct ao *ao)
void ao_reset(struct ao *ao)
{
+ ao->buffer.len = 0;
+ ao->buffer_playable_size = 0;
if (ao->driver->reset)
ao->driver->reset(ao);
}
diff --git a/libao2/audio_out.h b/libao2/audio_out.h
index fb62923297..628b9c3ae7 100644
--- a/libao2/audio_out.h
+++ b/libao2/audio_out.h
@@ -21,6 +21,8 @@
#include <stdbool.h>
+#include "bstr.h"
+
typedef struct ao_info {
/* driver name ("Matrox Millennium G200/G400" */
const char *name;
@@ -71,6 +73,8 @@ struct ao {
int outburst;
int buffersize;
int pts;
+ struct bstr buffer;
+ int buffer_playable_size;
bool initialized;
bool untimed;
const struct ao_driver *driver;
diff --git a/libmpcodecs/dec_audio.c b/libmpcodecs/dec_audio.c
index 00c66287ed..0541947f60 100644
--- a/libmpcodecs/dec_audio.c
+++ b/libmpcodecs/dec_audio.c
@@ -23,6 +23,7 @@
#include "config.h"
#include "mp_msg.h"
+#include "bstr.h"
#include "stream/stream.h"
#include "libmpdemux/demuxer.h"
@@ -134,10 +135,6 @@ static int init_audio_codec(sh_audio_t *sh_audio)
"ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels);
- sh_audio->a_out_buffer_size = 0;
- sh_audio->a_out_buffer = NULL;
- sh_audio->a_out_buffer_len = 0;
-
return 1;
}
@@ -317,9 +314,6 @@ void uninit_audio(sh_audio_t *sh_audio)
#endif
sh_audio->initialized = 0;
}
- free(sh_audio->a_out_buffer);
- sh_audio->a_out_buffer = NULL;
- sh_audio->a_out_buffer_size = 0;
av_freep(&sh_audio->a_buffer);
av_freep(&sh_audio->a_in_buffer);
}
@@ -364,24 +358,23 @@ int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
*out_channels = afs->output.nch;
*out_format = afs->output.format;
- sh_audio->a_out_buffer_len = 0;
-
// ok!
sh_audio->afilter = (void *) afs;
return 1;
}
-static void set_min_out_buffer_size(struct sh_audio *sh, int len)
+static void set_min_out_buffer_size(struct bstr *outbuf, int len)
{
- if (sh->a_out_buffer_size < len) {
+ size_t oldlen = talloc_get_size(outbuf->start);
+ if (oldlen < len) {
+ assert(outbuf->start); // talloc context should be already set
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;
+ "from %zd to %d\n", oldlen, len);
+ outbuf->start = talloc_realloc_size(NULL, outbuf->start, len);
}
}
-static int filter_n_bytes(sh_audio_t *sh, int len)
+static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len)
{
assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size);
@@ -420,10 +413,10 @@ 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;
- 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;
+ set_min_out_buffer_size(outbuf, outbuf->len + filter_output->len);
+ memcpy(outbuf->start + outbuf->len, filter_output->audio,
+ filter_output->len);
+ outbuf->len += filter_output->len;
// remove processed data from decoder buffer:
sh->a_buffer_len -= len;
@@ -432,13 +425,14 @@ static int filter_n_bytes(sh_audio_t *sh, int len)
return error;
}
-/* Try to get at least minlen decoded+filtered bytes in sh_audio->a_out_buffer
+/* Try to get at least minlen decoded+filtered bytes in outbuf
* (total length including possible existing data).
* Return 0 on success, -1 on error/EOF (not distinguished).
- * In the former case sh_audio->a_out_buffer_len is always >= minlen
- * on return. In case of EOF/error it might or might not be.
- * Can reallocate sh_audio->a_out_buffer if needed to fit all filter output. */
-int decode_audio(sh_audio_t *sh_audio, int minlen)
+ * In the former case outbuf->len is always >= minlen on return.
+ * In case of EOF/error it might or might not be.
+ * Outbuf.start must be talloc-allocated, and will be reallocated
+ * if needed to fit all filter output. */
+int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen)
{
// Indicates that a filter seems to be buffering large amounts of data
int huge_filter_buffer = 0;
@@ -458,8 +452,8 @@ int decode_audio(sh_audio_t *sh_audio, int minlen)
int max_decode_len = sh_audio->a_buffer_size - sh_audio->audio_out_minsize;
max_decode_len -= max_decode_len % unitsize;
- while (sh_audio->a_out_buffer_len < minlen) {
- int declen = (minlen - sh_audio->a_out_buffer_len) / filter_multiplier
+ while (outbuf->len < minlen) {
+ int declen = (minlen - outbuf->len) / filter_multiplier
+ (unitsize << 5); // some extra for possible filter buffering
if (huge_filter_buffer)
/* Some filter must be doing significant buffering if the estimated
@@ -478,19 +472,19 @@ int decode_audio(sh_audio_t *sh_audio, int minlen)
/* if this iteration does not fill buffer, we must have lots
* of buffering in filters */
huge_filter_buffer = 1;
- int res = filter_n_bytes(sh_audio, declen);
+ int res = filter_n_bytes(sh_audio, outbuf, declen);
if (res < 0)
return res;
}
return 0;
}
-void decode_audio_prepend_bytes(struct sh_audio *sh, int count, int byte)
+void decode_audio_prepend_bytes(struct bstr *outbuf, 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;
+ set_min_out_buffer_size(outbuf, outbuf->len + count);
+ memmove(outbuf->start + count, outbuf->start, outbuf->len);
+ memset(outbuf->start, byte, count);
+ outbuf->len += count;
}
diff --git a/libmpcodecs/dec_audio.h b/libmpcodecs/dec_audio.h
index c2b92c9818..0d4baf0666 100644
--- a/libmpcodecs/dec_audio.h
+++ b/libmpcodecs/dec_audio.h
@@ -21,11 +21,13 @@
#include "libmpdemux/stheader.h"
+struct bstr;
+
// dec_audio.c:
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);
+int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen);
+void decode_audio_prepend_bytes(struct bstr *outbuf, 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/libmpdemux/stheader.h b/libmpdemux/stheader.h
index ce4db94035..1ca4acab8b 100644
--- a/libmpdemux/stheader.h
+++ b/libmpdemux/stheader.h
@@ -72,11 +72,6 @@ typedef struct sh_audio {
char* a_buffer;
int a_buffer_len;
int a_buffer_size;
- // output buffers:
- char* a_out_buffer;
- int a_out_buffer_len;
- int a_out_buffer_size;
-// void* audio_out; // the audio_out handle, used for this audio stream
struct af_stream *afilter; // the audio filter stream
const struct ad_functions *ad_driver;
#ifdef CONFIG_DYNAMIC_PLUGINS
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;
}