diff options
author | 2012-05-20 11:42:44 +0200 | |
---|---|---|
committer | 2012-05-20 11:42:44 +0200 | |
commit | 2793e7eb70a342b346788f83e1ed660c8e0d491e (patch) | |
tree | fe62d4ab03de24c568244b66f10990e09af3a370 | |
parent | 4488583dda2754a2e71ec991e9541bcc2c259da3 (diff) | |
parent | f63dbaddb6de6add6d987dc28ca8771aca230451 (diff) |
Merge remote-tracking branch 'origin/master'
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | cfg-mplayer.h | 3 | ||||
-rwxr-xr-x | configure | 182 | ||||
-rw-r--r-- | input/input.c | 16 | ||||
-rw-r--r-- | libao2/ao_arts.c | 148 | ||||
-rw-r--r-- | libao2/ao_esd.c | 477 | ||||
-rw-r--r-- | libao2/ao_portaudio.c | 431 | ||||
-rw-r--r-- | libao2/ao_pulse.c | 2 | ||||
-rw-r--r-- | libao2/ao_sgi.c | 301 | ||||
-rw-r--r-- | libao2/audio_out.c | 11 | ||||
-rw-r--r-- | libmpcodecs/ad_mpg123.c | 248 | ||||
-rw-r--r-- | m_config.c | 116 | ||||
-rw-r--r-- | m_config.h | 5 | ||||
-rw-r--r-- | m_option.c | 457 | ||||
-rw-r--r-- | m_option.h | 71 | ||||
-rw-r--r-- | m_struct.c | 7 | ||||
-rw-r--r-- | mplayer.c | 38 | ||||
-rw-r--r-- | parser-mpcmd.c | 8 | ||||
-rw-r--r-- | parser-mpcmd.h | 3 | ||||
-rw-r--r-- | sub/font_load_ft.c | 2 |
20 files changed, 760 insertions, 1770 deletions
@@ -438,7 +438,6 @@ SRCS_MPLAYER-$(AA) += libvo/vo_aa.c SRCS_MPLAYER-$(ALSA) += libao2/ao_alsa.c SRCS_MPLAYER-$(APPLE_IR) += input/appleir.c SRCS_MPLAYER-$(APPLE_REMOTE) += input/ar.c -SRCS_MPLAYER-$(ARTS) += libao2/ao_arts.c SRCS_MPLAYER-$(BL) += libvo/vo_bl.c SRCS_MPLAYER-$(CACA) += libvo/vo_caca.c SRCS_MPLAYER-$(COREAUDIO) += libao2/ao_coreaudio.c @@ -449,7 +448,6 @@ SRCS_MPLAYER-$(DIRECT3D) += libvo/vo_direct3d.c libvo/w32_common.c SRCS_MPLAYER-$(DIRECTFB) += libvo/vo_directfb2.c libvo/vo_dfbmga.c SRCS_MPLAYER-$(DIRECTX) += libao2/ao_dsound.c libvo/vo_directx.c SRCS_MPLAYER-$(DXR3) += libvo/vo_dxr3.c -SRCS_MPLAYER-$(ESD) += libao2/ao_esd.c SRCS_MPLAYER-$(FBDEV) += libvo/vo_fbdev.c libvo/vo_fbdev2.c SRCS_MPLAYER-$(GGI) += libvo/vo_ggi.c SRCS_MPLAYER-$(GIF) += libvo/vo_gif89a.c @@ -471,10 +469,10 @@ SRCS_MPLAYER-$(OPENAL) += libao2/ao_openal.c SRCS_MPLAYER-$(OSS) += libao2/ao_oss.c SRCS_MPLAYER-$(PNM) += libvo/vo_pnm.c SRCS_MPLAYER-$(PULSE) += libao2/ao_pulse.c +SRCS_MPLAYER-$(PORTAUDIO) += libao2/ao_portaudio.c SRCS_MPLAYER-$(RSOUND) += libao2/ao_rsound.c SRCS_MPLAYER-$(S3FB) += libvo/vo_s3fb.c SRCS_MPLAYER-$(SDL) += libao2/ao_sdl.c libvo/vo_sdl.c libvo/sdl_common.c -SRCS_MPLAYER-$(SGIAUDIO) += libao2/ao_sgi.c SRCS_MPLAYER-$(SUNAUDIO) += libao2/ao_sun.c SRCS_MPLAYER-$(SVGA) += libvo/vo_svga.c SRCS_MPLAYER-$(TDFXFB) += libvo/vo_tdfxfb.c diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 1d18949ce0..b94b1cf7cc 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -373,7 +373,8 @@ const m_option_t common_opts[] = { // ------------------------- common options -------------------- OPT_MAKE_FLAGS("quiet", quiet, CONF_GLOBAL), {"really-quiet", &verbose, CONF_TYPE_FLAG, CONF_GLOBAL|CONF_PRE_PARSE, 0, -10, NULL}, - {"v", cfg_inc_verbose, CONF_TYPE_FUNC, CONF_GLOBAL|CONF_NOSAVE, 0, 0, NULL}, + // -v is handled in command line preparser + {"v", NULL, CONF_TYPE_FLAG, CONF_NOCFG, 0, 0, NULL}, {"msglevel", (void *) msgl_config, CONF_TYPE_SUBCONFIG, CONF_GLOBAL, 0, 0, NULL}, {"msgcolor", &mp_msg_color, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL}, {"nomsgcolor", &mp_msg_color, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL}, @@ -209,7 +209,6 @@ dragonfly() { issystem "DragonFly"; } freebsd() { issystem "FreeBSD" || issystem "GNU/kFreeBSD"; } gnu() { issystem "GNU"; } hpux() { issystem "HP-UX"; } -irix() { issystem "IRIX"; } linux() { issystem "Linux"; } mingw32() { issystem "MINGW32"; } morphos() { issystem "MorphOS"; } @@ -440,14 +439,12 @@ Video output: Audio output: --disable-alsa disable ALSA audio output [autodetect] --disable-ossaudio disable OSS audio output [autodetect] - --disable-arts disable aRts audio output [autodetect] - --disable-esd disable esd audio output [autodetect] --disable-rsound disable RSound audio output [autodetect] --disable-pulse disable Pulseaudio audio output [autodetect] + --disable-portaudio disable PortAudio audio output [autodetect] --disable-jack disable JACK audio output [autodetect] --enable-openal enable OpenAL audio output [disable] --disable-nas disable NAS audio output [autodetect] - --disable-sgiaudio disable SGI audio output [autodetect] --disable-sunaudio disable Sun audio output [autodetect] --disable-win32waveout disable Windows waveout audio output [autodetect] --disable-coreaudio disable CoreAudio audio output [autodetect] @@ -599,10 +596,9 @@ _iconv=auto _langinfo=auto _rtc=auto _ossaudio=auto -_arts=auto -_esd=auto _rsound=auto _pulse=auto +_portaudio=auto _jack=auto _openal=no _libcdio=auto @@ -637,7 +633,6 @@ _mga=auto _xmga=auto _vm=auto _xf86keysym=auto -_sgiaudio=auto _sunaudio=auto _alsa=auto _fastmemcpy=yes @@ -918,14 +913,12 @@ for ac_option do --disable-libdv) _libdv=no ;; --enable-ossaudio) _ossaudio=yes ;; --disable-ossaudio) _ossaudio=no ;; - --enable-arts) _arts=yes ;; - --disable-arts) _arts=no ;; - --enable-esd) _esd=yes ;; - --disable-esd) _esd=no ;; --enable-rsound) _rsound=yes ;; --disable-rsound) _rsound=no ;; --enable-pulse) _pulse=yes ;; --disable-pulse) _pulse=no ;; + --enable-portaudio) _portaudio=yes ;; + --disable-portaudio) _portaudio=no ;; --enable-jack) _jack=yes ;; --disable-jack) _jack=no ;; --enable-openal) _openal=yes ;; @@ -992,8 +985,6 @@ for ac_option do --disable-xf86keysym) _xf86keysym=no ;; --enable-sunaudio) _sunaudio=yes ;; --disable-sunaudio) _sunaudio=no ;; - --enable-sgiaudio) _sgiaudio=yes ;; - --disable-sgiaudio) _sgiaudio=no ;; --enable-alsa) _alsa=yes ;; --disable-alsa) _alsa=no ;; --enable-tv) _tv=yes ;; @@ -1254,9 +1245,6 @@ if test -z "$_target" ; then Haiku) system_name=BeOS ;; - IRIX*) - system_name=IRIX - ;; GNU/kFreeBSD) system_name=FreeBSD ;; @@ -1355,9 +1343,6 @@ fi if darwin; then extra_cflags="-mdynamic-no-pic $extra_cflags" - if test "$(basename $_cc)" != "clang" ; then - extra_cflags="-falign-loops=16 -shared-libgcc $extra_cflags" - fi _timer=timer-darwin.c fi @@ -1365,9 +1350,7 @@ if aix ; then extra_ldflags="$extra_ldflags -lC" fi -if irix ; then - _ranlib='ar -r' -elif linux ; then +if linux ; then _ranlib='true' fi @@ -2169,24 +2152,6 @@ EOF arch='mips' iproc='mips' - if irix ; then - echocheck "CPU type" - proc=$(hinv -c processor | grep CPU | cut -d " " -f3) - case "$(echo $proc)" in - R3000) _march='-mips1' _mcpu='-mtune=r2000' ;; - R4000) _march='-mips3' _mcpu='-mtune=r4000' ;; - R4400) _march='-mips3' _mcpu='-mtune=r4400' ;; - R4600) _march='-mips3' _mcpu='-mtune=r4600' ;; - R5000) _march='-mips4' _mcpu='-mtune=r5000' ;; - R8000|R10000|R12000|R14000|R16000) _march='-mips4' _mcpu='-mtune=r8000' ;; - esac - # gcc < 3.x does not support -mtune. - if test "$cc_vendor" = "gnu" && test "$_cc_major" -lt 3 ; then - _mcpu='' - fi - echores "$proc" - fi - test $_fast_clz = "auto" && _fast_clz=yes ;; @@ -2339,6 +2304,10 @@ else warn_cflags=yes fi +if darwin && test "$cc_vendor" = "gnu" ; then + extra_cflags="-falign-loops=16 -shared-libgcc $extra_cflags" +fi + if test "$cc_vendor" = "gnu" ; then cflag_check -Wundef && WARNFLAGS="-Wundef $WARNFLAGS" # -std=gnu99 is not a warning flag but is placed in WARN_CFLAGS because @@ -4004,12 +3973,11 @@ echocheck "VDPAU" if test "$_vdpau" = auto && test "$_x11" = yes ; then _vdpau=no if test "$_dl" = yes ; then - return_statement_check vdpau/vdpau_x11.h 'vdp_device_create_x11(0, 0, 0, 0)' VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 -lvdpau && _vdpau=yes + pkg_config_add 'vdpau >= 0.2' && _vdpau=yes fi fi if test "$_vdpau" = yes ; then def_vdpau='#define CONFIG_VDPAU 1' - libs_mplayer="$libs_mplayer -lvdpau" vomodules="vdpau $vomodules" else def_vdpau='#define CONFIG_VDPAU 0' @@ -4274,11 +4242,6 @@ fi echocheck "PNG support" if test "$_png" = auto ; then _png=no - if irix ; then - # Don't check for -lpng on irix since it has its own libpng - # incompatible with the GNU libpng - res_comment="disabled on irix (not GNU libpng)" - else cat > $TMPC << EOF #include <stdio.h> #include <string.h> @@ -4289,8 +4252,7 @@ int main(void) { return strcmp(PNG_LIBPNG_VER_STRING, png_libpng_ver); } EOF - cc_check -lpng -lz $_ld_lm && _png=yes - fi + cc_check -lpng -lz $_ld_lm && _png=yes fi echores "$_png" if test "$_png" = yes ; then @@ -4561,15 +4523,17 @@ int main(int argc, char *argv[]) { } EOF _gl=no - for _ld_tmp in "" -lGL "-lGL -lXdamage" "-lGL $_ld_pthread" ; do - if cc_check $_ld_tmp $_ld_lm ; then - _gl=yes - _gl_x11=yes - libs_mplayer="$libs_mplayer $_ld_tmp $_ld_dl" - break - fi - done - if cc_check -DGL_WIN32 -lopengl32 ; then + if test "$_x11" = yes ; then + for _ld_tmp in "" -lGL "-lGL -lXdamage" "-lGL $_ld_pthread" ; do + if cc_check $_ld_tmp $_ld_lm ; then + _gl=yes + _gl_x11=yes + libs_mplayer="$libs_mplayer $_ld_tmp $_ld_dl" + break + fi + done + fi + if win32 && cc_check -DGL_WIN32 -lopengl32 ; then _gl=yes _gl_win32=yes libs_mplayer="$libs_mplayer -lopengl32 -lgdi32" @@ -4806,51 +4770,6 @@ fi echores "$_ossaudio" -echocheck "aRts" -if test "$_arts" = auto ; then - _arts=no - if ( artsc-config --version ) >> "$TMPLOG" 2>&1 ; then - statement_check artsc.h 'arts_init()' $(artsc-config --libs) $(artsc-config --cflags) && - _arts=yes - fi -fi - -if test "$_arts" = yes ; then - def_arts='#define CONFIG_ARTS 1' - aomodules="arts $aomodules" - libs_mplayer="$libs_mplayer $(artsc-config --libs)" - extra_cflags="$extra_cflags $(artsc-config --cflags)" -else - noaomodules="arts $noaomodules" -fi -echores "$_arts" - - -echocheck "EsounD" -if test "$_esd" = auto ; then - _esd=no - if ( esd-config --version ) >> "$TMPLOG" 2>&1 ; then - statement_check esd.h 'esd_open_sound("test")' $(esd-config --libs) $(esd-config --cflags) && _esd=yes - fi -fi -echores "$_esd" - -if test "$_esd" = yes ; then - def_esd='#define CONFIG_ESD 1' - aomodules="esd $aomodules" - libs_mplayer="$libs_mplayer $(esd-config --libs)" - extra_cflags="$extra_cflags $(esd-config --cflags)" - - echocheck "esd_get_latency()" - statement_check esd.h 'esd_get_latency(0)' $(esd-config --libs) $(esd-config --cflags) && - _esd_latency=yes && def_esd_latency='#define CONFIG_ESD_LATENCY 1' - echores "$_esd_latency" -else - def_esd='#undef CONFIG_ESD' - def_esd_latency='#undef CONFIG_ESD_LATENCY' - noaomodules="esd $noaomodules" -fi - echocheck "RSound" if test "$_rsound" = auto ; then _rsound=no @@ -4902,6 +4821,28 @@ else fi +echocheck "PortAudio" +if test "$_portaudio" = auto && test "$_pthreads" != yes ; then + _portaudio=no + res_comment="pthreads not enabled" +fi +if test "$_portaudio" = auto ; then + _portaudio=no + if pkg_config_add 'portaudio-2.0 >= 19' ; then + _portaudio=yes + fi +fi +echores "$_portaudio" + +if test "$_portaudio" = yes ; then + def_portaudio='#define CONFIG_PORTAUDIO 1' + aomodules="portaudio $aomodules" +else + def_portaudio='#undef CONFIG_PORTAUDIO' + noaomodules="portaudio $noaomodules" +fi + + echocheck "JACK" if test "$_jack" = auto ; then _jack=no @@ -5012,24 +4953,6 @@ echores $_coreaudio fi #if darwin -if irix; then -echocheck "SGI audio" -if test "$_sgiaudio" = auto ; then - _sgiaudio=no - header_check dmedia/audio.h && _sgiaudio=yes -fi -if test "$_sgiaudio" = "yes" ; then - def_sgiaudio='#define CONFIG_SGI_AUDIO 1' - libs_mplayer="$libs_mplayer -laudio" - aomodules="sgi $aomodules" -else - def_sgiaudio='#undef CONFIG_SGI_AUDIO' - noaomodules="sgi $noaomodules" -fi -echores "$_sgiaudio" -fi #if irix - - # set default CD/DVD devices if win32 ; then default_cdrom_device="D:" @@ -5085,11 +5008,10 @@ echores "$_vcd" echocheck "Blu-ray support" if test "$_bluray" = auto ; then _bluray=no - statement_check libbluray/bluray.h 'bd_get_title_info(0, 0, 0)' -lbluray && _bluray=yes + pkg_config_add 'libbluray >= 0.2.1' && _bluray=yes fi if test "$_bluray" = yes ; then def_bluray='#define CONFIG_LIBBLURAY 1' - extra_ldflags="$extra_ldflags -lbluray" inputmodules="bluray $inputmodules" else def_bluray='#undef CONFIG_LIBBLURAY' @@ -5411,12 +5333,13 @@ else fi echores "$_theora" -# Any version of libmpg123 shall be fine. +# Any version of libmpg123 that knows MPG123_RESYNC_LIMIT shall be fine. +# That is, 1.2.0 onwards. Recommened is 1.14 onwards, though. echocheck "mpg123 support" def_mpg123='#undef CONFIG_MPG123' if test "$_mpg123" = auto; then _mpg123=no - statement_check mpg123.h 'mpg123_init()' -lmpg123 && _mpg123=yes && extra_ldflags="$extra_ldflags -lmpg123" + pkg_config_add 'libmpg123 >= 1.2.0' && _mpg123=yes fi if test "$_mpg123" = yes ; then def_mpg123='#define CONFIG_MPG123 1' @@ -6379,7 +6302,6 @@ AA = $_aa ALSA = $_alsa APPLE_IR = $_apple_ir APPLE_REMOTE = $_apple_remote -ARTS = $_arts AUDIO_INPUT = $_audio_input BITMAP_FONT = $_bitmap_font BL = $_bl @@ -6400,7 +6322,6 @@ DVDNAV_INTERNAL = $dvdnav_internal DVDREAD = $_dvdread DVDREAD_INTERNAL = $_dvdread_internal DXR3 = $_dxr3 -ESD = $_esd FAAD = $_faad FASTMEMCPY = $_fastmemcpy FBDEV = $_fbdev @@ -6452,6 +6373,7 @@ PNG = $_png PNM = $_pnm PRIORITY = $_priority PULSE = $_pulse +PORTAUDIO = $_portaudio PVR = $_pvr QTX_CODECS = $_qtx QTX_CODECS_WIN32 = $_qtx_codecs_win32 @@ -6464,7 +6386,6 @@ S3FB = $_s3fb SDL = $_sdl SPEEX = $_speex STREAM_CACHE = $_stream_cache -SGIAUDIO = $_sgiaudio SUNAUDIO = $_sunaudio SVGA = $_svga TDFXFB = $_tdfxfb @@ -6717,10 +6638,7 @@ $def_xmms /* Audio output drivers */ $def_alsa -$def_arts $def_coreaudio -$def_esd -$def_esd_latency $def_jack $def_nas $def_openal @@ -6729,8 +6647,8 @@ $def_ossaudio $def_ossaudio_devdsp $def_ossaudio_devmixer $def_pulse +$def_portaudio $def_rsound -$def_sgiaudio $def_sunaudio $def_win32waveout diff --git a/input/input.c b/input/input.c index ffa69043f8..89eb847385 100644 --- a/input/input.c +++ b/input/input.c @@ -631,16 +631,16 @@ struct input_ctx { int async_quit_request; -static int print_key_list(m_option_t *cfg); -static int print_cmd_list(m_option_t *cfg); +static int print_key_list(m_option_t *cfg, char *optname, char *optparam); +static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam); // Our command line options static const m_option_t input_conf[] = { OPT_STRING("conf", input.config_file, CONF_GLOBAL), OPT_INT("ar-delay", input.ar_delay, CONF_GLOBAL), OPT_INT("ar-rate", input.ar_rate, CONF_GLOBAL), - { "keylist", print_key_list, CONF_TYPE_FUNC, CONF_GLOBAL, 0, 0, NULL }, - { "cmdlist", print_cmd_list, CONF_TYPE_FUNC, CONF_GLOBAL, 0, 0, NULL }, + { "keylist", print_key_list, CONF_TYPE_PRINT_FUNC, CONF_NOCFG }, + { "cmdlist", print_cmd_list, CONF_TYPE_PRINT_FUNC, CONF_NOCFG }, OPT_STRING("js-dev", input.js_dev, CONF_GLOBAL), OPT_STRING("ar-dev", input.ar_dev, CONF_GLOBAL), OPT_STRING("file", input.in_file, CONF_GLOBAL), @@ -1915,16 +1915,16 @@ void mp_input_register_options(m_config_t *cfg) m_config_register_options(cfg, mp_input_opts); } -static int print_key_list(m_option_t *cfg) +static int print_key_list(m_option_t *cfg, char *optname, char *optparam) { int i; printf("\n"); for (i = 0; key_names[i].name != NULL; i++) printf("%s\n", key_names[i].name); - exit(0); + return M_OPT_EXIT; } -static int print_cmd_list(m_option_t *cfg) +static int print_cmd_list(m_option_t *cfg, char *optname, char *optparam) { const mp_cmd_t *cmd; int i, j; @@ -1953,7 +1953,7 @@ static int print_cmd_list(m_option_t *cfg) } printf("\n"); } - exit(0); + return M_OPT_EXIT; } void mp_input_wakeup(struct input_ctx *ictx) diff --git a/libao2/ao_arts.c b/libao2/ao_arts.c deleted file mode 100644 index d828e7953e..0000000000 --- a/libao2/ao_arts.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * aRts audio output driver for MPlayer - * - * copyright (c) 2002 Michele Balistreri <brain87@gmx.net> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <artsc.h> -#include <stdio.h> - -#include "config.h" -#include "audio_out.h" -#include "audio_out_internal.h" -#include "libaf/af_format.h" -#include "mp_msg.h" - -#define OBTAIN_BITRATE(a) (((a != AF_FORMAT_U8) && (a != AF_FORMAT_S8)) ? 16 : 8) - -/* Feel free to experiment with the following values: */ -#define ARTS_PACKETS 10 /* Number of audio packets */ -#define ARTS_PACKET_SIZE_LOG2 11 /* Log2 of audio packet size */ - -static arts_stream_t stream; - -static const ao_info_t info = -{ - "aRts audio output", - "arts", - "Michele Balistreri <brain87@gmx.net>", - "" -}; - -LIBAO_EXTERN(arts) - -static int control(int cmd, void *arg) -{ - return CONTROL_UNKNOWN; -} - -static int init(int rate_hz, int channels, int format, int flags) -{ - int err; - int frag_spec; - - if( (err=arts_init()) ) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ARTS] %s\n", arts_error_text(err)); - return 0; - } - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ARTS] Connected to sound server.\n"); - - /* - * arts supports 8bit unsigned and 16bit signed sample formats - * (16bit apparently in little endian format, even in the case - * when artsd runs on a big endian cpu). - * - * Unsupported formats are translated to one of these two formats - * using mplayer's audio filters. - */ - switch (format) { - case AF_FORMAT_U8: - case AF_FORMAT_S8: - format = AF_FORMAT_U8; - break; - default: - format = AF_FORMAT_S16_LE; /* artsd always expects little endian?*/ - break; - } - - ao_data.format = format; - ao_data.channels = channels; - ao_data.samplerate = rate_hz; - ao_data.bps = (rate_hz*channels); - - if(format != AF_FORMAT_U8 && format != AF_FORMAT_S8) - ao_data.bps*=2; - - stream=arts_play_stream(rate_hz, OBTAIN_BITRATE(format), channels, "MPlayer"); - - if(stream == NULL) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ARTS] Unable to open a stream.\n"); - arts_free(); - return 0; - } - - /* Set the stream to blocking: it will not block anyway, but it seems */ - /* to be working better */ - arts_stream_set(stream, ARTS_P_BLOCKING, 1); - frag_spec = ARTS_PACKET_SIZE_LOG2 | ARTS_PACKETS << 16; - arts_stream_set(stream, ARTS_P_PACKET_SETTINGS, frag_spec); - ao_data.buffersize = arts_stream_get(stream, ARTS_P_BUFFER_SIZE); - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ARTS] Stream opened.\n"); - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ARTS] buffer size: %d\n", - ao_data.buffersize); - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ARTS] buffer size: %d\n", - arts_stream_get(stream, ARTS_P_PACKET_SIZE)); - - return 1; -} - -static void uninit(int immed) -{ - arts_close_stream(stream); - arts_free(); -} - -static int play(void* data,int len,int flags) -{ - return arts_write(stream, data, len); -} - -static void audio_pause(void) -{ -} - -static void audio_resume(void) -{ -} - -static void reset(void) -{ -} - -static int get_space(void) -{ - return arts_stream_get(stream, ARTS_P_BUFFER_SPACE); -} - -static float get_delay(void) -{ - return ((float) (ao_data.buffersize - arts_stream_get(stream, - ARTS_P_BUFFER_SPACE))) / ((float) ao_data.bps); -} diff --git a/libao2/ao_esd.c b/libao2/ao_esd.c deleted file mode 100644 index e7c6701aa0..0000000000 --- a/libao2/ao_esd.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * EsounD audio output driver for MPlayer - * - * copyright (c) 2002 Juergen Keil <jk@tools.de> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - - /* - * TODO / known problems: - * - does not work well when the esd daemon has autostandby disabled - * (workaround: run esd with option "-as 2" - fortunatelly this is - * the default) - * - plays noise on a linux 2.4.4 kernel with a SB16PCI card, when using - * a local tcp connection to the esd daemon; there is no noise when using - * a unix domain socket connection. - * (there are EIO errors reported by the sound card driver, so this is - * most likely a linux sound card driver problem) - */ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <time.h> -#ifdef __svr4__ -#include <stropts.h> -#endif -#include <esd.h> - -#include "config.h" -#include "audio_out.h" -#include "audio_out_internal.h" -#include "libaf/af_format.h" -#include "mp_msg.h" - - -#define ESD_RESAMPLES 0 -#define ESD_DEBUG 0 - -#if ESD_DEBUG -#define dprintf(...) printf(__VA_ARGS__) -#else -#define dprintf(...) /**/ -#endif - - -#define ESD_CLIENT_NAME "MPlayer" -#define ESD_MAX_DELAY (1.0f) /* max amount of data buffered in esd (#sec) */ - -static const ao_info_t info = -{ - "EsounD audio output", - "esd", - "Juergen Keil <jk@tools.de>", - "" -}; - -LIBAO_EXTERN(esd) - -static int esd_fd = -1; -static int esd_play_fd = -1; -static esd_server_info_t *esd_svinfo; -static int esd_latency; -static int esd_bytes_per_sample; -static unsigned long esd_samples_written; -static struct timeval esd_play_start; -extern float audio_delay; - -/* - * to set/get/query special features/parameters - */ -static int control(int cmd, void *arg) -{ - esd_player_info_t *esd_pi; - esd_info_t *esd_i; - time_t now; - static time_t vol_cache_time; - static ao_control_vol_t vol_cache; - - switch (cmd) { - case AOCONTROL_GET_VOLUME: - time(&now); - if (now == vol_cache_time) { - *(ao_control_vol_t *)arg = vol_cache; - return CONTROL_OK; - } - - dprintf("esd: get vol\n"); - if ((esd_i = esd_get_all_info(esd_fd)) == NULL) - return CONTROL_ERROR; - - for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) - if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0) - break; - - if (esd_pi != NULL) { - ao_control_vol_t *vol = (ao_control_vol_t *)arg; - vol->left = esd_pi->left_vol_scale * 100 / ESD_VOLUME_BASE; - vol->right = esd_pi->right_vol_scale * 100 / ESD_VOLUME_BASE; - - vol_cache = *vol; - vol_cache_time = now; - } - esd_free_all_info(esd_i); - - return CONTROL_OK; - - case AOCONTROL_SET_VOLUME: - dprintf("esd: set vol\n"); - if ((esd_i = esd_get_all_info(esd_fd)) == NULL) - return CONTROL_ERROR; - - for (esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) - if (strcmp(esd_pi->name, ESD_CLIENT_NAME) == 0) - break; - - if (esd_pi != NULL) { - ao_control_vol_t *vol = (ao_control_vol_t *)arg; - esd_set_stream_pan(esd_fd, esd_pi->source_id, - vol->left * ESD_VOLUME_BASE / 100, - vol->right * ESD_VOLUME_BASE / 100); - - vol_cache = *vol; - time(&vol_cache_time); - } - esd_free_all_info(esd_i); - return CONTROL_OK; - - default: - return CONTROL_UNKNOWN; - } -} - - -/* - * open & setup audio device - * return: 1=success 0=fail - */ -static int init(int rate_hz, int channels, int format, int flags) -{ - esd_format_t esd_fmt; - int bytes_per_sample; - int fl; - char *server = ao_subdevice; /* NULL for localhost */ - float lag_seconds, lag_net = 0., lag_serv; - struct timeval proto_start, proto_end; - - global_ao->no_persistent_volume = true; - - if (esd_fd < 0) { - esd_fd = esd_open_sound(server); - if (esd_fd < 0) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ESD] esd_open_sound failed: %s\n", - strerror(errno)); - return 0; - } - - /* get server info, and measure network latency */ - gettimeofday(&proto_start, NULL); - esd_svinfo = esd_get_server_info(esd_fd); - if(server) { - gettimeofday(&proto_end, NULL); - lag_net = (proto_end.tv_sec - proto_start.tv_sec) + - (proto_end.tv_usec - proto_start.tv_usec) / 1000000.0; - lag_net /= 2.0; /* round trip -> one way */ - } else - lag_net = 0.0; /* no network lag */ - - /* - if (esd_svinfo) { - mp_msg(MSGT_AO, MSGL_INFO, "AO: [esd] server info:\n"); - esd_print_server_info(esd_svinfo); - } - */ - } - - esd_fmt = ESD_STREAM | ESD_PLAY; - -#if ESD_RESAMPLES - /* let the esd daemon convert sample rate */ -#else - /* let mplayer's audio filter convert the sample rate */ - if (esd_svinfo != NULL) - rate_hz = esd_svinfo->rate; -#endif - ao_data.samplerate = rate_hz; - - /* EsounD can play mono or stereo */ - switch (channels) { - case 1: - esd_fmt |= ESD_MONO; - ao_data.channels = bytes_per_sample = 1; - break; - default: - esd_fmt |= ESD_STEREO; - ao_data.channels = bytes_per_sample = 2; - break; - } - - /* EsounD can play 8bit unsigned and 16bit signed native */ - switch (format) { - case AF_FORMAT_S8: - case AF_FORMAT_U8: - esd_fmt |= ESD_BITS8; - ao_data.format = AF_FORMAT_U8; - break; - default: - esd_fmt |= ESD_BITS16; - ao_data.format = AF_FORMAT_S16_NE; - bytes_per_sample *= 2; - break; - } - - /* modify audio_delay depending on esd_latency - * latency is number of samples @ 44.1khz stereo 16 bit - * adjust according to rate_hz & bytes_per_sample - */ -#ifdef CONFIG_ESD_LATENCY - esd_latency = esd_get_latency(esd_fd); -#else - esd_latency = ((channels == 1 ? 2 : 1) * ESD_DEFAULT_RATE * - (ESD_BUF_SIZE + 64 * (4.0f / bytes_per_sample)) - ) / rate_hz; - esd_latency += ESD_BUF_SIZE * 2; -#endif - if(esd_latency > 0) { - lag_serv = (esd_latency * 4.0f) / (bytes_per_sample * rate_hz); - lag_seconds = lag_net + lag_serv; - audio_delay += lag_seconds; - mp_tmsg(MSGT_AO, MSGL_INFO,"[AO ESD] latency: [server: %0.2fs, net: %0.2fs] (adjust %0.2fs)\n", - lag_serv, lag_net, lag_seconds); - } - - esd_play_fd = esd_play_stream_fallback(esd_fmt, rate_hz, - server, ESD_CLIENT_NAME); - if (esd_play_fd < 0) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ESD] failed to open ESD playback stream: %s\n", strerror(errno)); - return 0; - } - - /* enable non-blocking i/o on the socket connection to the esd server */ - if ((fl = fcntl(esd_play_fd, F_GETFL)) >= 0) - fcntl(esd_play_fd, F_SETFL, O_NDELAY|fl); - -#if ESD_DEBUG - { - int sbuf, rbuf, len; - len = sizeof(sbuf); - getsockopt(esd_play_fd, SOL_SOCKET, SO_SNDBUF, &sbuf, &len); - len = sizeof(rbuf); - getsockopt(esd_play_fd, SOL_SOCKET, SO_RCVBUF, &rbuf, &len); - dprintf("esd: send/receive socket buffer space %d/%d bytes\n", - sbuf, rbuf); - } -#endif - - ao_data.bps = bytes_per_sample * rate_hz; - ao_data.outburst = ao_data.bps > 100000 ? 4*ESD_BUF_SIZE : 2*ESD_BUF_SIZE; - - esd_play_start.tv_sec = 0; - esd_samples_written = 0; - esd_bytes_per_sample = bytes_per_sample; - - return 1; -} - - -/* - * close audio device - */ -static void uninit(int immed) -{ - if (esd_play_fd >= 0) { - esd_close(esd_play_fd); - esd_play_fd = -1; - } - - if (esd_svinfo) { - esd_free_server_info(esd_svinfo); - esd_svinfo = NULL; - } - - if (esd_fd >= 0) { - esd_close(esd_fd); - esd_fd = -1; - } -} - - -/* - * 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) -{ - int offs; - int nwritten; - int nsamples; - int n; - - /* round down buffersize to a multiple of ESD_BUF_SIZE bytes */ - len = len / ESD_BUF_SIZE * ESD_BUF_SIZE; - if (len <= 0) - return 0; - -#define SINGLE_WRITE 0 -#if SINGLE_WRITE - nwritten = write(esd_play_fd, data, len); -#else - for (offs = 0, nwritten=0; offs + ESD_BUF_SIZE <= len; offs += ESD_BUF_SIZE) { - /* - * note: we're writing to a non-blocking socket here. - * A partial write means, that the socket buffer is full. - */ - n = write(esd_play_fd, (char*)data + offs, ESD_BUF_SIZE); - if ( n < 0 ) { - if ( errno != EAGAIN ) - dprintf("esd play: write failed: %s\n", strerror(errno)); - break; - } else if ( n != ESD_BUF_SIZE ) { - nwritten += n; - break; - } else - nwritten += n; - } -#endif - - if (nwritten > 0) { - if (!esd_play_start.tv_sec) - gettimeofday(&esd_play_start, NULL); - nsamples = nwritten / esd_bytes_per_sample; - esd_samples_written += nsamples; - - dprintf("esd play: %d %lu\n", nsamples, esd_samples_written); - } else { - dprintf("esd play: blocked / %lu\n", esd_samples_written); - } - - return nwritten; -} - - -/* - * stop playing, keep buffers (for pause) - */ -static void audio_pause(void) -{ - /* - * not possible with esd. the esd daemom will continue playing - * buffered data (not more than ESD_MAX_DELAY seconds of samples) - */ -} - - -/* - * resume playing, after audio_pause() - */ -static void audio_resume(void) -{ - /* - * not possible with esd. - * - * Let's hope the pause was long enough that the esd ran out of - * buffered data; we restart our time based delay computation - * for an audio resume. - */ - esd_play_start.tv_sec = 0; - esd_samples_written = 0; -} - - -/* - * stop playing and empty buffers (for seeking/pause) - */ -static void reset(void) -{ -#ifdef __svr4__ - /* throw away data buffered in the esd connection */ - if (ioctl(esd_play_fd, I_FLUSH, FLUSHW)) - perror("I_FLUSH"); -#endif -} - - -/* - * return: how many bytes can be played without blocking - */ -static int get_space(void) -{ - struct timeval tmout; - fd_set wfds; - float current_delay; - int space; - - /* - * Don't buffer too much data in the esd daemon. - * - * If we send too much, esd will block in write()s to the sound - * device, and the consequence is a huge slow down for things like - * esd_get_all_info(). - */ - if ((current_delay = get_delay()) >= ESD_MAX_DELAY) { - dprintf("esd get_space: too much data buffered\n"); - return 0; - } - - FD_ZERO(&wfds); - FD_SET(esd_play_fd, &wfds); - tmout.tv_sec = 0; - tmout.tv_usec = 0; - - if (select(esd_play_fd + 1, NULL, &wfds, NULL, &tmout) != 1) - return 0; - - if (!FD_ISSET(esd_play_fd, &wfds)) - return 0; - - /* try to fill 50% of the remaining "free" buffer space */ - space = (ESD_MAX_DELAY - current_delay) * ao_data.bps * 0.5f; - - /* round up to next multiple of ESD_BUF_SIZE */ - space = (space + ESD_BUF_SIZE-1) / ESD_BUF_SIZE * ESD_BUF_SIZE; - - dprintf("esd get_space: %d\n", space); - return space; -} - - -/* - * return: delay in seconds between first and last sample in buffer - */ -static float get_delay(void) -{ - struct timeval now; - double buffered_samples_time; - double play_time; - - if (!esd_play_start.tv_sec) - return 0; - - buffered_samples_time = (float)esd_samples_written / ao_data.samplerate; - gettimeofday(&now, NULL); - play_time = now.tv_sec - esd_play_start.tv_sec; - play_time += (now.tv_usec - esd_play_start.tv_usec) / 1000000.; - - /* dprintf("esd delay: %f %f\n", play_time, buffered_samples_time); */ - - if (play_time > buffered_samples_time) { - dprintf("esd: underflow\n"); - esd_play_start.tv_sec = 0; - esd_samples_written = 0; - return 0; - } - - dprintf("esd: get_delay %f\n", buffered_samples_time - play_time); - return buffered_samples_time - play_time; -} diff --git a/libao2/ao_portaudio.c b/libao2/ao_portaudio.c new file mode 100644 index 0000000000..c8275f0b38 --- /dev/null +++ b/libao2/ao_portaudio.c @@ -0,0 +1,431 @@ +/* + * This file is part of mplayer2. + * + * mplayer2 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mplayer2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mplayer2. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <pthread.h> + +#include <libavutil/avutil.h> +#include <portaudio.h> + +#include "config.h" +#include "subopt-helper.h" +#include "libaf/af_format.h" +#include "mp_msg.h" +#include "audio_out.h" + +struct priv { + PaStream *stream; + int framelen; + + pthread_mutex_t ring_mutex; + + // protected by ring_mutex + unsigned char *ring; + int ring_size; // max size of the ring + int read_pos; // points to first byte that can be read + int read_len; // number of bytes that can be read + double play_time; // time when last packet returned to PA is on speaker + // 0 is N/A (0 is not a valid PA time value) + int play_silence; // play this many bytes of silence, before real data + bool play_remaining;// play what's left in the buffer, then stop stream +}; + +struct format_map { + int mp_format; + PaSampleFormat pa_format; +}; + +static const struct format_map format_maps[] = { + // first entry is the default format + {AF_FORMAT_S16_NE, paInt16}, + {AF_FORMAT_S24_NE, paInt24}, + {AF_FORMAT_S32_NE, paInt32}, + {AF_FORMAT_S8, paInt8}, + {AF_FORMAT_U8, paUInt8}, + {AF_FORMAT_FLOAT_NE, paFloat32}, + {AF_FORMAT_UNKNOWN, 0} +}; + +static void print_help(void) +{ + mp_msg(MSGT_AO, MSGL_FATAL, + "\n-ao portaudio commandline help:\n" + "Example: mplayer -ao portaudio:device=subdevice\n" + "\nOptions:\n" + " device=subdevice\n" + " Audio device PortAudio should use. Devices can be listed\n" + " with -ao portaudio:device=help\n" + " The subdevice can be passed as index, or as complete name.\n"); +} + +static bool check_pa_ret(int ret) +{ + if (ret < 0) { + mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] %s\n", + Pa_GetErrorText(ret)); + if (ret == paUnanticipatedHostError) { + const PaHostErrorInfo* hosterr = Pa_GetLastHostErrorInfo(); + mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] Host error: %s\n", + hosterr->errorText); + } + return false; + } + return true; +} + +// Amount of bytes that contain audio of the given duration, aligned to frames. +static int seconds_to_bytes(struct ao *ao, double duration_seconds) +{ + struct priv *priv = ao->priv; + + int bytes = duration_seconds * ao->bps; + if (bytes % priv->framelen) + bytes += priv->framelen - (bytes % priv->framelen); + return bytes; +} + +static int to_int(const char *s, int return_on_error) +{ + char *endptr; + int res = strtol(s, &endptr, 10); + return (s[0] && !endptr[0]) ? res : return_on_error; +} + +static int find_device(struct ao *ao, const char *name) +{ + int help = strcmp(name, "help") == 0; + int count = Pa_GetDeviceCount(); + check_pa_ret(count); + int found = paNoDevice; + int index = to_int(name, -1); + if (help) + mp_msg(MSGT_AO, MSGL_INFO, "PortAudio devices:\n"); + for (int n = 0; n < count; n++) { + const PaDeviceInfo* info = Pa_GetDeviceInfo(n); + if (help) { + if (info->maxOutputChannels < 1) + continue; + mp_msg(MSGT_AO, MSGL_INFO, " %d '%s', %d channels, latency: %.2f " + "ms, sample rate: %.0f\n", n, info->name, + info->maxOutputChannels, + info->defaultHighOutputLatency * 1000, + info->defaultSampleRate); + } + if (strcmp(name, info->name) == 0 || n == index) { + found = n; + break; + } + } + if (found == paNoDevice && !help) + mp_msg(MSGT_AO, MSGL_FATAL, "[portaudio] Device '%s' not found!\n", + name); + return found; +} + +static int ring_write(struct ao *ao, unsigned char *data, int len) +{ + struct priv *priv = ao->priv; + + int free = priv->ring_size - priv->read_len; + int write_pos = (priv->read_pos + priv->read_len) % priv->ring_size; + int write_len = FFMIN(len, free); + int len1 = FFMIN(priv->ring_size - write_pos, write_len); + int len2 = write_len - len1; + + memcpy(priv->ring + write_pos, data, len1); + memcpy(priv->ring, data + len1, len2); + + priv->read_len += write_len; + + return write_len; +} + +static int ring_read(struct ao *ao, unsigned char *data, int len) +{ + struct priv *priv = ao->priv; + + int read_len = FFMIN(len, priv->read_len); + int len1 = FFMIN(priv->ring_size - priv->read_pos, read_len); + int len2 = read_len - len1; + + memcpy(data, priv->ring + priv->read_pos, len1); + memcpy(data + len1, priv->ring, len2); + + priv->read_len -= read_len; + priv->read_pos = (priv->read_pos + read_len) % priv->ring_size; + + return read_len; +} + +static void fill_silence(unsigned char *ptr, int len) +{ + memset(ptr, 0, len); +} + +static int stream_callback(const void *input, + void *output_v, + unsigned long frameCount, + const PaStreamCallbackTimeInfo *timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData) +{ + struct ao *ao = userData; + struct priv *priv = ao->priv; + int res = paContinue; + unsigned char *output = output_v; + int len_bytes = frameCount * priv->framelen; + + pthread_mutex_lock(&priv->ring_mutex); + + // NOTE: PA + ALSA in dmix mode seems to pretend that there is no latency + // (outputBufferDacTime == currentTime) + priv->play_time = timeInfo->outputBufferDacTime + + len_bytes / (float)ao->bps; + + if (priv->play_silence > 0) { + int bytes = FFMIN(priv->play_silence, len_bytes); + fill_silence(output, bytes); + priv->play_silence -= bytes; + len_bytes -= bytes; + output += bytes; + } + int read = ring_read(ao, output, len_bytes); + len_bytes -= read; + output += read; + + if (len_bytes > 0) { + if (priv->play_remaining) { + res = paComplete; + priv->play_remaining = false; + } else { + mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] Buffer underflow!\n"); + } + fill_silence(output, len_bytes); + } + + pthread_mutex_unlock(&priv->ring_mutex); + + return res; +} + +static void uninit(struct ao *ao, bool cut_audio) +{ + struct priv *priv = ao->priv; + + if (priv->stream) { + if (!cut_audio && Pa_IsStreamActive(priv->stream) == 1) { + pthread_mutex_lock(&priv->ring_mutex); + + priv->play_remaining = true; + + pthread_mutex_unlock(&priv->ring_mutex); + + check_pa_ret(Pa_StopStream(priv->stream)); + } + check_pa_ret(Pa_CloseStream(priv->stream)); + } + + pthread_mutex_destroy(&priv->ring_mutex); + Pa_Terminate(); +} + +static int init(struct ao *ao, char *params) +{ + struct priv *priv = talloc_zero(ao, struct priv); + ao->priv = priv; + + if (!check_pa_ret(Pa_Initialize())) + return -1; + + pthread_mutex_init(&priv->ring_mutex, NULL); + + char *device = NULL; + const opt_t subopts[] = { + {"device", OPT_ARG_MSTRZ, &device, NULL}, + {NULL} + }; + if (subopt_parse(params, subopts) != 0) { + print_help(); + goto error_exit; + } + + int pa_device = Pa_GetDefaultOutputDevice(); + if (device) + pa_device = find_device(ao, device); + if (pa_device == paNoDevice) + goto error_exit; + + PaStreamParameters sp = { + .device = pa_device, + .channelCount = ao->channels, + .suggestedLatency + = Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency, + }; + + const struct format_map *fmt = format_maps; + while (fmt->pa_format) { + if (fmt->mp_format == ao->format) { + PaStreamParameters test = sp; + test.sampleFormat = fmt->pa_format; + if (Pa_IsFormatSupported(NULL, &test, ao->samplerate) == paNoError) + break; + } + fmt++; + } + if (!fmt->pa_format) { + mp_msg(MSGT_AO, MSGL_V, + "[portaudio] Unsupported format, using default.\n"); + fmt = format_maps; + } + + ao->format = fmt->mp_format; + sp.sampleFormat = fmt->pa_format; + priv->framelen = ao->channels * (af_fmt2bits(ao->format) / 8); + ao->bps = ao->samplerate * priv->framelen; + + if (!check_pa_ret(Pa_IsFormatSupported(NULL, &sp, ao->samplerate))) + goto error_exit; + if (!check_pa_ret(Pa_OpenStream(&priv->stream, NULL, &sp, ao->samplerate, + paFramesPerBufferUnspecified, paNoFlag, + stream_callback, ao))) + goto error_exit; + + priv->ring_size = seconds_to_bytes(ao, 0.5); + priv->ring = talloc_zero_size(priv, priv->ring_size); + + free(device); + return 0; + +error_exit: + uninit(ao, true); + free(device); + return -1; +} + +static int play(struct ao *ao, void *data, int len, int flags) +{ + struct priv *priv = ao->priv; + + pthread_mutex_lock(&priv->ring_mutex); + + int write_len = ring_write(ao, data, len); + if (flags & AOPLAY_FINAL_CHUNK) + priv->play_remaining = true; + + pthread_mutex_unlock(&priv->ring_mutex); + + if (Pa_IsStreamStopped(priv->stream) == 1) + check_pa_ret(Pa_StartStream(priv->stream)); + + return write_len; +} + +static int get_space(struct ao *ao) +{ + struct priv *priv = ao->priv; + + pthread_mutex_lock(&priv->ring_mutex); + + int free = priv->ring_size - priv->read_len; + + pthread_mutex_unlock(&priv->ring_mutex); + + return free; +} + +static float get_delay(struct ao *ao) +{ + struct priv *priv = ao->priv; + + double stream_time = Pa_GetStreamTime(priv->stream); + + pthread_mutex_lock(&priv->ring_mutex); + + float frame_time = priv->play_time ? priv->play_time - stream_time : 0; + float buffer_latency = (priv->read_len + priv->play_silence) + / (float)ao->bps; + + pthread_mutex_unlock(&priv->ring_mutex); + + return buffer_latency + frame_time; +} + +static void reset(struct ao *ao) +{ + struct priv *priv = ao->priv; + + if (Pa_IsStreamStopped(priv->stream) != 1) + check_pa_ret(Pa_AbortStream(priv->stream)); + + pthread_mutex_lock(&priv->ring_mutex); + + priv->read_len = 0; + priv->read_pos = 0; + priv->play_remaining = false; + priv->play_time = 0; + priv->play_silence = 0; + + pthread_mutex_unlock(&priv->ring_mutex); +} + +static void pause(struct ao *ao) +{ + struct priv *priv = ao->priv; + + check_pa_ret(Pa_AbortStream(priv->stream)); + + double stream_time = Pa_GetStreamTime(priv->stream); + + pthread_mutex_lock(&priv->ring_mutex); + + // When playback resumes, replace the lost audio (due to dropping the + // portaudio/driver/hardware internal buffers) with silence. + float frame_time = priv->play_time ? priv->play_time - stream_time : 0; + priv->play_silence += seconds_to_bytes(ao, FFMAX(frame_time, 0)); + priv->play_time = 0; + + pthread_mutex_unlock(&priv->ring_mutex); +} + +static void resume(struct ao *ao) +{ + struct priv *priv = ao->priv; + + check_pa_ret(Pa_StartStream(priv->stream)); +} + +const struct ao_driver audio_out_portaudio = { + .is_new = true, + .info = &(const struct ao_info) { + "PortAudio", + "portaudio", + "wm4", + "", + }, + .init = init, + .uninit = uninit, + .reset = reset, + .get_space = get_space, + .play = play, + .get_delay = get_delay, + .pause = pause, + .resume = resume, +}; diff --git a/libao2/ao_pulse.c b/libao2/ao_pulse.c index ed6e08286a..e48c402fa6 100644 --- a/libao2/ao_pulse.c +++ b/libao2/ao_pulse.c @@ -186,7 +186,7 @@ static int init(struct ao *ao, char *params) ao->priv = priv; if (params) { - devarg = strdup(ao_subdevice); + devarg = strdup(params); sink = strchr(devarg, ':'); if (sink) *sink++ = 0; diff --git a/libao2/ao_sgi.c b/libao2/ao_sgi.c deleted file mode 100644 index 492c8ff3ba..0000000000 --- a/libao2/ao_sgi.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * SGI/IRIX audio output driver - * - * copyright (c) 2001 oliver.schoenbrunner@jku.at - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <dmedia/audio.h> - -#include "audio_out.h" -#include "audio_out_internal.h" -#include "mp_msg.h" -#include "libaf/af_format.h" - -static const ao_info_t info = -{ - "sgi audio output", - "sgi", - "Oliver Schoenbrunner", - "" -}; - -LIBAO_EXTERN(sgi) - - -static ALconfig ao_config; -static ALport ao_port; -static int sample_rate; -static int queue_size; -static int bytes_per_frame; - -/** - * \param [in/out] format - * \param [out] width - * - * \return the closest matching SGI AL sample format - * - * \note width is set to required per-channel sample width - * format is updated to match the SGI AL sample format - */ -static int fmt2sgial(int *format, int *width) { - int smpfmt = AL_SAMPFMT_TWOSCOMP; - - /* SGI AL only supports float and signed integers in native - * endianness. If this is something else, we must rely on the audio - * filter to convert it to a compatible format. */ - - /* 24-bit audio is supported, but only with 32-bit alignment. - * mplayer's 24-bit format is packed, unfortunately. - * So we must upgrade 24-bit requests to 32 bits. Then we drop the - * lowest 8 bits during playback. */ - - switch(*format) { - case AF_FORMAT_U8: - case AF_FORMAT_S8: - *width = AL_SAMPLE_8; - *format = AF_FORMAT_S8; - break; - - case AF_FORMAT_U16_LE: - case AF_FORMAT_U16_BE: - case AF_FORMAT_S16_LE: - case AF_FORMAT_S16_BE: - *width = AL_SAMPLE_16; - *format = AF_FORMAT_S16_NE; - break; - - case AF_FORMAT_U24_LE: - case AF_FORMAT_U24_BE: - case AF_FORMAT_S24_LE: - case AF_FORMAT_S24_BE: - case AF_FORMAT_U32_LE: - case AF_FORMAT_U32_BE: - case AF_FORMAT_S32_LE: - case AF_FORMAT_S32_BE: - *width = AL_SAMPLE_24; - *format = AF_FORMAT_S32_NE; - break; - - case AF_FORMAT_FLOAT_LE: - case AF_FORMAT_FLOAT_BE: - *width = 4; - *format = AF_FORMAT_FLOAT_NE; - smpfmt = AL_SAMPFMT_FLOAT; - break; - - default: - *width = AL_SAMPLE_16; - *format = AF_FORMAT_S16_NE; - break; - - } - - return smpfmt; -} - -// to set/get/query special features/parameters -static int control(int cmd, void *arg){ - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] control.\n"); - - return CONTROL_UNKNOWN; -} - -// open & setup audio device -// return: 1=success 0=fail -static int init(int rate, int channels, int format, int flags) { - - int smpwidth, smpfmt; - int rv = AL_DEFAULT_OUTPUT; - - smpfmt = fmt2sgial(&format, &smpwidth); - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] init: Samplerate: %iHz Channels: %s Format %s\n", rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); - - { /* from /usr/share/src/dmedia/audio/setrate.c */ - - double frate, realrate; - ALpv x[2]; - - if(ao_subdevice) { - rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE); - if (!rv) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] play: invalid device.\n"); - return 0; - } - } - - frate = rate; - - x[0].param = AL_RATE; - x[0].value.ll = alDoubleToFixed(rate); - x[1].param = AL_MASTER_CLOCK; - x[1].value.i = AL_CRYSTAL_MCLK_TYPE; - - if (alSetParams(rv,x, 2)<0) { - mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: setparams failed: %s\nCould not set desired samplerate.\n", alGetErrorString(oserror())); - } - - if (x[0].sizeOut < 0) { - mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: AL_RATE was not accepted on the given resource.\n"); - } - - if (alGetParams(rv,x, 1)<0) { - mp_tmsg(MSGT_AO, MSGL_WARN, "[AO SGI] init: getparams failed: %s\n", alGetErrorString(oserror())); - } - - realrate = alFixedToDouble(x[0].value.ll); - if (frate != realrate) { - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] init: samplerate is now %f (desired rate is %f)\n", realrate, frate); - } - sample_rate = (int)realrate; - } - - bytes_per_frame = channels * smpwidth; - - ao_data.samplerate = sample_rate; - ao_data.channels = channels; - ao_data.format = format; - ao_data.bps = sample_rate * bytes_per_frame; - ao_data.buffersize=131072; - ao_data.outburst = ao_data.buffersize/16; - - ao_config = alNewConfig(); - - if (!ao_config) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: %s\n", alGetErrorString(oserror())); - return 0; - } - - if(alSetChannels(ao_config, channels) < 0 || - alSetWidth(ao_config, smpwidth) < 0 || - alSetSampFmt(ao_config, smpfmt) < 0 || - alSetQueueSize(ao_config, sample_rate) < 0 || - alSetDevice(ao_config, rv) < 0) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: %s\n", alGetErrorString(oserror())); - return 0; - } - - ao_port = alOpenPort("mplayer", "w", ao_config); - - if (!ao_port) { - mp_tmsg(MSGT_AO, MSGL_ERR, "[AO SGI] init: Unable to open audio channel: %s\n", alGetErrorString(oserror())); - return 0; - } - - // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config); - queue_size = alGetQueueSize(ao_config); - return 1; - -} - -// close audio device -static void uninit(int immed) { - - /* TODO: samplerate should be set back to the value before mplayer was started! */ - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] uninit: ...\n"); - - if (ao_config) { - alFreeConfig(ao_config); - ao_config = NULL; - } - - if (ao_port) { - if (!immed) - while(alGetFilled(ao_port) > 0) sginap(1); - alClosePort(ao_port); - ao_port = NULL; - } - -} - -// stop playing and empty buffers (for seeking/pause) -static void reset(void) { - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] reset: ...\n"); - - alDiscardFrames(ao_port, queue_size); -} - -// stop playing, keep buffers (for pause) -static void audio_pause(void) { - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] audio_pause: ...\n"); - -} - -// resume playing, after audio_pause() -static void audio_resume(void) { - - mp_tmsg(MSGT_AO, MSGL_INFO, "[AO SGI] audio_resume: ...\n"); - -} - -// return: how many bytes can be played without blocking -static int get_space(void) { - - // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst); - // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port)); - - return alGetFillable(ao_port) * bytes_per_frame; - -} - - -// 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) { - - /* Always process data in quadword-aligned chunks (64-bits). */ - const int plen = len / (sizeof(uint64_t) * bytes_per_frame); - const int framecount = plen * sizeof(uint64_t); - - // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config); - // printf("channels %d\n", ao_data.channels); - - if(ao_data.format == AF_FORMAT_S32_NE) { - /* The zen of this is explained in fmt2sgial() */ - int32_t *smpls = data; - const int32_t *smple = smpls + (framecount * ao_data.channels); - while(smpls < smple) - *smpls++ >>= 8; - } - - alWriteFrames(ao_port, data, framecount); - - return framecount * bytes_per_frame; - -} - -// return: delay in seconds between first and last sample in buffer -static float get_delay(void){ - - // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize); - - // return (float)queue_size/((float)sample_rate); - const int outstanding = alGetFilled(ao_port); - return (float)((outstanding < 0) ? queue_size : outstanding) / - ((float)sample_rate); -} diff --git a/libao2/audio_out.c b/libao2/audio_out.c index 268c17d749..36b3e2d7c6 100644 --- a/libao2/audio_out.c +++ b/libao2/audio_out.c @@ -55,6 +55,7 @@ extern const struct ao_driver audio_out_v4l2; extern const struct ao_driver audio_out_mpegpes; extern const struct ao_driver audio_out_pcm; extern const struct ao_driver audio_out_pss; +extern const struct ao_driver audio_out_portaudio; static const struct ao_driver * const audio_out_drivers[] = { // native: @@ -82,19 +83,13 @@ static const struct ao_driver * const audio_out_drivers[] = { #ifdef CONFIG_OSS_AUDIO &audio_out_oss, #endif -#ifdef CONFIG_SGI_AUDIO - &audio_out_sgi, +#ifdef CONFIG_PORTAUDIO + &audio_out_portaudio, #endif #ifdef CONFIG_SUN_AUDIO &audio_out_sun, #endif // wrappers: -#ifdef CONFIG_ARTS - &audio_out_arts, -#endif -#ifdef CONFIG_ESD - &audio_out_esd, -#endif #ifdef CONFIG_JACK &audio_out_jack, #endif diff --git a/libmpcodecs/ad_mpg123.c b/libmpcodecs/ad_mpg123.c index 4a8507fe4d..21173a8a8f 100644 --- a/libmpcodecs/ad_mpg123.c +++ b/libmpcodecs/ad_mpg123.c @@ -1,7 +1,7 @@ /* * MPEG 1.0/2.0/2.5 audio layer I, II, III decoding with libmpg123 * - * Copyright (C) 2010 Thomas Orgis <thomas@orgis.org> + * Copyright (C) 2010-2012 Thomas Orgis <thomas@orgis.org> * * MPlayer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,36 +38,20 @@ LIBAD_EXTERN(mpg123) #include "libvo/fastmemcpy.h" -/* We avoid any usage of mpg123 API that is sensitive to the large file - * support setting. This ensures compatibility with a wide range of libmpg123 - * installs. This code is intended to work with version 1.0.0 of libmpg123. - * - * Though the chosen API subset is not affected by the choice of large file - * support, the mpg123 header (old versions of which) might include a check - * for matching _FILE_OFFSET_BITS. Since MPlayer does always define this one - * for large file support, we are safe for any default mpg123 install that - * either doesn't have such checks or defaults to the large value of - * _FILE_OFFSET_BITS . - * So, in short: There's no worry unless you have a non-default libmpg123 - * with intentionally disabled large file support. */ -/* You might need to #undef _FILE_OFFSET_BITS here on a 64 bit system - with released mpg123 1.12 when using callback API. SVN snapshots - should work fine. */ +/* Reducing the ifdeffery to two main variants: + * 1. most compatible to any libmpg123 version + * 2. fastest variant with recent libmpg123 (>=1.14) + * Running variant 2 on older libmpg123 versions may work in + * principle, but is not supported. + * So, please leave the check for MPG123_API_VERSION there, m-kay? + */ #include <mpg123.h> -/* Selection of mpg123 usage patterns: - * AD_MPG123_CALLBACK: Use callback API instead of feeding of memory buffers. - * That needs mpg123>=1.12, on x86-64 SVN snapshot because of - * _FILE_OFFSET_BITS being defined (see above). - * AD_MPG123_PACKET: Use packet-based input (including pts handling). - * AD_MPG123_SEEKBUFFER: Use internal mpg123 buffer to enhance stream parsing. - * Makes sense with callback API only. - * Any of those might affect I/O performance, might be significant compared - * to the excessively optimized decoding. - */ -/* #define AD_MPG123_CALLBACK */ -#define AD_MPG123_PACKET -/* #define AD_MPG123_SEEKBUFFER */ +/* Enable faster mode of operation with newer libmpg123, avoiding + * unnecessary memcpy() calls. */ +#if (defined MPG123_API_VERSION) && (MPG123_API_VERSION >= 33) +#define AD_MPG123_FRAMEWISE +#endif /* Switch for updating bitrate info of VBR files. Not essential. */ #define AD_MPG123_MEAN_BITRATE @@ -87,77 +71,8 @@ struct ad_mpg123_context { #endif /* If the stream is actually VBR. */ char vbr; -#if (defined AD_MPG123_CALLBACK) && (defined AD_MPG123_PACKET) - unsigned char *packet; - int packleft; -#endif }; -static void context_reset(struct ad_mpg123_context *con) -{ -#ifdef AD_MPG123_MEAN_BITRATE - con->mean_rate = 0.; - con->mean_count = 0; - con->delay = 1; -#endif -#if (defined AD_MPG123_CALLBACK) && (defined AD_MPG123_PACKET) - con->packet = NULL; - con->packleft = 0; -#endif -} - - -#ifdef AD_MPG123_CALLBACK -/* Mpg123 calls that for retrieving data. - * This wrapper is at least needed for the call frame (ssize_t vs. int). */ -static ssize_t read_callback(void *ash, void *buf, size_t count) -{ - sh_audio_t *sh = ash; -#ifdef AD_MPG123_PACKET - struct ad_mpg123_context *con = sh->context; - unsigned char *target = buf; - int need = count; - ssize_t got = 0; - while (need > 0) { - if (con->packleft > 0) { - int get = need > con->packleft ? con->packleft : need; - /* Any difference to normal memcpy? */ - fast_memcpy(target, con->packet, get); - /* OK, that does look redundant. */ - con->packet += get; - con->packleft -= get; - target += get; - need -= get; - got += get; - } else { - double pts; - /* Feed more input data. */ - con->packleft = ds_get_packet_pts(sh->ds, &con->packet, &pts); - if (con->packleft <= 0) - break; /* Apparently that's it. EOF. */ - - /* Next bytes from that presentation time. */ - if (pts != MP_NOPTS_VALUE) { - sh->pts = pts; - sh->pts_bytes = 0; - } - } - } - return got; -#else - /* It returns int... with the meaning of byte count. */ - return (ssize_t) demux_read_data(sh->ds, buf, count); -#endif -} - -/* Arbitrary input seeking is not supported with this MPlayer API(?). - That also means that we won't read any ID3v1 tags. */ -static off_t seek_callback(void *sh, off_t pos, int whence) -{ - return -1; -} -#endif - /* This initializes libmpg123 and prepares the handle, including funky * parameters. */ static int preinit(sh_audio_t *sh) @@ -173,8 +88,6 @@ static int preinit(sh_audio_t *sh) sh->context = malloc(sizeof(struct ad_mpg123_context)); con = sh->context; - context_reset(con); - /* Auto-choice of optimized decoder (first argument NULL). */ con->handle = mpg123_new(NULL, &err); if (!con->handle) @@ -188,17 +101,6 @@ static int preinit(sh_audio_t *sh) if (mpg123_param(con->handle, MPG123_ADD_FLAGS, flag, 0.0) != MPG123_OK) goto bad_end; #endif -#ifdef AD_MPG123_CALLBACK - /* The I/O is handled via callbacks to MPlayer stream functions, - * actually only the reading, as general seeking does not seem to be available */ - if (mpg123_replace_reader_handle(con->handle, read_callback, - seek_callback, NULL) != MPG123_OK) { - mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 error: %s\n", - mpg123_strerror(con->handle)); - mpg123_exit(); - return 0; - } -#endif /* Basic settings. * Don't spill messages, enable better resync with non-seekable streams. @@ -206,10 +108,6 @@ static int preinit(sh_audio_t *sh) * old libmpg123. Generally, it is not fatal if the flags are not * honored */ mpg123_param(con->handle, MPG123_ADD_FLAGS, MPG123_QUIET, 0.0); - /* Old headers don't know MPG123_SEEKBUFFER yet, so use the plain 0x100. */ -#ifdef AD_MPG123_SEEKBUFFER - mpg123_param(con->handle, MPG123_ADD_FLAGS, 0x100, 0.0); -#endif /* Do not bail out on malformed streams at all. * MPlayer does not handle a decoder throwing the towel on crappy input. */ mpg123_param(con->handle, MPG123_RESYNC_LIMIT, -1, 0.0); @@ -220,9 +118,25 @@ static int preinit(sh_audio_t *sh) * Don't forget to eventually enable ReplayGain/RVA support, too. * Let's try to run with the default for now. */ + /* That would produce floating point output. + * You can get 32 and 24 bit ints, even 8 bit via format matrix. */ + /* mpg123_param(con->handle, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT, 0.); */ + /* Example for RVA choice (available since libmpg123 1.0.0): mpg123_param(con->handle, MPG123_RVA, MPG123_RVA_MIX, 0.0) */ +#ifdef AD_MPG123_FRAMEWISE + /* Prevent funky automatic resampling. + * This way, we can be sure that one frame will never produce + * more than 1152 stereo samples. */ + mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 0.); +#else + /* Older mpg123 is vulnerable to concatenated streams when gapless cutting + * is enabled (will only play the jingle of a badly constructed radio + * stream). The versions using framewise decoding are fine with that. */ + mpg123_param(con->handle, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0.); +#endif + return 1; bad_end: @@ -294,7 +208,6 @@ static void print_header_compact(struct mpg123_frameinfo *i) smodes[i->mode]); } -#ifndef AD_MPG123_CALLBACK /* This tries to extract a requested amount of decoded data. * Even when you request 0 bytes, it will feed enough input so that * the decoder _could_ have delivered something. @@ -321,19 +234,13 @@ static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count) struct ad_mpg123_context *con = sh->context; /* There will be one MPG123_NEW_FORMAT message on first open. - * This will be implicitly handled in reopen_stream(). */ + * This will be handled in init(). */ do { size_t got_now = 0; - ret = mpg123_decode(con->handle, NULL, 0, buf + got, count - got, - &got_now); - got += got_now; -#ifdef AD_MPG123_PACKET - sh->pts_bytes += got_now; -#endif + /* Feed the decoder. This will only fire from the second round on. */ if (ret == MPG123_NEED_MORE) { int incount; -#ifdef AD_MPG123_PACKET double pts; unsigned char *inbuf; /* Feed more input data. */ @@ -346,26 +253,45 @@ static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count) sh->pts = pts; sh->pts_bytes = 0; } -#else - const int inbufsize = 4096; - unsigned char inbuf[inbufsize]; - /* Feed more input data. */ - incount = demux_read_data(((sh_audio_t *) sh)->ds, - inbuf, inbufsize); - if (incount == 0) - break; /* Apparently that's it. EOF. */ -#endif +#ifdef AD_MPG123_FRAMEWISE + /* Have to use mpg123_feed() to avoid decoding here. */ + ret = mpg123_feed(con->handle, inbuf, incount); +#else /* Do not use mpg123_feed(), added in later libmpg123 versions. */ ret = mpg123_decode(con->handle, inbuf, incount, NULL, 0, NULL); - /* Return value is checked in the loop condition. - * It could be MPG12_OK now, it could need more. */ +#endif + if (ret == MPG123_ERR) + break; } - /* Older mpg123 versions might indicate MPG123_DONE, so be prepared. */ + /* Theoretically, mpg123 could return MPG123_DONE, so be prepared. + * Should not happen in our usage, but it is a valid return code. */ else if (ret == MPG123_ERR || ret == MPG123_DONE) break; + /* Try to decode a bit. This is the return value that counts + * for the loop condition. */ +#ifdef AD_MPG123_FRAMEWISE + if (!buf) { /* fake call just for feeding to get format */ + ret = mpg123_getformat(con->handle, NULL, NULL, NULL); + } else { /* This is the decoding. One frame at a time. */ + ret = mpg123_replace_buffer(con->handle, buf, count); + if (ret == MPG123_OK) + ret = mpg123_decode_frame(con->handle, NULL, NULL, &got_now); + } +#else + ret = mpg123_decode(con->handle, NULL, 0, buf + got, count - got, + &got_now); +#endif + + got += got_now; + sh->pts_bytes += got_now; + +#ifdef AD_MPG123_FRAMEWISE + } while (ret == MPG123_NEED_MORE || (got == 0 && count != 0)); +#else } while (ret == MPG123_NEED_MORE || got < count); +#endif if (ret == MPG123_ERR) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 decoding failed: %s\n", @@ -376,29 +302,21 @@ static int decode_a_bit(sh_audio_t *sh, unsigned char *buf, int count) return got; } -#endif /* Close, reopen stream. Feed data until we know the format of the stream. * 1 on success, 0 on error */ static int reopen_stream(sh_audio_t *sh) { - long rate; - int chan, enc; struct ad_mpg123_context *con = (struct ad_mpg123_context*) sh->context; mpg123_close(con->handle); - context_reset(con); + /* No resetting of the context: + * We do not want to loose the mean bitrate data. */ -#ifdef AD_MPG123_CALLBACK - if (MPG123_OK == mpg123_open_handle(con->handle, sh) && -#else - if (/* Open and make sure we have fed enough data to get stream properties. */ - MPG123_OK == mpg123_open_feed(con->handle) && + /* Open and make sure we have fed enough data to get stream properties. */ + if (MPG123_OK == mpg123_open_feed(con->handle) && /* Feed data until mpg123 is ready (has found stream beginning). */ - !decode_a_bit(sh, NULL, 0) && -#endif - /* Not handing NULL pointers for compatibility with old libmpg123. */ - MPG123_OK == mpg123_getformat(con->handle, &rate, &chan, &enc)) { + !decode_a_bit(sh, NULL, 0)) { return 1; } else { mp_msg(MSGT_DECAUDIO, MSGL_ERR, @@ -446,7 +364,11 @@ static int init(sh_audio_t *sh) * For VBR, the first frame will be a bad estimate. */ sh->i_bps = (finfo.bitrate ? finfo.bitrate : compute_bitrate(&finfo)) * 1000 / 8; - context_reset(con); +#ifdef AD_MPG123_MEAN_BITRATE + con->delay = 1; + con->mean_rate = 0.; + con->mean_count = 0; +#endif con->vbr = (finfo.vbr != MPG123_CBR); sh->channels = channels; sh->samplerate = rate; @@ -480,6 +402,12 @@ static int init(sh_audio_t *sh) mpg123_close(con->handle); return 0; } +#ifdef AD_MPG123_FRAMEWISE + /* Going to decode directly to MPlayer's memory. It is important + * to have MPG123_AUTO_RESAMPLE disabled for the buffer size + * being an all-time limit. */ + sh->audio_out_minsize = 1152 * 2 * sh->samplesize; +#endif return 1; } else { @@ -529,29 +457,13 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf, int minlen, { int bytes; -#ifdef AD_MPG123_CALLBACK - struct ad_mpg123_context *con = sh->context; - size_t got_bytes = 0; - if (MPG123_ERR == mpg123_read(con->handle, buf, minlen, &got_bytes)) { - mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Decoding error in mpg123: %s\n", - mpg123_strerror(con->handle)); - return -1; - } -#ifdef AD_MPG123_PACKET - sh->pts_bytes += got_bytes; -#endif - bytes = got_bytes; -#else - bytes = decode_a_bit(sh, buf, minlen); -#endif - + bytes = decode_a_bit(sh, buf, maxlen); if (bytes == 0) return -1; /* EOF */ #ifdef AD_MPG123_MEAN_BITRATE update_info(sh); #endif - return bytes; } @@ -569,6 +481,8 @@ static int control(sh_audio_t *sh, int cmd, void *arg, ...) #endif return CONTROL_TRUE; } else { + /* MPlayer ignores this case! It just keeps on decoding. + * So we have to make sure resync never fails ... */ mp_msg(MSGT_DECAUDIO, MSGL_ERR, "mpg123 cannot reopen stream for resync.\n"); return CONTROL_FALSE; diff --git a/m_config.c b/m_config.c index 94d7e26b2e..3da7707f14 100644 --- a/m_config.c +++ b/m_config.c @@ -36,12 +36,21 @@ #define MAX_PROFILE_DEPTH 20 -static int parse_profile(const struct m_option *opt, struct bstr name, - struct bstr param, bool ambiguous_param, void *dst) +static int parse_include(struct m_config *config, struct bstr param, bool set) +{ + if (param.len == 0) + return M_OPT_MISSING_PARAM; + if (!set) + return 1; + char *filename = bstrdup0(NULL, param); + config->includefunc(config, filename); + talloc_free(filename); + return 1; +} + +static int parse_profile(struct m_config *config, const struct m_option *opt, + struct bstr name, struct bstr param, bool set) { - struct m_config *config = opt->priv; - char **list = NULL; - int i, r; if (!bstrcmp0(param, "help")) { struct m_profile *p; if (!config->profiles) { @@ -57,40 +66,23 @@ static int parse_profile(const struct m_option *opt, struct bstr name, return M_OPT_EXIT - 1; } - r = m_option_type_string_list.parse(opt, name, param, false, &list); + char **list = NULL; + int r = m_option_type_string_list.parse(opt, name, param, false, &list); if (r < 0) return r; if (!list || !list[0]) return M_OPT_INVALID; - for (i = 0; list[i]; i++) - if (!m_config_get_profile(config, list[i])) { + for (int i = 0; list[i]; i++) { + struct m_profile *p = m_config_get_profile(config, list[i]); + if (!p) { mp_tmsg(MSGT_CFGPARSER, MSGL_WARN, "Unknown profile '%s'.\n", list[i]); r = M_OPT_INVALID; - } - if (dst) - m_option_copy(opt, dst, &list); - else - m_option_free(opt, &list); - return r; -} - -static void set_profile(const struct m_option *opt, void *dst, const void *src) -{ - struct m_config *config = opt->priv; - struct m_profile *p; - char **list = NULL; - int i; - if (!src || !*(char ***)src) - return; - m_option_copy(opt, &list, src); - for (i = 0; list[i]; i++) { - p = m_config_get_profile(config, list[i]); - if (!p) - continue; - m_config_set_profile(config, p); + } else if (set) + m_config_set_profile(config, p); } m_option_free(opt, &list); + return r; } static int show_profile(struct m_option *opt, char *name, char *param) @@ -150,18 +142,18 @@ static int list_options(struct m_option *opt, char *name, char *param) static void m_option_save(const struct m_config *config, const struct m_option *opt, void *dst) { - if (opt->type->save) { + if (opt->type->copy) { const void *src = m_option_get_ptr(opt, config->optstruct); - opt->type->save(opt, dst, src); + opt->type->copy(opt, dst, src); } } static void m_option_set(const struct m_config *config, const struct m_option *opt, const void *src) { - if (opt->type->set) { + if (opt->type->copy) { void *dst = m_option_get_ptr(opt, config->optstruct); - opt->type->set(opt, dst, src); + opt->type->copy(opt, dst, src); } } @@ -172,40 +164,31 @@ static void m_config_add_option(struct m_config *config, const char *prefix, char *disabled_feature); struct m_config *m_config_new(void *optstruct, - int includefunc(struct m_option *conf, + int includefunc(struct m_config *conf, char *filename)) { struct m_config *config; - static int initialized = 0; - static struct m_option_type profile_opt_type; static const struct m_option ref_opts[] = { - { "profile", NULL, &profile_opt_type, CONF_NOSAVE, 0, 0, NULL }, + { "profile", NULL, CONF_TYPE_STRING_LIST, CONF_NOSAVE, 0, 0, NULL }, { "show-profile", show_profile, CONF_TYPE_PRINT_FUNC, CONF_NOCFG }, { "list-options", list_options, CONF_TYPE_PRINT_FUNC, CONF_NOCFG }, { NULL } }; - int i; config = talloc_zero(NULL, struct m_config); config->lvl = 1; // 0 Is the defaults - if (!initialized) { - initialized = 1; - profile_opt_type = m_option_type_string_list; - profile_opt_type.parse = parse_profile; - profile_opt_type.set = set_profile; - } struct m_option *self_opts = talloc_memdup(config, ref_opts, sizeof(ref_opts)); - for (i = 0; self_opts[i].name; i++) + for (int i = 1; self_opts[i].name; i++) self_opts[i].priv = config; m_config_register_options(config, self_opts); if (includefunc) { struct m_option *p = talloc_ptrtype(config, p); *p = (struct m_option){ - "include", includefunc, CONF_TYPE_FUNC_PARAM, - CONF_NOSAVE, 0, 0, config + "include", NULL, CONF_TYPE_STRING, CONF_NOSAVE, }; m_config_add_option(config, p, NULL, NULL); + config->includefunc = includefunc; } config->optstruct = optstruct; @@ -420,18 +403,15 @@ static struct m_config_option *m_config_get_co(const struct m_config *config, return NULL; } -static int m_config_parse_option(const struct m_config *config, +static int m_config_parse_option(struct m_config *config, struct bstr name, struct bstr param, bool ambiguous_param, bool set) { - struct m_config_option *co; - int r = 0; - assert(config != NULL); assert(config->lvl > 0); assert(name.len != 0); - co = m_config_get_co(config, name); + struct m_config_option *co = m_config_get_co(config, name); if (!co) return M_OPT_UNKNOWN; if (co->disabled_feature) { @@ -466,23 +446,27 @@ static int m_config_parse_option(const struct m_config *config, (co->opt->flags & M_OPT_PRE_PARSE) && (co->flags & M_CFG_OPT_SET))) set = 0; + if (config->includefunc && !bstrcmp0(name, "include")) { + return parse_include(config, param, set); + } else if (!bstrcmp0(name, "profile")) + return parse_profile(config, co->opt, name, param, set); + // Option with children are a bit different to parse if (co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { char **lst = NULL; - int i, sr; // Parse the child options - r = m_option_parse(co->opt, name, param, false, &lst); + int r = m_option_parse(co->opt, name, param, false, &lst); // Set them now if (r >= 0) - for (i = 0; lst && lst[2 * i]; i++) { + for (int i = 0; lst && lst[2 * i]; i++) { int l = strlen(co->name) + 1 + strlen(lst[2 * i]) + 1; if (r >= 0) { // Build the full name char n[l]; sprintf(n, "%s:%s", co->name, lst[2 * i]); - sr = m_config_parse_option(config, bstr(n), - bstr(lst[2 * i + 1]), false, - set); + int sr = m_config_parse_option(config, bstr(n), + bstr(lst[2 * i + 1]), false, + set); if (sr < 0) { if (sr == M_OPT_UNKNOWN) { mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, @@ -502,18 +486,16 @@ static int m_config_parse_option(const struct m_config *config, talloc_free(lst[2 * i + 1]); } talloc_free(lst); - } else - r = m_option_parse(co->opt, name, param, ambiguous_param, - set ? co->slots->data : NULL); + return r; + } + void *dst = set ? m_option_get_ptr(co->opt, config->optstruct) : NULL; + int r = m_option_parse(co->opt, name, param, ambiguous_param, dst); // Parsing failed ? if (r < 0) return r; - // Set the option - if (set) { - m_option_set(config, co->opt, co->slots->data); + else if (set) co->flags |= M_CFG_OPT_SET; - } return r; } @@ -526,7 +508,7 @@ int m_config_set_option(struct m_config *config, struct bstr name, return m_config_parse_option(config, name, param, ambiguous_param, 1); } -int m_config_check_option(const struct m_config *config, struct bstr name, +int m_config_check_option(struct m_config *config, struct bstr name, struct bstr param, bool ambiguous_param) { int r; diff --git a/m_config.h b/m_config.h index 91ee7ffe43..ff54aae8b2 100644 --- a/m_config.h +++ b/m_config.h @@ -95,6 +95,7 @@ typedef struct m_config { int profile_depth; void *optstruct; // struct mpopts or other + int (*includefunc)(struct m_config *conf, char *filename); } m_config_t; @@ -107,7 +108,7 @@ typedef struct m_config { // Create a new config object. struct m_config * m_config_new(void *optstruct, - int includefunc(struct m_option *conf, char *filename)); + int includefunc(struct m_config *conf, char *filename)); // Free a config object. void m_config_free(struct m_config *config); @@ -151,7 +152,7 @@ static inline int m_config_set_option0(struct m_config *config, /* Check if an option setting is valid. * Same as above m_config_set_option() but doesn't actually set anything. */ -int m_config_check_option(const struct m_config *config, struct bstr name, +int m_config_check_option(struct m_config *config, struct bstr name, struct bstr param, bool ambiguous_param); static inline int m_config_check_option0(struct m_config *config, diff --git a/m_option.c b/m_option.c index 2af87b059f..0ca3ed9f29 100644 --- a/m_option.c +++ b/m_option.c @@ -129,16 +129,12 @@ static char *print_flag(const m_option_t *opt, const void *val) } const m_option_type_t m_option_type_flag = { - "Flag", - "need yes or no in config files", - sizeof(int), - 0, - parse_flag, - print_flag, - copy_opt, - copy_opt, - NULL, - NULL + // need yes or no in config files + .name = "Flag", + .size = sizeof(int), + .parse = parse_flag, + .print = print_flag, + .copy = copy_opt, }; // Integer @@ -209,29 +205,19 @@ static char *print_int(const m_option_t *opt, const void *val) } const m_option_type_t m_option_type_int = { - "Integer", - "", - sizeof(int), - 0, - parse_int, - print_int, - copy_opt, - copy_opt, - NULL, - NULL + .name = "Integer", + .size = sizeof(int), + .parse = parse_int, + .print = print_int, + .copy = copy_opt, }; const m_option_type_t m_option_type_int64 = { - "Integer64", - "", - sizeof(int64_t), - 0, - parse_int64, - print_int, - copy_opt, - copy_opt, - NULL, - NULL + .name = "Integer64", + .size = sizeof(int64_t), + .parse = parse_int64, + .print = print_int, + .copy = copy_opt, }; static int parse_intpair(const struct m_option *opt, struct bstr name, @@ -271,11 +257,10 @@ bad: } const struct m_option_type m_option_type_intpair = { - .name = "Int[-Int]", - .size = sizeof(int[2]), + .name = "Int[-Int]", + .size = sizeof(int[2]), .parse = parse_intpair, - .save = copy_opt, - .set = copy_opt, + .copy = copy_opt, }; static int parse_choice(const struct m_option *opt, struct bstr name, @@ -322,12 +307,11 @@ static char *print_choice(const m_option_t *opt, const void *val) } const struct m_option_type m_option_type_choice = { - .name = "String", // same as arbitrary strings in option list for now - .size = sizeof(int), + .name = "String", // same as arbitrary strings in option list for now + .size = sizeof(int), .parse = parse_choice, .print = print_choice, - .save = copy_opt, - .set = copy_opt, + .copy = copy_opt, }; // Float @@ -398,16 +382,12 @@ static char *print_double(const m_option_t *opt, const void *val) } const m_option_type_t m_option_type_double = { - "Double", - "double precision floating point number or ratio (numerator[:/]denominator)", - sizeof(double), - 0, - parse_double, - print_double, - copy_opt, - copy_opt, - NULL, - NULL + // double precision float or ratio (numerator[:/]denominator) + .name = "Double", + .size = sizeof(double), + .parse = parse_double, + .print = print_double, + .copy = copy_opt, }; #undef VAL @@ -430,16 +410,12 @@ static char *print_float(const m_option_t *opt, const void *val) } const m_option_type_t m_option_type_float = { - "Float", - "floating point number or ratio (numerator[:/]denominator)", - sizeof(float), - 0, - parse_float, - print_float, - copy_opt, - copy_opt, - NULL, - NULL + // floating point number or ratio (numerator[:/]denominator) + .name = "Float", + .size = sizeof(float), + .parse = parse_float, + .print = print_float, + .copy = copy_opt, }; ///////////// Position @@ -462,16 +438,12 @@ static char *print_position(const m_option_t *opt, const void *val) } const m_option_type_t m_option_type_position = { - "Position", - "Integer (off_t)", - sizeof(off_t), - 0, - parse_position, - print_position, - copy_opt, - copy_opt, - NULL, - NULL + // Integer (off_t) + .name = "Position", + .size = sizeof(off_t), + .parse = parse_position, + .print = print_position, + .copy = copy_opt, }; @@ -528,16 +500,13 @@ static void free_str(void *src) } const m_option_type_t m_option_type_string = { - "String", - "", - sizeof(char *), - M_OPT_TYPE_DYNAMIC, - parse_str, - print_str, - copy_str, - copy_str, - copy_str, - free_str + .name = "String", + .size = sizeof(char *), + .flags = M_OPT_TYPE_DYNAMIC, + .parse = parse_str, + .print = print_str, + .copy = copy_str, + .free = free_str, }; //////////// String list @@ -795,164 +764,24 @@ static char *print_str_list(const m_option_t *opt, const void *src) } const m_option_type_t m_option_type_string_list = { - "String list", - "A list of strings separated by ','\n" - "Option with a name ending in an * permits using the following suffix: \n" - "\t-add: Add the given parameters at the end of the list.\n" - "\t-pre: Add the given parameters at the beginning of the list.\n" - "\t-del: Remove the entry at the given indices.\n" - "\t-clr: Clear the list.\n" - "e.g: -vf-add flip,mirror -vf-del 2,5\n", - sizeof(char **), - M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, - parse_str_list, - print_str_list, - copy_str_list, - copy_str_list, - copy_str_list, - free_str_list + /* A list of strings separated by ','. + * Option with a name ending in '*' permits using the following suffixes: + * -add: Add the given parameters at the end of the list. + * -pre: Add the given parameters at the beginning of the list. + * -del: Remove the entry at the given indices. + * -clr: Clear the list. + * e.g: -vf-add flip,mirror -vf-del 2,5 + */ + .name = "String list", + .size = sizeof(char **), + .flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, + .parse = parse_str_list, + .print = print_str_list, + .copy = copy_str_list, + .free = free_str_list, }; -/////////////////// Func based options - -// A chained list to save the various calls for func_param -struct m_func_save { - struct m_func_save *next; - char *name; - char *param; -}; - -#undef VAL -#define VAL(x) (*(struct m_func_save **)(x)) - -static void free_func_pf(void *src) -{ - struct m_func_save *s, *n; - - if (!src) - return; - - s = VAL(src); - - while (s) { - n = s->next; - talloc_free(s->name); - talloc_free(s->param); - talloc_free(s); - s = n; - } - VAL(src) = NULL; -} - -// Parser for func_param -static int parse_func_pf(const m_option_t *opt, struct bstr name, - struct bstr param, bool ambiguous_param, void *dst) -{ - struct m_func_save *s, *p; - - if (!dst) - return 1; - - s = talloc_zero(NULL, struct m_func_save); - s->name = bstrdup0(NULL, name); - s->param = bstrdup0(NULL, param); - - p = VAL(dst); - if (p) { - for (; p->next != NULL; p = p->next) - /**/; - p->next = s; - } else - VAL(dst) = s; - - return 1; -} - -static void copy_func_pf(const m_option_t *opt, void *dst, const void *src) -{ - struct m_func_save *d = NULL, *s, *last = NULL; - - if (!(dst && src)) - return; - s = VAL(src); - - if (VAL(dst)) - free_func_pf(dst); - - while (s) { - d = talloc_zero(NULL, struct m_func_save); - d->name = talloc_strdup(NULL, s->name); - d->param = talloc_strdup(NULL, s->param); - if (last) - last->next = d; - else - VAL(dst) = d; - last = d; - s = s->next; - } - - -} - -/////////////////// Func_param - -static void set_func_param(const m_option_t *opt, void *dst, const void *src) -{ - struct m_func_save *s; - - if (!src) - return; - s = VAL(src); - - if (!s) - return; - - for (; s != NULL; s = s->next) - ((m_opt_func_param_t) opt->p)(opt, s->param); -} - -const m_option_type_t m_option_type_func_param = { - "Func param", - "", - sizeof(struct m_func_save *), - M_OPT_TYPE_INDIRECT, - parse_func_pf, - NULL, - NULL, // Nothing to do on save - set_func_param, - copy_func_pf, - free_func_pf -}; - -/////////////// Func - -#undef VAL - -static int parse_func(const m_option_t *opt, struct bstr name, - struct bstr param, bool ambiguous_param, void *dst) -{ - return 0; -} - -static void set_func(const m_option_t *opt, void *dst, const void *src) -{ - ((m_opt_func_t) opt->p)(opt); -} - -const m_option_type_t m_option_type_func = { - "Func", - "", - sizeof(int), - M_OPT_TYPE_INDIRECT, - parse_func, - NULL, - NULL, // Nothing to do on save - set_func, - NULL, - NULL -}; - /////////////////// Print static int parse_print(const m_option_t *opt, struct bstr name, @@ -976,42 +805,19 @@ static int parse_print(const m_option_t *opt, struct bstr name, } const m_option_type_t m_option_type_print = { - "Print", - "", - 0, - 0, - parse_print, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Print", + .parse = parse_print, }; const m_option_type_t m_option_type_print_indirect = { - "Print", - "", - 0, - 0, - parse_print, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Print", + .parse = parse_print, }; const m_option_type_t m_option_type_print_func = { - "Print", - "", - 0, - M_OPT_TYPE_ALLOW_WILDCARD, - parse_print, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Print", + .flags = M_OPT_TYPE_ALLOW_WILDCARD, + .parse = parse_print, }; @@ -1104,16 +910,10 @@ static int parse_subconf(const m_option_t *opt, struct bstr name, } const m_option_type_t m_option_type_subconfig = { - "Subconfig", - "The syntax is -option opt1=foo:flag:opt2=blah", - sizeof(int), - M_OPT_TYPE_HAS_CHILD, - parse_subconf, - NULL, - NULL, - NULL, - NULL, - NULL + // The syntax is -option opt1=foo:flag:opt2=blah + .name = "Subconfig", + .flags = M_OPT_TYPE_HAS_CHILD, + .parse = parse_subconf, }; #include "libmpcodecs/img_format.h" @@ -1238,16 +1038,11 @@ static int parse_imgfmt(const m_option_t *opt, struct bstr name, } const m_option_type_t m_option_type_imgfmt = { - "Image format", - "Please report any missing colorspaces.", - sizeof(uint32_t), - 0, - parse_imgfmt, - NULL, - copy_opt, - copy_opt, - NULL, - NULL + // Please report any missing colorspaces + .name = "Image format", + .size = sizeof(uint32_t), + .parse = parse_imgfmt, + .copy = copy_opt, }; #include "libaf/af_format.h" @@ -1333,16 +1128,11 @@ static int parse_afmt(const m_option_t *opt, struct bstr name, } const m_option_type_t m_option_type_afmt = { - "Audio format", - "Please report any missing formats.", - sizeof(uint32_t), - 0, - parse_afmt, - NULL, - copy_opt, - copy_opt, - NULL, - NULL + // Please report any missing formats + .name = "Audio format", + .size = sizeof(uint32_t), + .parse = parse_afmt, + .copy = copy_opt, }; @@ -1385,16 +1175,11 @@ static int parse_time(const m_option_t *opt, struct bstr name, } const m_option_type_t m_option_type_time = { - "Time", - "", - sizeof(double), - 0, - parse_time, - print_double, - copy_opt, - copy_opt, - NULL, - NULL + .name = "Time", + .size = sizeof(double), + .parse = parse_time, + .print = print_double, + .copy = copy_opt, }; @@ -1449,16 +1234,10 @@ out: } const m_option_type_t m_option_type_time_size = { - "Time or size", - "", - sizeof(m_time_size_t), - 0, - parse_time_size, - NULL, - copy_opt, - copy_opt, - NULL, - NULL + .name = "Time or size", + .size = sizeof(m_time_size_t), + .parse = parse_time_size, + .copy = copy_opt, }; @@ -1668,16 +1447,8 @@ static int parse_obj_params(const m_option_t *opt, struct bstr name, const m_option_type_t m_option_type_obj_params = { - "Object params", - "", - 0, - 0, - parse_obj_params, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Object params", + .parse = parse_obj_params, }; /// Some predefined types as a definition would be quite lengthy @@ -2007,16 +1778,12 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst, } const m_option_type_t m_option_type_obj_settings_list = { - "Object settings list", - "", - sizeof(m_obj_settings_t *), - M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, - parse_obj_settings_list, - NULL, - copy_obj_settings_list, - copy_obj_settings_list, - copy_obj_settings_list, - free_obj_settings_list, + .name = "Object settings list", + .size = sizeof(m_obj_settings_t *), + .flags = M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD, + .parse = parse_obj_settings_list, + .copy = copy_obj_settings_list, + .free = free_obj_settings_list, }; @@ -2093,16 +1860,8 @@ static int parse_obj_presets(const m_option_t *opt, struct bstr name, const m_option_type_t m_option_type_obj_presets = { - "Object presets", - "", - 0, - 0, - parse_obj_presets, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Object presets", + .parse = parse_obj_presets, }; static int parse_custom_url(const m_option_t *opt, struct bstr name, @@ -2290,14 +2049,6 @@ static int parse_custom_url(const m_option_t *opt, struct bstr name, /// TODO : Write the other needed funcs for 'normal' options const m_option_type_t m_option_type_custom_url = { - "Custom URL", - "", - 0, - 0, - parse_custom_url, - NULL, - NULL, - NULL, - NULL, - NULL + .name = "Custom URL", + .parse = parse_custom_url, }; diff --git a/m_option.h b/m_option.h index 5c1441c303..8aa3f41da5 100644 --- a/m_option.h +++ b/m_option.h @@ -55,28 +55,9 @@ extern const m_option_type_t m_option_type_subconfig; extern const m_option_type_t m_option_type_imgfmt; extern const m_option_type_t m_option_type_afmt; -// Func-based types -extern const m_option_type_t m_option_type_func_param; -extern const m_option_type_t m_option_type_func; - -// Callback used to reset func options. -typedef void (*m_opt_default_func_t)(const m_option_t *, const char *); - -// Callback used by m_option_type_func_full options. +// Callback used by m_option_type_print_func options. typedef int (*m_opt_func_full_t)(const m_option_t *, const char *, const char *); -// Callback used by m_option_type_func_param options. -typedef int (*m_opt_func_param_t)(const m_option_t *, const char *); - -// Callback used by m_option_type_func options. -typedef int (*m_opt_func_t)(const m_option_t *); - -// Backwards compatibility -typedef m_opt_default_func_t cfg_default_func_t; -typedef m_opt_func_full_t cfg_func_arg_param_t; -typedef m_opt_func_param_t cfg_func_param_t; -typedef m_opt_func_t cfg_func_t; - #define END_AT_NONE 0 #define END_AT_TIME 1 #define END_AT_SIZE 2 @@ -175,8 +156,6 @@ struct m_opt_choice_alternatives { #define CONF_TYPE_FLOAT (&m_option_type_float) #define CONF_TYPE_DOUBLE (&m_option_type_double) #define CONF_TYPE_STRING (&m_option_type_string) -#define CONF_TYPE_FUNC (&m_option_type_func) -#define CONF_TYPE_FUNC_PARAM (&m_option_type_func_param) #define CONF_TYPE_PRINT (&m_option_type_print) #define CONF_TYPE_PRINT_INDIRECT (&m_option_type_print_indirect) #define CONF_TYPE_PRINT_FUNC (&m_option_type_print_func) @@ -198,8 +177,6 @@ struct m_opt_choice_alternatives { // Option type description struct m_option_type { const char *name; - // Syntax description, etc - const char *comments; // Size needed for the data. unsigned int size; // See \ref OptionTypeFlags. @@ -229,35 +206,12 @@ struct m_option_type { */ char *(*print)(const m_option_t *opt, const void *val); - /** \name - * These functions are called to save/set/restore the status of the - * variables. The difference between the 3 only matters for types like - * \ref m_option_type_func where 'setting' needs to do more than just - * copying some data. - */ - //@{ - - // Update a save slot (dst) from the current value in the program (src). - /** \param opt The option to copy. - * \param dst Pointer to the destination memory. - * \param src Pointer to the source memory. - */ - void (*save)(const m_option_t *opt, void *dst, const void *src); - - // Set the value in the program (dst) from a save slot. - /** \param opt The option to copy. - * \param dst Pointer to the destination memory. - * \param src Pointer to the source memory. - */ - void (*set)(const m_option_t *opt, void *dst, const void *src); - - // Copy the data between two save slots. If NULL and size is > 0 a memcpy will be used. + // Copy data between two locations. Deep copy if the data has pointers. /** \param opt The option to copy. * \param dst Pointer to the destination memory. * \param src Pointer to the source memory. */ void (*copy)(const m_option_t *opt, void *dst, const void *src); - //@} // Free the data allocated for a save slot. /** This is only needed for dynamic types like strings. @@ -296,7 +250,6 @@ struct m_option { // Type dependent data (for all kinds of extended settings). /** This used to be a function pointer to hold a 'reverse to defaults' func. * Now it can be used to pass any type of extra args needed by the parser. - * Passing a 'default func' is still valid for all func based option types. */ void *priv; @@ -379,17 +332,6 @@ struct m_option { */ #define M_OPT_TYPE_DYNAMIC (1 << 2) -// Indirect option type. -/** If this is set the parse function doesn't directly return - * the wanted thing. Options use this if for some reasons they have to wait - * until the set call to be able to correctly set the target var. - * So for those types new values must first be parsed, then set to the target - * var. If this flag isn't set then new values can be parsed directly to the - * target var. It's used by the callback-based options as the callback call - * may append later on. - */ -#define M_OPT_TYPE_INDIRECT (1 << 3) - ///////////////////////////// Parser flags ///////////////////////////////// // On success parsers return the number of arguments consumed: 0 or 1. @@ -421,13 +363,6 @@ struct m_option { */ #define M_OPT_EXIT -6 -// These are kept for compatibility with older code. -// -#define ERR_NOT_AN_OPTION M_OPT_UNKNOWN -#define ERR_MISSING_PARAM M_OPT_MISSING_PARAM -#define ERR_OUT_OF_RANGE M_OPT_OUT_OF_RANGE -#define ERR_FUNC_ERR M_OPT_PARSER_ERR - char *m_option_strerror(int code); // Find the option matching the given name in the list. @@ -470,8 +405,6 @@ static inline void m_option_copy(const m_option_t *opt, void *dst, { if (opt->type->copy) opt->type->copy(opt, dst, src); - else if (opt->type->size > 0) - memcpy(dst, src, opt->type->size); } // Helper around \ref m_option_type::free. diff --git a/m_struct.c b/m_struct.c index 764f616a89..8b34cea359 100644 --- a/m_struct.c +++ b/m_struct.c @@ -48,13 +48,6 @@ m_struct_alloc(const m_struct_t* st) { mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Struct %s needs defaults\n",st->name); return NULL; } - // Check the struct fields - for(i = 0 ; st->fields[i].name ; i++) { - if(st->fields[i].type->flags & M_OPT_TYPE_INDIRECT) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Struct %s->%s: Option types with the indirect flag are forbidden.\n",st->name,st->fields[i].name); - return NULL; - } - } r = calloc(1,st->size); memcpy(r,st->defaults,st->size); @@ -148,12 +148,6 @@ char *heartbeat_cmd; // Config file //**************************************************************************// -static int cfg_inc_verbose(m_option_t *conf) -{ - ++verbose; - return 0; -} - #include "path.h" //**************************************************************************// @@ -864,9 +858,9 @@ static void exit_sighandler(int x) #include "cfg-mplayer.h" -static int cfg_include(m_option_t *conf, char *filename) +static int cfg_include(struct m_config *conf, char *filename) { - return m_config_parse_config_file(conf->priv, filename); + return m_config_parse_config_file(conf, filename); } #define DEF_CONFIG "# Write your default config options here!\n\n\n" @@ -2541,9 +2535,6 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts) current_module = "play_audio"; - if (ao->untimed && mpctx->sh_video && mpctx->delay > 0) - return 0; - // hack used by some mpeg-writing AOs ao->brokenpts = ((mpctx->sh_video ? mpctx->sh_video->timer : 0) + mpctx->delay) * 90000.0; @@ -3465,9 +3456,9 @@ static void run_playloop(struct MPContext *mpctx) pause_player(mpctx); } - if (mpctx->sh_audio && !mpctx->restart_playback) { + if (mpctx->sh_audio && !mpctx->restart_playback && !mpctx->ao->untimed) { int status = fill_audio_out_buffers(mpctx, endpts); - full_audio_buffers = status >= 0 && !mpctx->ao->untimed; + full_audio_buffers = status >= 0; // Not at audio stream EOF yet audio_left = status > -2; } @@ -3679,15 +3670,16 @@ static void run_playloop(struct MPContext *mpctx) } #endif - if (mpctx->restart_playback && !video_left) { - if (mpctx->sh_audio) { - int status = fill_audio_out_buffers(mpctx, endpts); - full_audio_buffers = status >= 0 && !mpctx->ao->untimed; - // Not at audio stream EOF yet - audio_left = status > -2; - } - mpctx->restart_playback = false; + if (mpctx->sh_audio && (mpctx->restart_playback ? !video_left : + mpctx->ao->untimed && (mpctx->delay <= 0 || + !video_left))) { + int status = fill_audio_out_buffers(mpctx, endpts); + full_audio_buffers = status >= 0 && !mpctx->ao->untimed; + // Not at audio stream EOF yet + audio_left = status > -2; } + if (!video_left) + mpctx->restart_playback = false; if (mpctx->sh_audio && buffered_audio == -1) buffered_audio = mpctx->paused ? 0 : ao_get_delay(mpctx->ao); @@ -3736,7 +3728,7 @@ static void run_playloop(struct MPContext *mpctx) double audio_sleep = 9; if (mpctx->sh_audio && !mpctx->paused) { if (mpctx->ao->untimed) { - if (!mpctx->sh_video) + if (!video_left) audio_sleep = 0; } else if (full_audio_buffers) { audio_sleep = buffered_audio - 0.050; @@ -3961,7 +3953,7 @@ int main(int argc, char *argv[]) mp_input_register_options(mpctx->mconfig); // Preparse the command line - m_config_preparse_command_line(mpctx->mconfig, argc, argv); + m_config_preparse_command_line(mpctx->mconfig, argc, argv, &verbose); #if (defined(__MINGW32__) || defined(__CYGWIN__)) && defined(CONFIG_WIN32DLL) set_path_env(); diff --git a/parser-mpcmd.c b/parser-mpcmd.c index 49b4e0c5fd..93011d3760 100644 --- a/parser-mpcmd.c +++ b/parser-mpcmd.c @@ -308,7 +308,8 @@ extern int mp_msg_levels[]; * command line parsing), and --really-quiet suppresses messages printed * during normal options parsing. */ -int m_config_preparse_command_line(m_config_t *config, int argc, char **argv) +int m_config_preparse_command_line(m_config_t *config, int argc, char **argv, + int *verbose) { int ret = 0; @@ -330,6 +331,11 @@ int m_config_preparse_command_line(m_config_t *config, int argc, char **argv) // Ignore invalid options if (map_to_option(config, old_syntax, NULL, &opt, ¶m) < 0) continue; + // "-v" is handled here + if (!bstrcmp0(opt, "v")) { + (*verbose)++; + continue; + } // Set, non-pre-parse options will be ignored int r = m_config_set_option(config, opt, param, old_syntax); if (r < 0) diff --git a/parser-mpcmd.h b/parser-mpcmd.h index 3de9f626b5..948105ab6f 100644 --- a/parser-mpcmd.h +++ b/parser-mpcmd.h @@ -24,6 +24,7 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, char **argv); -int m_config_preparse_command_line(m_config_t *config, int argc, char **argv); +int m_config_preparse_command_line(m_config_t *config, int argc, char **argv, + int *verbose); #endif /* MPLAYER_PARSER_MPCMD_H */ diff --git a/sub/font_load_ft.c b/sub/font_load_ft.c index a501cfc750..eb6d70b657 100644 --- a/sub/font_load_ft.c +++ b/sub/font_load_ft.c @@ -1160,7 +1160,7 @@ void load_font_ft(int width, int height, font_desc_t** fontp, const char *font_n FcConfigSubstitute(0, fc_pattern, FcMatchPattern); FcDefaultSubstitute(fc_pattern); fc_pattern2 = fc_pattern; - fc_pattern = FcFontMatch(0, fc_pattern, 0); + fc_pattern = FcFontMatch(0, fc_pattern, &result); FcPatternDestroy(fc_pattern2); } // s doesn't need to be freed according to fontconfig docs |