1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-10 17:09:45 +00:00

ao_null: properly simulate final chunk, add buffer options

Simulate proper handling of AOPLAY_FINAL_CHUNK. Print when underruns
occur (i.e. running out of data). Add some options that control
simulated buffer and outburst sizes.

All this is useful for debugging and self-documentation. (Note that
ao_null always was supposed to simulate an ideal AO, which is the reason
why it fools people who try to use it for benchmarking video.)
This commit is contained in:
wm4 2013-11-17 16:08:39 +01:00
parent b3eed7374e
commit e403140201
2 changed files with 56 additions and 19 deletions

View File

@ -157,6 +157,12 @@ Available audio output drivers are:
decoding will go as fast as possible, instead of timing it to the
system clock.
``buffer``
Simulated buffer length in seconds.
``outburst``
Simulated chunk size in samples.
``pcm``
Raw PCM/WAVE file writer audio output

View File

@ -18,6 +18,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Note: this does much more than just ignoring audio output. It simulates
* (to some degree) an ideal AO.
*/
#include <stdio.h>
#include <stdlib.h>
@ -26,18 +31,24 @@
#include "config.h"
#include "osdep/timer.h"
#include "mpvcore/m_option.h"
#include "mpvcore/mp_msg.h"
#include "audio/format.h"
#include "ao.h"
struct priv {
bool paused;
double last_time;
// All values are in samples
float buffered;
int buffersize;
int outburst;
bool playing_final;
float buffered; // samples
int buffersize; // samples
int untimed;
float bufferlen; // seconds
// Minimal unit of audio samples that can be written at once. If play() is
// called with sizes not aligned to this, a rounded size will be returned.
// (This is not needed by the AO API, but many AOs behave this way.)
int outburst; // samples
};
static void drain(struct ao *ao)
@ -53,9 +64,14 @@ static void drain(struct ao *ao)
return;
double now = mp_time_sec();
priv->buffered -= (now - priv->last_time) * ao->samplerate;
if (priv->buffered < 0)
priv->buffered = 0;
if (priv->buffered > 0) {
priv->buffered -= (now - priv->last_time) * ao->samplerate;
if (priv->buffered < 0) {
if (!priv->playing_final)
MP_ERR(ao, "buffer underrun\n");
priv->buffered = 0;
}
}
priv->last_time = now;
}
@ -70,13 +86,8 @@ static int init(struct ao *ao)
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;
// Minimal unit of audio samples that can be written at once. If play() is
// called with sizes not aligned to this, a rounded size will be returned.
// (This is not needed by the AO API, but many AOs behave this way.)
priv->outburst = 256;
// A "buffer" for about 0.2 seconds of audio
int bursts = (int)(ao->samplerate * 0.2 + 1) / priv->outburst;
// A "buffer" for this many seconds of audio
int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst;
priv->buffersize = priv->outburst * bursts;
priv->last_time = mp_time_sec();
@ -87,6 +98,9 @@ static int init(struct ao *ao)
// close audio device
static void uninit(struct ao *ao, bool cut_audio)
{
struct priv *priv = ao->priv;
if (!cut_audio && !priv->paused)
mp_sleep_us(1000.0 * 1000.0 * priv->buffered / ao->samplerate);
}
// stop playing and empty buffers (for seeking/pause)
@ -94,6 +108,7 @@ static void reset(struct ao *ao)
{
struct priv *priv = ao->priv;
priv->buffered = 0;
priv->playing_final = false;
}
// stop playing, keep buffers (for pause)
@ -101,6 +116,7 @@ static void pause(struct ao *ao)
{
struct priv *priv = ao->priv;
drain(ao);
priv->paused = true;
}
@ -125,13 +141,22 @@ static int get_space(struct ao *ao)
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *priv = ao->priv;
int accepted;
resume(ao);
int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst;
int playbursts = samples / priv->outburst;
int bursts = playbursts > maxbursts ? maxbursts : playbursts;
priv->buffered += bursts * priv->outburst;
return bursts * priv->outburst;
priv->playing_final = flags & AOPLAY_FINAL_CHUNK;
if (priv->playing_final) {
// Last audio chunk - don't round to outburst.
accepted = MPMIN(priv->buffersize - priv->buffered, samples);
} else {
int maxbursts = (priv->buffersize - priv->buffered) / priv->outburst;
int playbursts = samples / priv->outburst;
int bursts = playbursts > maxbursts ? maxbursts : playbursts;
accepted = bursts * priv->outburst;
}
priv->buffered += accepted;
return accepted;
}
static float get_delay(struct ao *ao)
@ -156,8 +181,14 @@ const struct ao_driver audio_out_null = {
.pause = pause,
.resume = resume,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.bufferlen = 200,
.outburst = 256,
},
.options = (const struct m_option[]) {
OPT_FLAG("untimed", untimed, 0),
OPT_FLOATRANGE("buffer", bufferlen, 0, 0, 100),
OPT_INTRANGE("outburst", outburst, 0, 1, 100000),
{0}
},
};