diff options
author | Uoti Urpala <uau@mplayer2.org> | 2011-05-05 21:34:17 +0300 |
---|---|---|
committer | Uoti Urpala <uau@mplayer2.org> | 2011-05-05 21:34:17 +0300 |
commit | 40f6ab5064a628dc11b79b5e571dc9444efac093 (patch) | |
tree | d5217e4e08b5a8ebd16c323c69df2b45c85222ed /libao2 | |
parent | 2fae42d00e7f8a4a8e0e39bd5e84836a26d3755a (diff) | |
download | mpv-40f6ab5064a628dc11b79b5e571dc9444efac093.tar.bz2 mpv-40f6ab5064a628dc11b79b5e571dc9444efac093.tar.xz |
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.
Diffstat (limited to 'libao2')
-rw-r--r-- | libao2/ao_pcm.c | 249 | ||||
-rw-r--r-- | libao2/audio_out.c | 13 | ||||
-rw-r--r-- | libao2/audio_out.h | 1 |
3 files changed, 125 insertions, 138 deletions
diff --git a/libao2/ao_pcm.c b/libao2/ao_pcm.c index 64eda888f7..20399152c5 100644 --- a/libao2/ao_pcm.c +++ b/libao2/ao_pcm.c @@ -24,13 +24,14 @@ #include <stdlib.h> #include <string.h> -#include "libavutil/common.h" -#include "mpbswap.h" +#include <libavutil/common.h> + +#include "talloc.h" + #include "subopt-helper.h" #include "libaf/af_format.h" #include "libaf/reorder_ch.h" #include "audio_out.h" -#include "audio_out_internal.h" #include "mp_msg.h" #ifdef __MINGW32__ @@ -38,22 +39,13 @@ #include <windows.h> #endif -static const ao_info_t info = -{ - "RAW PCM/WAVE file writer audio output", - "pcm", - "Atmosfear", - "" +struct priv { + char *outputfilename; + int waveheader; + uint64_t data_length; + 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_WAVE 0x45564157 /* "WAVE" */ #define WAV_ID_FMT 0x20746d66 /* "fmt " */ @@ -62,30 +54,30 @@ static int fast = 0; #define WAV_ID_FLOAT_PCM 0x0003 #define WAV_ID_FORMAT_EXTENSIBLE 0xfffe -/* init with default values */ -static uint64_t data_length; -static FILE *fp = NULL; - - -static void fput16le(uint16_t val, FILE *fp) { +static void fput16le(uint16_t val, FILE *fp) +{ uint8_t bytes[2] = {val, val >> 8}; 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}; fwrite(bytes, 1, 4, fp); } -static void write_wave_header(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; +static void write_wave_header(struct ao *ao, FILE *fp, uint64_t data_length) +{ + 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; - int bits = af_fmt2bits(ao_data.format); + int bits = af_fmt2bits(ao->format); // Master RIFF chunk 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(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(fmt_chunk_size, fp); fput16le(use_waveex ? WAV_ID_FORMAT_EXTENSIBLE : fmt, fp); - fput16le(ao_data.channels, fp); - fput32le(ao_data.samplerate, fp); - fput32le(ao_data.bps, fp); - fput16le(ao_data.channels * (bits / 8), fp); + fput16le(ao->channels, fp); + fput32le(ao->samplerate, fp); + fput32le(ao->bps, fp); + fput16le(ao->channels * (bits / 8), fp); fput16le(bits, fp); if (use_waveex) { // Extension chunk fput16le(22, fp); fput16le(bits, fp); - switch (ao_data.channels) { + switch (ao->channels) { case 5: fput32le(0x0607, fp); // L R C Lb Rb break; @@ -129,36 +121,36 @@ static void write_wave_header(FILE *fp, uint64_t data_length) { fput32le(data_length, fp); } -// to set/get/query special features/parameters -static int control(int cmd,void *arg){ - return -1; -} +static int init(struct ao *ao, char *params) +{ + struct priv *priv = talloc_zero(ao, struct priv); + ao->priv = priv; -// open & setup audio device -// return: 1=success 0=fail -static int init(int rate,int channels,int format,int flags){ + int fast; const opt_t subopts[] = { - {"waveheader", OPT_ARG_BOOL, &ao_pcm_waveheader, NULL}, - {"file", OPT_ARG_MSTRZ, &ao_outputfilename, NULL}, - {"fast", OPT_ARG_BOOL, &fast, NULL}, + {"waveheader", OPT_ARG_BOOL, &priv->waveheader, NULL}, + {"file", OPT_ARG_MSTRZ, &priv->outputfilename, NULL}, + {"fast", OPT_ARG_BOOL, &fast, NULL}, {NULL} }; // set defaults - ao_pcm_waveheader = 1; - - if (subopt_parse(ao_subdevice, subopts) != 0) { - return 0; - } - if (!ao_outputfilename){ - ao_outputfilename = - strdup(ao_pcm_waveheader?"audiodump.wav":"audiodump.pcm"); - } - - if (ao_pcm_waveheader) - { + priv->waveheader = 1; + + if (subopt_parse(params, subopts) != 0) + return -1; + + 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 - switch(format){ + switch (ao->format) { case AF_FORMAT_U8: case AF_FORMAT_S16_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: break; default: - format = AF_FORMAT_S16_LE; + ao->format = AF_FORMAT_S16_LE; break; } } - ao_data.outburst = 65536; - ao_data.buffersize= 2*65536; - ao_data.channels=channels; - 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, - (ao_pcm_waveheader?"WAVE":"RAW PCM"), rate, - (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); - 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"); - - fp = fopen(ao_outputfilename, "wb"); - if(fp) { - if(ao_pcm_waveheader){ /* Reserve space for wave header */ - write_wave_header(fp, 0x7ffff000); - } - return 1; + ao->outburst = 65536; + ao->buffersize = 2 * 65536; + ao->bps = ao->channels * ao->samplerate * (af_fmt2bits(ao->format) / 8); + + mp_tmsg(MSGT_AO, MSGL_INFO, "[AO PCM] File: %s (%s)\n" + "PCM: Samplerate: %d Hz Channels: %d Format: %s\n", + priv->outputfilename, + 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"); + + priv->fp = fopen(priv->outputfilename, "wb"); + if (!priv->fp) { + mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n", + priv->outputfilename); + return -1; } - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO PCM] Failed to open %s for writing!\n", - ao_outputfilename); + if (priv->waveheader) // Reserve space for wave header + write_wave_header(ao, priv->fp, 0x7ffff000); + ao->untimed = true; + return 0; } // 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 */ - int broken_seek = 0; + if (priv->waveheader) { // Rewrite wave header + bool broken_seek = false; #ifdef __MINGW32__ - // Windows, in its usual idiocy "emulates" seeks on pipes so it always looks - // like they work. So we have to detect them brute-force. - broken_seek = GetFileType((HANDLE)_get_osfhandle(_fileno(fp))) != FILE_TYPE_DISK; + // Windows, in its usual idiocy "emulates" seeks on pipes so it always + // looks like they work. So we have to detect them brute-force. + broken_seek = FILE_TYPE_DISK != + GetFileType((HANDLE)_get_osfhandle(_fileno(priv->fp))); #endif - if (broken_seek || fseek(fp, 0, SEEK_SET) != 0) - mp_msg(MSGT_AO, MSGL_ERR, "Could not seek to start, WAV size headers not updated!\n"); + 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"); else { - if (data_length > 0xfffff000) { - mp_msg(MSGT_AO, MSGL_ERR, "File larger than allowed for WAV files, may play truncated!\n"); - 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"); + priv->data_length = 0xfffff000; } - write_wave_header(fp, data_length); + write_wave_header(ao, priv->fp, priv->data_length); } } - fclose(fp); - free(ao_outputfilename); - ao_outputfilename = NULL; + fclose(priv->fp); + free(priv->outputfilename); } -// stop playing and empty buffers (for seeking/pause) -static void reset(void){ - -} - -// stop playing, keep buffers (for pause) -static void audio_pause(void) +static int get_space(struct ao *ao) { - // for now, just call reset(); - reset(); + return ao->outburst; } -// resume playing, after audio_pause() -static void audio_resume(void) +static int play(struct ao *ao, void *data, int len, int flags) { -} - -// return: how many bytes can be played without blocking -static int get_space(void){ + struct priv *priv = ao->priv; - 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); + if (ao->channels == 5 || ao->channels == 6 || ao->channels == 8) { + int frame_size = af_fmt2bits(ao->format) / 8; + len -= len % (frame_size * ao->channels); reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT, AF_CHANNEL_LAYOUT_WAVEEX_DEFAULT, - ao_data.channels, - len / frame_size, frame_size); + ao->channels, len / frame_size, frame_size); } - - //printf("PCM: Writing chunk!\n"); - fwrite(data,len,1,fp); - - if(ao_pcm_waveheader) - data_length += len; - + fwrite(data, len, 1, priv->fp); + priv->data_length += len; return len; } -// return: delay in seconds between first and last sample in buffer -static float get_delay(void){ - - return 0.0; -} +const struct ao_driver audio_out_pcm = { + .is_new = true, + .info = &(const struct ao_info) { + "RAW PCM/WAVE file writer audio output", + "pcm", + "Atmosfear", + "", + }, + .init = init, + .uninit = uninit, + .get_space = get_space, + .play = play, +}; diff --git a/libao2/audio_out.c b/libao2/audio_out.c index da471f0cc7..699ae7071b 100644 --- a/libao2/audio_out.c +++ b/libao2/audio_out.c @@ -236,6 +236,10 @@ int ao_control(struct ao *ao, int cmd, void *arg) double ao_get_delay(struct ao *ao) { + if (!ao->driver->get_delay) { + assert(ao->untimed); + return 0; + } return ao->driver->get_delay(ao); } @@ -246,17 +250,20 @@ int ao_get_space(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) { - ao->driver->pause(ao); + if (ao->driver->pause) + ao->driver->pause(ao); } void ao_resume(struct ao *ao) { - ao->driver->resume(ao); + if (ao->driver->resume) + ao->driver->resume(ao); } diff --git a/libao2/audio_out.h b/libao2/audio_out.h index c60819e545..fb62923297 100644 --- a/libao2/audio_out.h +++ b/libao2/audio_out.h @@ -72,6 +72,7 @@ struct ao { int buffersize; int pts; bool initialized; + bool untimed; const struct ao_driver *driver; void *priv; }; |