mirror of https://github.com/mpv-player/mpv
ao_pcm, core: use new API in ao_pcm, change timing with it
Change ao_pcm to use the new audio output driver API and clean up some of the code. Rewrite the logic controlling how playback timing works when using -ao pcm. Deprecate the "fast" suboption; its only effect now is to print a warning, but it's still accepted so that specifying it is not an error. Before, timing with -ao pcm and video enabled had two possible modes. In the default mode playback speed was rather arbitrary - not realtime, but not particularly fast. -ao pcm:fast tried to play back at maximum video playback speed - mostly succeeding, but not quite guaranteed to work in all cases. Now the default is to play at realtime speed. The -benchmark option can now be used to get faster playback (same as the video-only case). In the audio-only case playback is always maximum speed.
This commit is contained in:
parent
2fae42d00e
commit
40f6ab5064
|
@ -3020,11 +3020,6 @@ When not included, raw PCM will be generated.
|
||||||
Write the sound to <filename> instead of the default
|
Write the sound to <filename> instead of the default
|
||||||
audiodump.wav.
|
audiodump.wav.
|
||||||
If nowaveheader is specified, the default is audiodump.pcm.
|
If nowaveheader is specified, the default is audiodump.pcm.
|
||||||
.IPs "fast\ "
|
|
||||||
Try to dump faster than realtime.
|
|
||||||
Make sure the output does not get truncated (usually with
|
|
||||||
"Too many video packets in buffer" message).
|
|
||||||
It is normal that you get a "Your system is too SLOW to play this!" message.
|
|
||||||
.RE
|
.RE
|
||||||
.PD 1
|
.PD 1
|
||||||
.
|
.
|
||||||
|
|
241
libao2/ao_pcm.c
241
libao2/ao_pcm.c
|
@ -24,13 +24,14 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libavutil/common.h"
|
#include <libavutil/common.h>
|
||||||
#include "mpbswap.h"
|
|
||||||
|
#include "talloc.h"
|
||||||
|
|
||||||
#include "subopt-helper.h"
|
#include "subopt-helper.h"
|
||||||
#include "libaf/af_format.h"
|
#include "libaf/af_format.h"
|
||||||
#include "libaf/reorder_ch.h"
|
#include "libaf/reorder_ch.h"
|
||||||
#include "audio_out.h"
|
#include "audio_out.h"
|
||||||
#include "audio_out_internal.h"
|
|
||||||
#include "mp_msg.h"
|
#include "mp_msg.h"
|
||||||
|
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
|
@ -38,22 +39,13 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const ao_info_t info =
|
struct priv {
|
||||||
{
|
char *outputfilename;
|
||||||
"RAW PCM/WAVE file writer audio output",
|
int waveheader;
|
||||||
"pcm",
|
uint64_t data_length;
|
||||||
"Atmosfear",
|
FILE *fp;
|
||||||
""
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LIBAO_EXTERN(pcm)
|
|
||||||
|
|
||||||
extern int vo_pts;
|
|
||||||
|
|
||||||
static char *ao_outputfilename = NULL;
|
|
||||||
static int ao_pcm_waveheader = 1;
|
|
||||||
static int fast = 0;
|
|
||||||
|
|
||||||
#define WAV_ID_RIFF 0x46464952 /* "RIFF" */
|
#define WAV_ID_RIFF 0x46464952 /* "RIFF" */
|
||||||
#define WAV_ID_WAVE 0x45564157 /* "WAVE" */
|
#define WAV_ID_WAVE 0x45564157 /* "WAVE" */
|
||||||
#define WAV_ID_FMT 0x20746d66 /* "fmt " */
|
#define WAV_ID_FMT 0x20746d66 /* "fmt " */
|
||||||
|
@ -62,30 +54,30 @@ static int fast = 0;
|
||||||
#define WAV_ID_FLOAT_PCM 0x0003
|
#define WAV_ID_FLOAT_PCM 0x0003
|
||||||
#define WAV_ID_FORMAT_EXTENSIBLE 0xfffe
|
#define WAV_ID_FORMAT_EXTENSIBLE 0xfffe
|
||||||
|
|
||||||
/* init with default values */
|
static void fput16le(uint16_t val, FILE *fp)
|
||||||
static uint64_t data_length;
|
{
|
||||||
static FILE *fp = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
static void fput16le(uint16_t val, FILE *fp) {
|
|
||||||
uint8_t bytes[2] = {val, val >> 8};
|
uint8_t bytes[2] = {val, val >> 8};
|
||||||
fwrite(bytes, 1, 2, fp);
|
fwrite(bytes, 1, 2, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fput32le(uint32_t val, FILE *fp) {
|
static void fput32le(uint32_t val, FILE *fp)
|
||||||
|
{
|
||||||
uint8_t bytes[4] = {val, val >> 8, val >> 16, val >> 24};
|
uint8_t bytes[4] = {val, val >> 8, val >> 16, val >> 24};
|
||||||
fwrite(bytes, 1, 4, fp);
|
fwrite(bytes, 1, 4, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_wave_header(FILE *fp, uint64_t data_length) {
|
static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length)
|
||||||
int use_waveex = (ao_data.channels >= 5 && ao_data.channels <= 8);
|
{
|
||||||
uint16_t fmt = (ao_data.format == AF_FORMAT_FLOAT_LE) ? WAV_ID_FLOAT_PCM : WAV_ID_PCM;
|
bool use_waveex = ao->channels >= 5 && ao->channels <= 8;
|
||||||
|
uint16_t fmt = ao->format == AF_FORMAT_FLOAT_LE ?
|
||||||
|
WAV_ID_FLOAT_PCM : WAV_ID_PCM;
|
||||||
uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
|
uint32_t fmt_chunk_size = use_waveex ? 40 : 16;
|
||||||
int bits = af_fmt2bits(ao_data.format);
|
int bits = af_fmt2bits(ao->format);
|
||||||
|
|
||||||
// Master RIFF chunk
|
// Master RIFF chunk
|
||||||
fput32le(WAV_ID_RIFF, fp);
|
fput32le(WAV_ID_RIFF, fp);
|
||||||
// RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size + data chunk hdr (8) + data length
|
// RIFF chunk size: 'WAVE' + 'fmt ' + 4 + fmt_chunk_size +
|
||||||
|
// data chunk hdr (8) + data length
|
||||||
fput32le(12 + fmt_chunk_size + 8 + data_length, fp);
|
fput32le(12 + fmt_chunk_size + 8 + data_length, fp);
|
||||||
fput32le(WAV_ID_WAVE, fp);
|
fput32le(WAV_ID_WAVE, fp);
|
||||||
|
|
||||||
|
@ -93,17 +85,17 @@ static void write_wave_header(FILE *fp, uint64_t data_length) {
|
||||||
fput32le(WAV_ID_FMT, fp);
|
fput32le(WAV_ID_FMT, fp);
|
||||||
fput32le(fmt_chunk_size, fp);
|
fput32le(fmt_chunk_size, fp);
|
||||||
fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
|
fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp);
|
||||||
fput16le(ao_data.channels, fp);
|
fput16le(ao->channels, fp);
|
||||||
fput32le(ao_data.samplerate, fp);
|
fput32le(ao->samplerate, fp);
|
||||||
fput32le(ao_data.bps, fp);
|
fput32le(ao->bps, fp);
|
||||||
fput16le(ao_data.channels * (bits / 8), fp);
|
fput16le(ao->channels * (bits / 8), fp);
|
||||||
fput16le(bits, fp);
|
fput16le(bits, fp);
|
||||||
|
|
||||||
if (use_waveex) {
|
if (use_waveex) {
|
||||||
// Extension chunk
|
// Extension chunk
|
||||||
fput16le(22, fp);
|
fput16le(22, fp);
|
||||||
fput16le(bits, fp);
|
fput16le(bits, fp);
|
||||||
switch (ao_data.channels) {
|
switch (ao->channels) {
|
||||||
case 5:
|
case 5:
|
||||||
fput32le(0x0607, fp); // L R C Lb Rb
|
fput32le(0x0607, fp); // L R C Lb Rb
|
||||||
break;
|
break;
|
||||||
|
@ -129,36 +121,36 @@ static void write_wave_header(FILE *fp, uint64_t data_length) {
|
||||||
fput32le(data_length, fp);
|
fput32le(data_length, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// to set/get/query special features/parameters
|
static int init(struct ao *ao, char *params)
|
||||||
static int control(int cmd,void *arg){
|
{
|
||||||
return -1;
|
struct priv *priv = talloc_zero(ao, struct priv);
|
||||||
}
|
ao->priv = priv;
|
||||||
|
|
||||||
// open & setup audio device
|
int fast;
|
||||||
// return: 1=success 0=fail
|
|
||||||
static int init(int rate,int channels,int format,int flags){
|
|
||||||
const opt_t subopts[] = {
|
const opt_t subopts[] = {
|
||||||
{"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL},
|
{"waveheader", OPT_ARG_BOOL, &priv->waveheader, NULL},
|
||||||
{"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL},
|
{"file", OPT_ARG_MSTRZ, &priv->outputfilename, NULL},
|
||||||
{"fast", OPT_ARG_BOOL, &fast, NULL},
|
{"fast", OPT_ARG_BOOL, &fast, NULL},
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
// set defaults
|
// set defaults
|
||||||
ao_pcm_waveheader = 1;
|
priv->waveheader = 1;
|
||||||
|
|
||||||
if (subopt_parse(ao_subdevice, subopts) != 0) {
|
if (subopt_parse(params, subopts) != 0)
|
||||||
return 0;
|
return -1;
|
||||||
}
|
|
||||||
if (!ao_outputfilename){
|
|
||||||
ao_outputfilename =
|
|
||||||
strdup(ao_pcm_waveheader?"audiodump.wav":"audiodump.pcm");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ao_pcm_waveheader)
|
if (fast)
|
||||||
{
|
mp_msg(MSGT_AO, MSGL_WARN,
|
||||||
|
"[AO PCM] Suboption \"fast\" is deprecated.\n"
|
||||||
|
"[AO PCM] Use -novideo, or -benchmark if you want "
|
||||||
|
"faster playback with video.\n");
|
||||||
|
if (!priv->outputfilename)
|
||||||
|
priv->outputfilename =
|
||||||
|
strdup(priv->waveheader ? "audiodump.wav" : "audiodump.pcm");
|
||||||
|
if (priv->waveheader) {
|
||||||
// WAV files must have one of the following formats
|
// WAV files must have one of the following formats
|
||||||
|
|
||||||
switch(format){
|
switch (ao->format) {
|
||||||
case AF_FORMAT_U8:
|
case AF_FORMAT_U8:
|
||||||
case AF_FORMAT_S16_LE:
|
case AF_FORMAT_S16_LE:
|
||||||
case AF_FORMAT_S24_LE:
|
case AF_FORMAT_S24_LE:
|
||||||
|
@ -168,110 +160,97 @@ static int init(int rate,int channels,int format,int flags){
|
||||||
case AF_FORMAT_AC3_LE:
|
case AF_FORMAT_AC3_LE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
format = AF_FORMAT_S16_LE;
|
ao->format = AF_FORMAT_S16_LE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ao_data.outburst = 65536;
|
ao->outburst = 65536;
|
||||||
ao_data.buffersize= 2*65536;
|
ao->buffersize = 2 * 65536;
|
||||||
ao_data.channels=channels;
|
ao->bps = ao->channels * ao->samplerate * (af_fmt2bits(ao->format) / 8);
|
||||||
ao_data.samplerate=rate;
|
|
||||||
ao_data.format=format;
|
|
||||||
ao_data.bps=channels*rate*(af_fmt2bits(format)/8);
|
|
||||||
|
|
||||||
mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\nPCM: Samplerate: %iHz Channels: %s Format %s\n", ao_outputfilename,
|
mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\n"
|
||||||
(ao_pcm_waveheader?"WAVE":"RAW PCM"), rate,
|
"PCM: Samplerate: %d Hz Channels: %d Format: %s\n",
|
||||||
(channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
|
priv->outputfilename,
|
||||||
mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] Info: Faster dumping is achieved with -novideo -ao pcm:fast\n[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n");
|
priv->waveheader ? "WAVE" : "RAW PCM", ao->samplerate,
|
||||||
|
ao->channels, af_fmt2str_short(ao->format));
|
||||||
|
mp_tmsg(MSGT_AO, MSGL_INFO,
|
||||||
|
"[AO PCM] Info: Faster dumping is achieved with -novideo\n"
|
||||||
|
"[AO PCM] Info: To write WAVE files use -ao pcm:waveheader (default).\n");
|
||||||
|
|
||||||
fp = fopen(ao_outputfilename, "wb");
|
priv->fp = fopen(priv->outputfilename, "wb");
|
||||||
if(fp) {
|
if (!priv->fp) {
|
||||||
if(ao_pcm_waveheader){ /* Reserve space for wave header */
|
mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n",
|
||||||
write_wave_header(fp, 0x7ffff000);
|
priv->outputfilename);
|
||||||
}
|
return -1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n",
|
if (priv->waveheader) // Reserve space for wave header
|
||||||
ao_outputfilename);
|
write_wave_header(ao, priv->fp, 0x7ffff000);
|
||||||
|
ao->untimed = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close audio device
|
// close audio device
|
||||||
static void uninit(int immed){
|
static void uninit(struct ao *ao, bool cut_audio)
|
||||||
|
{
|
||||||
|
struct priv *priv = ao->priv;
|
||||||
|
|
||||||
if(ao_pcm_waveheader){ /* Rewrite wave header */
|
if (priv->waveheader) { // Rewrite wave header
|
||||||
int broken_seek = 0;
|
bool broken_seek = false;
|
||||||
#ifdef __MINGW32__
|
#ifdef __MINGW32__
|
||||||
// Windows, in its usual idiocy "emulates" seeks on pipes so it always looks
|
// Windows, in its usual idiocy "emulates" seeks on pipes so it always
|
||||||
// like they work. So we have to detect them brute-force.
|
// looks like they work. So we have to detect them brute-force.
|
||||||
broken_seek = GetFileType((HANDLE)_get_osfhandle(_fileno(fp))) != FILE_TYPE_DISK;
|
broken_seek = FILE_TYPE_DISK !=
|
||||||
|
GetFileType((HANDLE)_get_osfhandle(_fileno(priv->fp)));
|
||||||
#endif
|
#endif
|
||||||
if (broken_seek || fseek(fp, 0, SEEK_SET) != 0)
|
if (broken_seek || fseek(priv->fp, 0, SEEK_SET) != 0)
|
||||||
mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, WAV size headers not updated!\n");
|
mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, "
|
||||||
|
"WAV size headers not updated!\n");
|
||||||
else {
|
else {
|
||||||
if (data_length > 0xfffff000) {
|
if (priv->data_length > 0xfffff000) {
|
||||||
mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for WAV files, may play truncated!\n");
|
mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for "
|
||||||
data_length = 0xfffff000;
|
"WAV files, may play truncated!\n");
|
||||||
|
priv->data_length = 0xfffff000;
|
||||||
}
|
}
|
||||||
write_wave_header(fp, data_length);
|
write_wave_header(ao, priv->fp, priv->data_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(priv->fp);
|
||||||
free(ao_outputfilename);
|
free(priv->outputfilename);
|
||||||
ao_outputfilename = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop playing and empty buffers (for seeking/pause)
|
static int get_space(struct ao *ao)
|
||||||
static void reset(void){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop playing, keep buffers (for pause)
|
|
||||||
static void audio_pause(void)
|
|
||||||
{
|
{
|
||||||
// for now, just call reset();
|
return ao->outburst;
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resume playing, after audio_pause()
|
static int play(struct ao *ao, void *data, int len, int flags)
|
||||||
static void audio_resume(void)
|
|
||||||
{
|
{
|
||||||
}
|
struct priv *priv = ao->priv;
|
||||||
|
|
||||||
// return: how many bytes can be played without blocking
|
if (ao->channels == 5 || ao->channels == 6 || ao->channels == 8) {
|
||||||
static int get_space(void){
|
int frame_size = af_fmt2bits(ao->format) / 8;
|
||||||
|
len -= len % (frame_size * ao->channels);
|
||||||
if(vo_pts)
|
|
||||||
return ao_data.pts < vo_pts + fast * 30000 ? ao_data.outburst : 0;
|
|
||||||
return ao_data.outburst;
|
|
||||||
}
|
|
||||||
|
|
||||||
// plays 'len' bytes of 'data'
|
|
||||||
// it should round it down to outburst*n
|
|
||||||
// return: number of bytes played
|
|
||||||
static int play(void* data,int len,int flags){
|
|
||||||
|
|
||||||
if (ao_data.channels == 5 || ao_data.channels == 6 || ao_data.channels == 8) {
|
|
||||||
int frame_size = af_fmt2bits(ao_data.format) / 8;
|
|
||||||
len -= len % (frame_size * ao_data.channels);
|
|
||||||
reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
|
reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
|
||||||
AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
|
AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT,
|
||||||
ao_data.channels,
|
ao->channels, len / frame_size, frame_size);
|
||||||
len / frame_size, frame_size);
|
|
||||||
}
|
}
|
||||||
|
fwrite(data, len, 1, priv->fp);
|
||||||
//printf("PCM: Writing chunk!\n");
|
priv->data_length += len;
|
||||||
fwrite(data,len,1,fp);
|
|
||||||
|
|
||||||
if(ao_pcm_waveheader)
|
|
||||||
data_length += len;
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return: delay in seconds between first and last sample in buffer
|
const struct ao_driver audio_out_pcm = {
|
||||||
static float get_delay(void){
|
.is_new = true,
|
||||||
|
.info = &(const struct ao_info) {
|
||||||
return 0.0;
|
"RAW PCM/WAVE file writer audio output",
|
||||||
}
|
"pcm",
|
||||||
|
"Atmosfear",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
.init = init,
|
||||||
|
.uninit = uninit,
|
||||||
|
.get_space = get_space,
|
||||||
|
.play = play,
|
||||||
|
};
|
||||||
|
|
|
@ -236,6 +236,10 @@ int ao_control(struct ao *ao, int cmd, void *arg)
|
||||||
|
|
||||||
double ao_get_delay(struct ao *ao)
|
double ao_get_delay(struct ao *ao)
|
||||||
{
|
{
|
||||||
|
if (!ao->driver->get_delay) {
|
||||||
|
assert(ao->untimed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return ao->driver->get_delay(ao);
|
return ao->driver->get_delay(ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,17 +250,20 @@ int ao_get_space(struct ao *ao)
|
||||||
|
|
||||||
void ao_reset(struct ao *ao)
|
void ao_reset(struct ao *ao)
|
||||||
{
|
{
|
||||||
ao->driver->reset(ao);
|
if (ao->driver->reset)
|
||||||
|
ao->driver->reset(ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ao_pause(struct ao *ao)
|
void ao_pause(struct ao *ao)
|
||||||
{
|
{
|
||||||
ao->driver->pause(ao);
|
if (ao->driver->pause)
|
||||||
|
ao->driver->pause(ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ao_resume(struct ao *ao)
|
void ao_resume(struct ao *ao)
|
||||||
{
|
{
|
||||||
ao->driver->resume(ao);
|
if (ao->driver->resume)
|
||||||
|
ao->driver->resume(ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct ao {
|
||||||
int buffersize;
|
int buffersize;
|
||||||
int pts;
|
int pts;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
bool untimed;
|
||||||
const struct ao_driver *driver;
|
const struct ao_driver *driver;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
11
mplayer.c
11
mplayer.c
|
@ -2048,7 +2048,7 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time) {
|
||||||
struct MPOpts *opts = &mpctx->opts;
|
struct MPOpts *opts = &mpctx->opts;
|
||||||
// check for frame-drop:
|
// check for frame-drop:
|
||||||
current_module = "check_framedrop";
|
current_module = "check_framedrop";
|
||||||
if (mpctx->sh_audio && !mpctx->d_audio->eof) {
|
if (mpctx->sh_audio && !mpctx->ao->untimed && !mpctx->d_audio->eof) {
|
||||||
static int dropped_frames;
|
static int dropped_frames;
|
||||||
float delay = opts->playback_speed * ao_get_delay(mpctx->ao);
|
float delay = opts->playback_speed * ao_get_delay(mpctx->ao);
|
||||||
float d = delay-mpctx->delay;
|
float d = delay-mpctx->delay;
|
||||||
|
@ -2411,6 +2411,9 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
|
||||||
|
|
||||||
current_module="play_audio";
|
current_module="play_audio";
|
||||||
|
|
||||||
|
if (ao->untimed && mpctx->sh_video && mpctx->delay > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// all the current uses of ao->pts seem to be in aos that handle
|
// all the current uses of ao->pts seem to be in aos that handle
|
||||||
// sync completely wrong; there should be no need to use ao->pts
|
// sync completely wrong; there should be no need to use ao->pts
|
||||||
// in get_space()
|
// in get_space()
|
||||||
|
@ -3366,7 +3369,7 @@ static void run_playloop(struct MPContext *mpctx)
|
||||||
if (mpctx->sh_audio && !mpctx->paused
|
if (mpctx->sh_audio && !mpctx->paused
|
||||||
&& (!mpctx->restart_playback || !mpctx->sh_video)) {
|
&& (!mpctx->restart_playback || !mpctx->sh_video)) {
|
||||||
int status = fill_audio_out_buffers(mpctx);
|
int status = fill_audio_out_buffers(mpctx);
|
||||||
full_audio_buffers = status >= 0;
|
full_audio_buffers = status >= 0 && !mpctx->ao->untimed;
|
||||||
if (status == -2)
|
if (status == -2)
|
||||||
// at eof, all audio at least written to ao
|
// at eof, all audio at least written to ao
|
||||||
if (!mpctx->sh_video)
|
if (!mpctx->sh_video)
|
||||||
|
@ -3412,7 +3415,9 @@ static void run_playloop(struct MPContext *mpctx)
|
||||||
} else if (!mpctx->stop_play) {
|
} else if (!mpctx->stop_play) {
|
||||||
int sleep_time = 100;
|
int sleep_time = 100;
|
||||||
if (mpctx->sh_audio) {
|
if (mpctx->sh_audio) {
|
||||||
if (full_audio_buffers)
|
if (mpctx->ao->untimed)
|
||||||
|
sleep_time = 0;
|
||||||
|
else if (full_audio_buffers)
|
||||||
sleep_time = FFMAX(20, a_buf * 1000 - 50);
|
sleep_time = FFMAX(20, a_buf * 1000 - 50);
|
||||||
else
|
else
|
||||||
sleep_time = 20;
|
sleep_time = 20;
|
||||||
|
|
Loading…
Reference in New Issue