summaryrefslogtreecommitdiffstats
path: root/mpvcore
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-10 23:38:18 +0100
committerwm4 <wm4@nowhere>2013-11-12 23:29:53 +0100
commit347a86198b214b5e79b45d198c5cd2cc3c3a759a (patch)
treea8adf255ac2cedfa4bb29384e02243550c7a6647 /mpvcore
parentd1ee9ea261798f94fe958578d9748a69864c3058 (diff)
downloadmpv-347a86198b214b5e79b45d198c5cd2cc3c3a759a.tar.bz2
mpv-347a86198b214b5e79b45d198c5cd2cc3c3a759a.tar.xz
audio: switch output to mp_audio_buffer
Replace the code that used a single buffer with mp_audio_buffer. This also enables non-interleaved output operation, although it's still disabled, and no AO supports it yet.
Diffstat (limited to 'mpvcore')
-rw-r--r--mpvcore/player/audio.c134
-rw-r--r--mpvcore/player/loadfile.c12
2 files changed, 80 insertions, 66 deletions
diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c
index e0c35c628e..fa29778fe9 100644
--- a/mpvcore/player/audio.c
+++ b/mpvcore/player/audio.c
@@ -30,6 +30,8 @@
#include "mpvcore/mp_common.h"
#include "audio/mixer.h"
+#include "audio/audio.h"
+#include "audio/audio_buffer.h"
#include "audio/decode/dec_audio.h"
#include "audio/filter/af.h"
#include "audio/out/ao.h"
@@ -147,7 +149,11 @@ void reinit_audio_chain(struct MPContext *mpctx)
MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n");
goto init_error;
}
- ao->buffer.start = talloc_new(ao);
+
+ ao->buffer = mp_audio_buffer_create(ao);
+ mp_audio_buffer_reinit_fmt(ao->buffer, ao->format, &ao->channels,
+ ao->samplerate);
+
char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format);
MP_INFO(mpctx, "AO: [%s] %s\n", ao->driver->name, s);
talloc_free(s);
@@ -196,16 +202,16 @@ double written_audio_pts(struct MPContext *mpctx)
// Decoded but not filtered
a_pts -= sh_audio->a_buffer_len / bps;
- // Data buffered in audio filters, measured in bytes of "missing" output
- double buffered_output = af_calc_delay(sh_audio->afilter);
+ // Data buffered in audio filters, measured in seconds of "missing" output
+ double buffered_output = af_calc_delay(sh_audio->afilter) / mpctx->ao->bps;
// Data that was ready for ao but was buffered because ao didn't fully
// accept everything to internal buffers yet
- buffered_output += mpctx->ao->buffer.len;
+ buffered_output += mp_audio_buffer_seconds(mpctx->ao->buffer);
// Filters divide audio length by playback_speed, so multiply by it
// to get the length in original units without speedup or slowdown
- a_pts -= buffered_output * mpctx->opts->playback_speed / mpctx->ao->bps;
+ a_pts -= buffered_output * mpctx->opts->playback_speed;
return a_pts + mpctx->video_offset;
}
@@ -219,29 +225,42 @@ double playing_audio_pts(struct MPContext *mpctx)
return pts - mpctx->opts->playback_speed * ao_get_delay(mpctx->ao);
}
-static int write_to_ao(struct MPContext *mpctx, void *data, int len, int flags,
+static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags,
double pts)
{
if (mpctx->paused)
return 0;
struct ao *ao = mpctx->ao;
- double bps = ao->bps / mpctx->opts->playback_speed;
- int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8;
ao->pts = pts;
- int played = ao_play(mpctx->ao, data, len, flags);
- assert(played <= len);
- assert(played % unitsize == 0);
+ double real_samplerate = ao->samplerate / mpctx->opts->playback_speed;
+ int played = ao_play(mpctx->ao, data->planes, data->samples, flags);
+ assert(played <= data->samples);
if (played > 0) {
- mpctx->shown_aframes += played / unitsize;
- mpctx->delay += played / bps;
+ mpctx->shown_aframes += played;
+ mpctx->delay += played / real_samplerate;
// Keep correct pts for remaining data - could be used to flush
// remaining buffer when closing ao.
- ao->pts += played / bps;
+ ao->pts += played / real_samplerate;
return played;
}
return 0;
}
+static int write_silence_to_ao(struct MPContext *mpctx, int samples, int flags,
+ double pts)
+{
+ struct mp_audio tmp = {0};
+ mp_audio_buffer_get_format(mpctx->ao->buffer, &tmp);
+ tmp.samples = samples;
+ char *p = talloc_size(NULL, tmp.samples * tmp.sstride);
+ for (int n = 0; n < tmp.num_planes; n++)
+ tmp.planes[n] = p;
+ mp_audio_fill_silence(&tmp, 0, tmp.samples);
+ int r = write_to_ao(mpctx, &tmp, 0, pts);
+ talloc_free(p);
+ return r;
+}
+
#define ASYNC_PLAY_DONE -3
static int audio_start_sync(struct MPContext *mpctx, int playsize)
{
@@ -251,14 +270,14 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
int res;
// Timing info may not be set without
- res = decode_audio(sh_audio, &ao->buffer, 1);
+ res = decode_audio(sh_audio, ao->buffer, 1);
if (res < 0)
return res;
- int bytes;
+ int samples;
bool did_retry = false;
double written_pts;
- double bps = ao->bps / opts->playback_speed;
+ double real_samplerate = ao->samplerate / opts->playback_speed;
bool hrseek = mpctx->hrseek_active; // audio only hrseek
mpctx->hrseek_active = false;
while (1) {
@@ -269,64 +288,56 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
else
ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay
- mpctx->audio_delay;
- bytes = ptsdiff * bps;
- bytes -= bytes % (ao->channels.num * af_fmt2bits(ao->format) / 8);
+ samples = ptsdiff * real_samplerate;
// ogg demuxers give packets without timing
if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) {
if (!did_retry) {
// Try to read more data to see packets that have pts
- res = decode_audio(sh_audio, &ao->buffer, ao->bps);
+ res = decode_audio(sh_audio, ao->buffer, ao->samplerate);
if (res < 0)
return res;
did_retry = true;
continue;
}
- bytes = 0;
+ samples = 0;
}
if (fabs(ptsdiff) > 300 || isnan(ptsdiff)) // pts reset or just broken?
- bytes = 0;
+ samples = 0;
- if (bytes > 0)
+ if (samples > 0)
break;
mpctx->syncing_audio = false;
- int a = MPMIN(-bytes, MPMAX(playsize, 20000));
- res = decode_audio(sh_audio, &ao->buffer, a);
- bytes += ao->buffer.len;
- if (bytes >= 0) {
- memmove(ao->buffer.start,
- ao->buffer.start + ao->buffer.len - bytes, bytes);
- ao->buffer.len = bytes;
+ int skip_samples = -samples;
+ int a = MPMIN(skip_samples, MPMAX(playsize, 2500));
+ res = decode_audio(sh_audio, ao->buffer, a);
+ if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) {
+ mp_audio_buffer_skip(ao->buffer, skip_samples);
if (res < 0)
return res;
- return decode_audio(sh_audio, &ao->buffer, playsize);
+ return decode_audio(sh_audio, ao->buffer, playsize);
}
- ao->buffer.len = 0;
+ mp_audio_buffer_clear(ao->buffer);
if (res < 0)
return res;
}
if (hrseek)
// Don't add silence in audio-only case even if position is too late
return 0;
- int fillbyte = 0;
- if ((ao->format & AF_FORMAT_SIGN_MASK) == AF_FORMAT_US)
- fillbyte = 0x80;
- if (bytes >= playsize) {
+ if (samples >= 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
+ * samples = playsize, but then silence would keep accumulating
+ * in ao->buffer if the AO accepts less data than it asks for
* in playsize. */
- char *p = malloc(playsize);
- memset(p, fillbyte, playsize);
- write_to_ao(mpctx, p, playsize, 0, written_pts - bytes / bps);
- free(p);
+ write_silence_to_ao(mpctx, playsize, 0,
+ written_pts - samples / real_samplerate);
return ASYNC_PLAY_DONE;
}
mpctx->syncing_audio = false;
- decode_audio_prepend_bytes(&ao->buffer, bytes, fillbyte);
- return decode_audio(sh_audio, &ao->buffer, playsize);
+ mp_audio_buffer_prepend_silence(ao->buffer, samples);
+ return decode_audio(sh_audio, ao->buffer, playsize);
}
int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
@@ -340,7 +351,6 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
bool partial_fill = false;
sh_audio_t * const sh_audio = mpctx->sh_audio;
bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK);
- int unitsize = ao->channels.num * af_fmt2bits(ao->format) / 8;
if (mpctx->paused)
playsize = 1; // just initialize things (audio pts at least)
@@ -359,7 +369,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
if (mpctx->syncing_audio || mpctx->hrseek_active)
res = audio_start_sync(mpctx, playsize);
else
- res = decode_audio(sh_audio, &ao->buffer, playsize);
+ res = decode_audio(sh_audio, ao->buffer, playsize);
if (res < 0) { // EOF, error or format change
if (res == -2) {
@@ -378,21 +388,19 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
}
if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) {
- double bytes = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay)
- * ao->bps / opts->playback_speed;
- if (playsize > bytes) {
- playsize = MPMAX(bytes, 0);
+ double samples = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay)
+ * ao->samplerate / opts->playback_speed;
+ if (playsize > samples) {
+ playsize = MPMAX(samples, 0);
audio_eof = true;
partial_fill = true;
}
}
- assert(ao->buffer.len % unitsize == 0);
- if (playsize > ao->buffer.len) {
+ if (playsize > mp_audio_buffer_samples(ao->buffer)) {
+ playsize = mp_audio_buffer_samples(ao->buffer);
partial_fill = true;
- playsize = ao->buffer.len;
}
- playsize -= playsize % unitsize;
if (!playsize)
return partial_fill && audio_eof ? -2 : -partial_fill;
@@ -406,14 +414,16 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
}
}
- assert(ao->buffer_playable_size <= ao->buffer.len);
- int played = write_to_ao(mpctx, ao->buffer.start, playsize, playflags,
- written_audio_pts(mpctx));
- ao->buffer_playable_size = playsize - played;
+ assert(ao->buffer_playable_samples <= mp_audio_buffer_samples(ao->buffer));
+
+ struct mp_audio data;
+ mp_audio_buffer_peek(ao->buffer, &data);
+ data.samples = MPMIN(data.samples, playsize);
+ int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx));
+ ao->buffer_playable_samples = playsize - played;
if (played > 0) {
- ao->buffer.len -= played;
- memmove(ao->buffer.start, ao->buffer.start + played, ao->buffer.len);
+ mp_audio_buffer_skip(ao->buffer, played);
} else if (!mpctx->paused && 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
@@ -428,8 +438,8 @@ void clear_audio_output_buffers(struct MPContext *mpctx)
{
if (mpctx->ao) {
ao_reset(mpctx->ao);
- mpctx->ao->buffer.len = 0;
- mpctx->ao->buffer_playable_size = 0;
+ mp_audio_buffer_clear(mpctx->ao->buffer);
+ mpctx->ao->buffer_playable_samples = 0;
}
}
diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c
index a35da703ed..fffb1566c2 100644
--- a/mpvcore/player/loadfile.c
+++ b/mpvcore/player/loadfile.c
@@ -43,6 +43,8 @@
#include "mpvcore/input/input.h"
#include "audio/mixer.h"
+#include "audio/audio.h"
+#include "audio/audio_buffer.h"
#include "audio/decode/dec_audio.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
@@ -163,11 +165,13 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
// Note: with gapless_audio, stop_play is not correctly set
if (opts->gapless_audio || mpctx->stop_play == AT_END_OF_FILE) {
drain = true;
- int len = ao->buffer_playable_size;
- assert(len <= ao->buffer.len);
- int played = ao_play(ao, ao->buffer.start, len,
+ struct mp_audio data;
+ mp_audio_buffer_peek(ao->buffer, &data);
+ int samples = ao->buffer_playable_samples;
+ assert(samples <= data.samples);
+ int played = ao_play(ao, data.planes, samples,
AOPLAY_FINAL_CHUNK);
- if (played < len)
+ if (played < samples)
MP_WARN(ao, "Audio output truncated at end.\n");
}
ao_uninit(ao, drain);