mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
audio_buffer: remove dependency on mp_audio
Just reimplement it in some way, as mp_audio is GPL-only. Actually I wanted to get rid of audio_buffer.c completely (and instead have a list of mp_aframes), but to do so would require rewriting some more player core audio code. So to get this LGPL relicensing over quickly, just do some extra work.
This commit is contained in:
parent
a4de782272
commit
caaa1189ba
@ -21,141 +21,137 @@
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include "chmap.h"
|
||||
#include "audio_buffer.h"
|
||||
#include "audio.h"
|
||||
#include "format.h"
|
||||
|
||||
struct mp_audio_buffer {
|
||||
struct mp_audio *buffer;
|
||||
int format;
|
||||
struct mp_chmap channels;
|
||||
int srate;
|
||||
int sstride;
|
||||
int num_planes;
|
||||
uint8_t *data[MP_NUM_CHANNELS];
|
||||
int allocated;
|
||||
int num_samples;
|
||||
};
|
||||
|
||||
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx)
|
||||
{
|
||||
struct mp_audio_buffer *ab = talloc(talloc_ctx, struct mp_audio_buffer);
|
||||
*ab = (struct mp_audio_buffer) {
|
||||
.buffer = talloc_zero(ab, struct mp_audio),
|
||||
};
|
||||
return ab;
|
||||
return talloc_zero(talloc_ctx, struct mp_audio_buffer);
|
||||
}
|
||||
|
||||
// Reinitialize the buffer, set a new format, drop old data.
|
||||
// The audio data in fmt is not used, only the format.
|
||||
void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt)
|
||||
{
|
||||
mp_audio_copy_config(ab->buffer, fmt);
|
||||
mp_audio_realloc(ab->buffer, 1);
|
||||
ab->buffer->samples = 0;
|
||||
}
|
||||
|
||||
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
|
||||
const struct mp_chmap *channels, int srate)
|
||||
{
|
||||
struct mp_audio mpa = {0};
|
||||
mp_audio_set_format(&mpa, format);
|
||||
mp_audio_set_channels(&mpa, channels);
|
||||
mpa.rate = srate;
|
||||
mp_audio_buffer_reinit(ab, &mpa);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
|
||||
struct mp_audio *out_fmt)
|
||||
{
|
||||
*out_fmt = (struct mp_audio){0};
|
||||
mp_audio_copy_config(out_fmt, ab->buffer);
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
TA_FREEP(&ab->data[n]);
|
||||
ab->format = format;
|
||||
ab->channels = *channels;
|
||||
ab->srate = srate;
|
||||
ab->allocated = 0;
|
||||
ab->num_samples = 0;
|
||||
ab->sstride = af_fmt_to_bytes(ab->format);
|
||||
ab->num_planes = 1;
|
||||
if (af_fmt_is_planar(ab->format)) {
|
||||
ab->num_planes = ab->channels.num;
|
||||
} else {
|
||||
ab->sstride *= ab->channels.num;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the total size of the internal buffer at least this number of samples.
|
||||
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
mp_audio_realloc_min(ab->buffer, samples);
|
||||
if (samples > ab->allocated) {
|
||||
for (int n = 0; n < ab->num_planes; n++) {
|
||||
ab->data[n] = talloc_realloc(ab, ab->data[n], char,
|
||||
ab->sstride * samples);
|
||||
}
|
||||
ab->allocated = samples;
|
||||
}
|
||||
}
|
||||
|
||||
// Get number of samples that can be written without forcing a resize of the
|
||||
// internal buffer.
|
||||
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return mp_audio_get_allocated_size(ab->buffer) - ab->buffer->samples;
|
||||
return ab->allocated - ab->num_samples;
|
||||
}
|
||||
|
||||
// Get a pointer to the end of the buffer (where writing would append). If the
|
||||
// internal buffer is too small for the given number of samples, it's resized.
|
||||
// After writing to the buffer, mp_audio_buffer_finish_write() has to be used
|
||||
// to make the written data part of the readable buffer.
|
||||
void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int samples,
|
||||
struct mp_audio *out_buffer)
|
||||
// All integer parameters are in samples.
|
||||
// dst and src can overlap.
|
||||
static void copy_planes(struct mp_audio_buffer *ab,
|
||||
uint8_t **dst, int dst_offset,
|
||||
uint8_t **src, int src_offset, int length)
|
||||
{
|
||||
assert(samples >= 0);
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples + samples);
|
||||
*out_buffer = *ab->buffer;
|
||||
out_buffer->samples = ab->buffer->samples + samples;
|
||||
mp_audio_skip_samples(out_buffer, ab->buffer->samples);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab));
|
||||
ab->buffer->samples += samples;
|
||||
for (int n = 0; n < ab->num_planes; n++) {
|
||||
memmove((char *)dst[n] + dst_offset * ab->sstride,
|
||||
(char *)src[n] + src_offset * ab->sstride,
|
||||
length * ab->sstride);
|
||||
}
|
||||
}
|
||||
|
||||
// Append data to the end of the buffer.
|
||||
// If the buffer is not large enough, it is transparently resized.
|
||||
// For now always copies the data.
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa)
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples)
|
||||
{
|
||||
int offset = ab->buffer->samples;
|
||||
ab->buffer->samples += mpa->samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, offset, mpa, 0, mpa->samples);
|
||||
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
|
||||
copy_planes(ab, ab->data, ab->num_samples, (uint8_t **)ptr, 0, samples);
|
||||
ab->num_samples += samples;
|
||||
}
|
||||
|
||||
// Prepend silence to the start of the buffer.
|
||||
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0);
|
||||
int oldlen = ab->buffer->samples;
|
||||
ab->buffer->samples += samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, samples, ab->buffer, 0, oldlen);
|
||||
mp_audio_fill_silence(ab->buffer, 0, samples);
|
||||
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
|
||||
copy_planes(ab, ab->data, samples, ab->data, 0, ab->num_samples);
|
||||
ab->num_samples += samples;
|
||||
for (int n = 0; n < ab->num_planes; n++)
|
||||
af_fill_silence(ab->data[n], samples * ab->sstride, ab->format);
|
||||
}
|
||||
|
||||
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= ab->buffer->samples);
|
||||
int oldlen = ab->buffer->samples;
|
||||
ab->buffer->samples += samples;
|
||||
mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, oldlen, ab->buffer, oldlen - samples, samples);
|
||||
assert(samples >= 0 && samples <= ab->num_samples);
|
||||
mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
|
||||
copy_planes(ab, ab->data, ab->num_samples,
|
||||
ab->data, ab->num_samples - samples, samples);
|
||||
ab->num_samples += samples;
|
||||
}
|
||||
|
||||
// Get the start of the current readable buffer.
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa)
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
|
||||
int *samples)
|
||||
{
|
||||
*out_mpa = *ab->buffer;
|
||||
*ptr = ab->data;
|
||||
*samples = ab->num_samples;
|
||||
}
|
||||
|
||||
// Skip leading samples. (Used with mp_audio_buffer_peek() to read data.)
|
||||
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples)
|
||||
{
|
||||
assert(samples >= 0 && samples <= ab->buffer->samples);
|
||||
mp_audio_copy(ab->buffer, 0, ab->buffer, samples,
|
||||
ab->buffer->samples - samples);
|
||||
ab->buffer->samples -= samples;
|
||||
assert(samples >= 0 && samples <= ab->num_samples);
|
||||
copy_planes(ab, ab->data, 0, ab->data, samples, ab->num_samples - samples);
|
||||
ab->num_samples -= samples;
|
||||
}
|
||||
|
||||
void mp_audio_buffer_clear(struct mp_audio_buffer *ab)
|
||||
{
|
||||
ab->buffer->samples = 0;
|
||||
ab->num_samples = 0;
|
||||
}
|
||||
|
||||
// Return number of buffered audio samples
|
||||
int mp_audio_buffer_samples(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return ab->buffer->samples;
|
||||
return ab->num_samples;
|
||||
}
|
||||
|
||||
// Return amount of buffered audio in seconds.
|
||||
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab)
|
||||
{
|
||||
return ab->buffer->samples / (double)ab->buffer->rate;
|
||||
return ab->num_samples / (double)ab->srate;
|
||||
}
|
||||
|
@ -19,24 +19,18 @@
|
||||
#define MP_AUDIO_BUFFER_H
|
||||
|
||||
struct mp_audio_buffer;
|
||||
struct mp_audio;
|
||||
struct mp_chmap;
|
||||
|
||||
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx);
|
||||
void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt);
|
||||
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
|
||||
const struct mp_chmap *channels, int srate);
|
||||
void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
|
||||
struct mp_audio *out_fmt);
|
||||
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples);
|
||||
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab);
|
||||
void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples,
|
||||
struct mp_audio *out_buffer);
|
||||
void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa);
|
||||
void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples);
|
||||
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa);
|
||||
void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
|
||||
int *samples);
|
||||
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
|
||||
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
|
||||
int mp_audio_buffer_samples(struct mp_audio_buffer *ab);
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include "osdep/timer.h"
|
||||
#include "osdep/atomic.h"
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/audio_buffer.h"
|
||||
|
||||
struct ao_push_state {
|
||||
@ -49,7 +48,8 @@ struct ao_push_state {
|
||||
|
||||
struct mp_audio_buffer *buffer;
|
||||
|
||||
struct mp_audio *silence;
|
||||
uint8_t *silence[MP_NUM_CHANNELS];
|
||||
int silence_samples;
|
||||
|
||||
bool terminate;
|
||||
bool wait_on_ao;
|
||||
@ -237,12 +237,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
||||
flags = flags & ~AOPLAY_FINAL_CHUNK;
|
||||
bool is_final = flags & AOPLAY_FINAL_CHUNK;
|
||||
|
||||
struct mp_audio audio;
|
||||
mp_audio_buffer_get_format(p->buffer, &audio);
|
||||
for (int n = 0; n < ao->num_planes; n++)
|
||||
audio.planes[n] = data[n];
|
||||
audio.samples = write_samples;
|
||||
mp_audio_buffer_append(p->buffer, &audio);
|
||||
mp_audio_buffer_append(p->buffer, data, samples);
|
||||
|
||||
bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final;
|
||||
|
||||
@ -260,22 +255,26 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
||||
return write_samples;
|
||||
}
|
||||
|
||||
static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size)
|
||||
static bool realloc_silence(struct ao *ao, int samples)
|
||||
{
|
||||
struct ao_push_state *p = ao->api_priv;
|
||||
if (!p->silence) {
|
||||
p->silence = talloc_zero(p, struct mp_audio);
|
||||
mp_audio_set_format(p->silence, ao->format);
|
||||
mp_audio_set_channels(p->silence, &ao->channels);
|
||||
p->silence->rate = ao->samplerate;
|
||||
|
||||
if (samples <= 0 || !af_fmt_is_pcm(ao->format))
|
||||
return false;
|
||||
|
||||
if (samples > p->silence_samples) {
|
||||
talloc_free(p->silence[0]);
|
||||
|
||||
int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
|
||||
p->silence[0] = talloc_size(p, bytes);
|
||||
for (int n = 1; n < MP_NUM_CHANNELS; n++)
|
||||
p->silence[n] = p->silence[0];
|
||||
p->silence_samples = samples;
|
||||
|
||||
af_fill_silence(p->silence[0], bytes, ao->format);
|
||||
}
|
||||
if (p->silence->samples < size) {
|
||||
mp_audio_realloc_min(p->silence, size);
|
||||
p->silence->samples = size;
|
||||
mp_audio_fill_silence(p->silence, 0, size);
|
||||
}
|
||||
*data = *p->silence;
|
||||
data->samples = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// called locked
|
||||
@ -287,39 +286,41 @@ static void ao_play_data(struct ao *ao)
|
||||
space = MPMAX(space, 0);
|
||||
if (space % ao->period_size)
|
||||
MP_ERR(ao, "Audio device reports unaligned available buffer size.\n");
|
||||
struct mp_audio data;
|
||||
uint8_t **planes;
|
||||
int samples;
|
||||
if (play_silence) {
|
||||
ao_get_silence(ao, &data, space);
|
||||
planes = p->silence;
|
||||
samples = realloc_silence(ao, space) ? space : 0;
|
||||
} else {
|
||||
mp_audio_buffer_peek(p->buffer, &data);
|
||||
mp_audio_buffer_peek(p->buffer, &planes, &samples);
|
||||
}
|
||||
int max = data.samples;
|
||||
if (data.samples > space)
|
||||
data.samples = space;
|
||||
int max = samples;
|
||||
if (samples > space)
|
||||
samples = space;
|
||||
int flags = 0;
|
||||
if (p->final_chunk && data.samples == max) {
|
||||
if (p->final_chunk && samples == max) {
|
||||
flags |= AOPLAY_FINAL_CHUNK;
|
||||
} else {
|
||||
data.samples = data.samples / ao->period_size * ao->period_size;
|
||||
samples = samples / ao->period_size * ao->period_size;
|
||||
}
|
||||
MP_STATS(ao, "start ao fill");
|
||||
int r = 0;
|
||||
if (data.samples)
|
||||
r = ao->driver->play(ao, data.planes, data.samples, flags);
|
||||
if (samples)
|
||||
r = ao->driver->play(ao, (void **)planes, samples, flags);
|
||||
MP_STATS(ao, "end ao fill");
|
||||
if (r > data.samples) {
|
||||
if (r > samples) {
|
||||
MP_ERR(ao, "Audio device returned non-sense value.\n");
|
||||
r = data.samples;
|
||||
r = samples;
|
||||
} else if (r < 0) {
|
||||
MP_ERR(ao, "Error writing audio to device.\n");
|
||||
} else if (r != data.samples) {
|
||||
} else if (r != samples) {
|
||||
MP_ERR(ao, "Audio device returned broken buffer state (sent %d samples, "
|
||||
"got %d samples, %d period%s)!\n", data.samples, r,
|
||||
"got %d samples, %d period%s)!\n", samples, r,
|
||||
ao->period_size, flags & AOPLAY_FINAL_CHUNK ? " final" : "");
|
||||
}
|
||||
r = MPMAX(r, 0);
|
||||
// Probably can't copy the rest of the buffer due to period alignment.
|
||||
bool stuck_eof = r <= 0 && space >= max && data.samples > 0;
|
||||
bool stuck_eof = r <= 0 && space >= max && samples > 0;
|
||||
if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) {
|
||||
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
|
||||
r = max;
|
||||
@ -491,17 +492,13 @@ const struct ao_driver ao_api_push = {
|
||||
int ao_play_silence(struct ao *ao, int samples)
|
||||
{
|
||||
assert(ao->api == &ao_api_push);
|
||||
if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play)
|
||||
|
||||
struct ao_push_state *p = ao->api_priv;
|
||||
|
||||
if (!realloc_silence(ao, samples) || !ao->driver->play)
|
||||
return 0;
|
||||
int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
|
||||
char *p = talloc_size(NULL, bytes);
|
||||
af_fill_silence(p, bytes, ao->format);
|
||||
void *tmp[MP_NUM_CHANNELS];
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
tmp[n] = p;
|
||||
int r = ao->driver->play(ao, tmp, samples, 0);
|
||||
talloc_free(p);
|
||||
return r;
|
||||
|
||||
return ao->driver->play(ao, (void **)p->silence, samples, 0);
|
||||
}
|
||||
|
||||
#ifndef __MINGW32__
|
||||
|
@ -497,7 +497,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
|
||||
goto init_error;
|
||||
}
|
||||
|
||||
mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt);
|
||||
mp_audio_buffer_reinit_fmt(ao_c->ao_buffer, fmt.format, &fmt.channels,
|
||||
fmt.rate);
|
||||
afs->output = fmt;
|
||||
if (!mp_audio_config_equals(&afs->output, &afs->filter_output))
|
||||
afs->initialized = 0;
|
||||
@ -603,9 +604,11 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track)
|
||||
reset_audio_state(mpctx);
|
||||
|
||||
if (mpctx->ao) {
|
||||
struct mp_audio fmt;
|
||||
get_ao_format(mpctx->ao, &fmt);
|
||||
mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt);
|
||||
int rate;
|
||||
int format;
|
||||
struct mp_chmap channels;
|
||||
ao_get_format(mpctx->ao, &rate, &format, &channels);
|
||||
mp_audio_buffer_reinit_fmt(ao_c->ao_buffer, format, &channels, rate);
|
||||
}
|
||||
|
||||
mp_wakeup_core(mpctx);
|
||||
@ -656,25 +659,28 @@ double playing_audio_pts(struct MPContext *mpctx)
|
||||
return pts - mpctx->audio_speed * ao_get_delay(mpctx->ao);
|
||||
}
|
||||
|
||||
static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags)
|
||||
static int write_to_ao(struct MPContext *mpctx, uint8_t **planes, int samples,
|
||||
int flags)
|
||||
{
|
||||
if (mpctx->paused)
|
||||
return 0;
|
||||
struct ao *ao = mpctx->ao;
|
||||
struct mp_audio out_format;
|
||||
get_ao_format(ao, &out_format);
|
||||
int samplerate;
|
||||
int format;
|
||||
struct mp_chmap channels;
|
||||
ao_get_format(ao, &samplerate, &format, &channels);
|
||||
#if HAVE_ENCODING
|
||||
encode_lavc_set_audio_pts(mpctx->encode_lavc_ctx, playing_audio_pts(mpctx));
|
||||
#endif
|
||||
if (data->samples == 0)
|
||||
if (samples == 0)
|
||||
return 0;
|
||||
double real_samplerate = out_format.rate / mpctx->audio_speed;
|
||||
int played = ao_play(mpctx->ao, data->planes, data->samples, flags);
|
||||
assert(played <= data->samples);
|
||||
double real_samplerate = samplerate / mpctx->audio_speed;
|
||||
int played = ao_play(mpctx->ao, (void **)planes, samples, flags);
|
||||
assert(played <= samples);
|
||||
if (played > 0) {
|
||||
mpctx->shown_aframes += played;
|
||||
mpctx->delay += played / real_samplerate;
|
||||
mpctx->written_audio += played / (double)out_format.rate;
|
||||
mpctx->written_audio += played / (double)samplerate;
|
||||
return played;
|
||||
}
|
||||
return 0;
|
||||
@ -812,8 +818,8 @@ static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
|
||||
if (cursamples + mpa->samples > maxsamples) {
|
||||
if (cursamples < maxsamples) {
|
||||
struct mp_audio pre = *mpa;
|
||||
pre.samples = maxsamples - cursamples;
|
||||
mp_audio_buffer_append(outbuf, &pre);
|
||||
mp_audio_buffer_append(outbuf, mpa->planes,
|
||||
maxsamples - cursamples);
|
||||
mp_audio_skip_samples(mpa, pre.samples);
|
||||
}
|
||||
af_unread_output_frame(afs, mpa);
|
||||
@ -821,7 +827,7 @@ static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
|
||||
return true;
|
||||
}
|
||||
|
||||
mp_audio_buffer_append(outbuf, mpa);
|
||||
mp_audio_buffer_append(outbuf, mpa->planes, mpa->samples);
|
||||
talloc_free(mpa);
|
||||
}
|
||||
return true;
|
||||
@ -1157,13 +1163,14 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
|
||||
if (audio_eof && !opts->gapless_audio)
|
||||
playflags |= AOPLAY_FINAL_CHUNK;
|
||||
|
||||
struct mp_audio data;
|
||||
mp_audio_buffer_peek(ao_c->ao_buffer, &data);
|
||||
if (audio_eof || data.samples >= align)
|
||||
data.samples = data.samples / align * align;
|
||||
data.samples = MPMIN(data.samples, mpctx->paused ? 0 : playsize);
|
||||
int played = write_to_ao(mpctx, &data, playflags);
|
||||
assert(played >= 0 && played <= data.samples);
|
||||
uint8_t **planes;
|
||||
int samples;
|
||||
mp_audio_buffer_peek(ao_c->ao_buffer, &planes, &samples);
|
||||
if (audio_eof || samples >= align)
|
||||
samples = samples / align * align;
|
||||
samples = MPMIN(samples, mpctx->paused ? 0 : playsize);
|
||||
int played = write_to_ao(mpctx, planes, samples, playflags);
|
||||
assert(played >= 0 && played <= samples);
|
||||
mp_audio_buffer_skip(ao_c->ao_buffer, played);
|
||||
|
||||
mpctx->audio_drop_throttle =
|
||||
|
Loading…
Reference in New Issue
Block a user