summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-05-23 01:10:54 +0200
committerwm4 <wm4@nowhere>2013-05-23 01:10:54 +0200
commitd576e2acbd2eff75a1826b7157cfcb9bc43948a3 (patch)
tree9b7aac8300ed97aa078cf1b072190ba84e8ff6a2
parent88e8b1827fde1c33571214deb7212202af3c77a9 (diff)
parent5bdf9d01cafd451fa971e94d5f2dab982338130a (diff)
downloadmpv-d576e2acbd2eff75a1826b7157cfcb9bc43948a3.tar.bz2
mpv-d576e2acbd2eff75a1826b7157cfcb9bc43948a3.tar.xz
Merge branch 'master' into libxmp
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml29
-rw-r--r--Copyright66
-rw-r--r--DOCS/OUTDATED-tech/Doxyfile1142
-rw-r--r--DOCS/OUTDATED-tech/codecs.conf.txt214
-rw-r--r--DOCS/OUTDATED-tech/colorspaces.txt158
-rw-r--r--DOCS/OUTDATED-tech/dr-methods.txt129
-rw-r--r--DOCS/OUTDATED-tech/libmpcodecs.txt383
-rw-r--r--DOCS/OUTDATED-tech/manpage.txt283
-rw-r--r--DOCS/OUTDATED-tech/realcodecs/TODO22
-rw-r--r--DOCS/OUTDATED-tech/realcodecs/audio-codecs.txt155
-rw-r--r--DOCS/OUTDATED-tech/realcodecs/streaming.txt58
-rw-r--r--DOCS/OUTDATED-tech/realcodecs/video-codecs.txt185
-rw-r--r--DOCS/OUTDATED-tech/slave.txt592
-rw-r--r--DOCS/OUTDATED-tech/subcp.txt42
-rw-r--r--DOCS/OUTDATED-tech/win32-codec-howto.txt118
-rw-r--r--DOCS/encoding.rst8
-rw-r--r--DOCS/man/en/af.rst108
-rw-r--r--DOCS/man/en/changes.rst13
-rw-r--r--DOCS/man/en/input.rst101
-rw-r--r--DOCS/man/en/mpv.rst70
-rw-r--r--DOCS/man/en/options.rst519
-rw-r--r--DOCS/man/en/vf.rst62
-rw-r--r--DOCS/man/en/vo.rst48
-rw-r--r--DOCS/tech-overview.txt6
-rw-r--r--Makefile54
-rw-r--r--README.md (renamed from README.rst)40
-rwxr-xr-xTOOLS/mpv_identify.sh8
-rwxr-xr-xTOOLS/osxbundle.py71
-rw-r--r--TOOLS/osxbundle/mpv.app/Contents/Info.plist2
-rw-r--r--TOOLS/uncrustify.cfg7
-rw-r--r--TOOLS/vf_dlopen/Makefile25
-rw-r--r--TOOLS/vf_dlopen/filterutils.c21
-rw-r--r--TOOLS/vf_dlopen/filterutils.h21
-rw-r--r--TOOLS/vf_dlopen/framestep.c104
-rw-r--r--TOOLS/vf_dlopen/rectangle.c21
-rw-r--r--TOOLS/vf_dlopen/showqscale.c21
-rw-r--r--TOOLS/vf_dlopen/telecine.c21
-rw-r--r--TOOLS/vf_dlopen/tile.c21
-rw-r--r--audio/audio.c76
-rw-r--r--audio/audio.h46
-rw-r--r--audio/chmap.c489
-rw-r--r--audio/chmap.h132
-rw-r--r--audio/chmap_sel.c210
-rw-r--r--audio/chmap_sel.h43
-rw-r--r--audio/decode/ad.c4
-rw-r--r--audio/decode/ad.h17
-rw-r--r--audio/decode/ad_internal.h10
-rw-r--r--audio/decode/ad_lavc.c207
-rw-r--r--audio/decode/ad_mpg123.c20
-rw-r--r--audio/decode/ad_spdif.c114
-rw-r--r--audio/decode/dec_audio.c433
-rw-r--r--audio/decode/dec_audio.h10
-rw-r--r--audio/filter/af.c1096
-rw-r--r--audio/filter/af.h63
-rw-r--r--audio/filter/af_bs2b.c8
-rw-r--r--audio/filter/af_center.c5
-rw-r--r--audio/filter/af_channels.c47
-rw-r--r--audio/filter/af_delay.c5
-rw-r--r--audio/filter/af_drc.c (renamed from audio/filter/af_volnorm.c)47
-rw-r--r--audio/filter/af_dummy.c4
-rw-r--r--audio/filter/af_equalizer.c30
-rw-r--r--audio/filter/af_export.c6
-rw-r--r--audio/filter/af_extrastereo.c17
-rw-r--r--audio/filter/af_force.c146
-rw-r--r--audio/filter/af_format.c32
-rw-r--r--audio/filter/af_hrtf.c11
-rw-r--r--audio/filter/af_karaoke.c6
-rw-r--r--audio/filter/af_ladspa.c38
-rw-r--r--audio/filter/af_lavcac3enc.c125
-rw-r--r--audio/filter/af_lavcresample.c213
-rw-r--r--audio/filter/af_lavrresample.c401
-rw-r--r--audio/filter/af_pan.c24
-rw-r--r--audio/filter/af_resample.c394
-rw-r--r--audio/filter/af_resample_template.c171
-rw-r--r--audio/filter/af_scaletempo.c14
-rw-r--r--audio/filter/af_sinesuppress.c19
-rw-r--r--audio/filter/af_sub.c5
-rw-r--r--audio/filter/af_surround.c12
-rw-r--r--audio/filter/af_sweep.c8
-rw-r--r--audio/filter/af_tools.c4
-rw-r--r--audio/filter/af_volume.c33
-rw-r--r--audio/filter/control.h127
-rw-r--r--audio/fmt-conversion.c65
-rw-r--r--audio/fmt-conversion.h (renamed from demux/mp_taglists.h)13
-rw-r--r--audio/format.c18
-rw-r--r--audio/format.h9
-rw-r--r--audio/mixer.c7
-rw-r--r--audio/mixer.h2
-rw-r--r--audio/out/ao.c43
-rw-r--r--audio/out/ao.h27
-rw-r--r--audio/out/ao_alsa.c1345
-rw-r--r--audio/out/ao_coreaudio.c24
-rw-r--r--audio/out/ao_dsound.c93
-rw-r--r--audio/out/ao_jack.c30
-rw-r--r--audio/out/ao_lavc.c116
-rw-r--r--audio/out/ao_null.c11
-rw-r--r--audio/out/ao_openal.c82
-rw-r--r--audio/out/ao_oss.c36
-rw-r--r--audio/out/ao_pcm.c38
-rw-r--r--audio/out/ao_portaudio.c11
-rw-r--r--audio/out/ao_pulse.c106
-rw-r--r--audio/out/ao_rsound.c13
-rw-r--r--audio/out/ao_sdl.c18
-rw-r--r--audio/out/audio_out_internal.h3
-rw-r--r--audio/reorder_ch.c1426
-rw-r--r--audio/reorder_ch.h111
-rw-r--r--compat/libav.h17
-rwxr-xr-xconfigure420
-rw-r--r--core/av_common.c103
-rw-r--r--core/av_common.h31
-rw-r--r--core/av_log.c7
-rw-r--r--core/bstr.c9
-rw-r--r--core/bstr.h7
-rw-r--r--core/cfg-mplayer.h301
-rw-r--r--core/codec-cfg.c607
-rw-r--r--core/codec-cfg.h79
-rw-r--r--core/codecs.c147
-rw-r--r--core/codecs.h43
-rw-r--r--core/command.c569
-rw-r--r--core/command.h1
-rw-r--r--core/defaultopts.c66
-rw-r--r--core/encode.h1
-rw-r--r--core/encode_lavc.c14
-rw-r--r--core/encode_lavc.h2
-rw-r--r--core/input/appleir.c155
-rw-r--r--core/input/ar.c469
-rw-r--r--core/input/ar.h35
-rw-r--r--core/input/input.c607
-rw-r--r--core/input/input.h12
-rw-r--r--core/input/joystick.c10
-rw-r--r--core/input/keycodes.h303
-rw-r--r--core/m_config.c226
-rw-r--r--core/m_config.h47
-rw-r--r--core/m_option.c1221
-rw-r--r--core/m_option.h252
-rw-r--r--core/m_property.c4
-rw-r--r--core/mp_common.c74
-rw-r--r--core/mp_common.h13
-rw-r--r--core/mp_core.h46
-rw-r--r--core/mp_fifo.c12
-rw-r--r--core/mp_msg.c19
-rw-r--r--core/mp_msg.h2
-rw-r--r--core/mp_osd.h2
-rw-r--r--core/mpc_info.h44
-rw-r--r--core/mplayer.c1495
-rw-r--r--core/mplayer.h8
-rw-r--r--core/options.h140
-rw-r--r--core/parser-cfg.c135
-rw-r--r--core/parser-mpcmd.c141
-rw-r--r--core/parser-mpcmd.h6
-rw-r--r--core/path.c45
-rw-r--r--core/path.h2
-rw-r--r--core/screenshot.c53
-rw-r--r--core/screenshot.h4
-rw-r--r--core/timeline/tl_edl.c2
-rw-r--r--core/timeline/tl_matroska.c123
-rw-r--r--demux/asfheader.c4
-rw-r--r--demux/aviheader.c3
-rw-r--r--demux/codec_tags.c380
-rw-r--r--demux/codec_tags.h31
-rw-r--r--demux/demux.c461
-rw-r--r--demux/demux.h29
-rw-r--r--demux/demux_asf.c3
-rw-r--r--demux/demux_avi.c11
-rw-r--r--demux/demux_lavf.c538
-rw-r--r--demux/demux_mf.c102
-rw-r--r--demux/demux_mkv.c1330
-rw-r--r--demux/demux_mng.c16
-rw-r--r--demux/demux_mpg.c19
-rw-r--r--demux/demux_packet.h3
-rw-r--r--demux/demux_rawaudio.c24
-rw-r--r--demux/demux_rawvideo.c37
-rw-r--r--demux/demux_ts.c18
-rw-r--r--demux/ebml.c81
-rw-r--r--demux/ebml.h6
-rw-r--r--demux/matroska.h7
-rw-r--r--demux/mf.c10
-rw-r--r--demux/mp_taglists.c158
-rw-r--r--demux/stheader.h56
-rw-r--r--demux/video.c10
-rw-r--r--etc/codecs.conf2210
-rw-r--r--etc/encoding-example-profiles.conf12
-rw-r--r--etc/input.conf29
-rw-r--r--osdep/cocoa_events.h30
-rw-r--r--osdep/cocoa_events.m137
-rw-r--r--osdep/getch2-win.c28
-rw-r--r--osdep/getch2.c80
-rw-r--r--osdep/macosx_application.h56
-rw-r--r--osdep/macosx_application.m374
-rw-r--r--osdep/macosx_application_objc.h34
-rw-r--r--osdep/macosx_finder_args.h29
-rw-r--r--osdep/macosx_finder_args.m97
-rw-r--r--stream/cache2.c25
-rw-r--r--stream/cookies.c2
-rw-r--r--stream/dvb_tune.c4
-rw-r--r--stream/http.c20
-rw-r--r--stream/network.c2
-rw-r--r--stream/stream.c70
-rw-r--r--stream/stream.h17
-rw-r--r--stream/stream_bluray.c85
-rw-r--r--stream/stream_cdda.c33
-rw-r--r--stream/stream_cddb.c17
-rw-r--r--stream/stream_dvb.c7
-rw-r--r--stream/stream_dvd.c45
-rw-r--r--stream/stream_radio.c136
-rw-r--r--stream/stream_radio.h6
-rw-r--r--stream/tv.c24
-rw-r--r--stream/tvi_bsdbt848.c907
-rw-r--r--stream/tvi_v4l2.c27
-rw-r--r--stream/vcd_read.h21
-rw-r--r--stream/vcd_read_win32.h2
-rw-r--r--sub/ass_mp.c10
-rw-r--r--sub/dec_sub.c25
-rw-r--r--sub/dec_sub.h7
-rw-r--r--sub/draw_bmp.c6
-rw-r--r--sub/find_subfiles.c1
-rw-r--r--sub/osd_font.otfbin0 -> 2276 bytes
-rw-r--r--sub/osd_font.pfbbin8322 -> 0 bytes
-rw-r--r--sub/osd_libass.c276
-rw-r--r--sub/sd.h1
-rw-r--r--sub/sd_ass.c17
-rw-r--r--sub/sd_lavc.c35
-rw-r--r--sub/sub.c32
-rw-r--r--sub/sub.h16
-rw-r--r--sub/subassconvert.c198
-rw-r--r--sub/subreader.c18
-rw-r--r--sub/subreader.h1
-rwxr-xr-xtravis-deps92
-rwxr-xr-xversion.sh2
-rw-r--r--video/csputils.c40
-rw-r--r--video/csputils.h2
-rw-r--r--video/decode/dec_video.c259
-rw-r--r--video/decode/dec_video.h11
-rw-r--r--video/decode/lavc.h12
-rw-r--r--video/decode/vd.c31
-rw-r--r--video/decode/vd.h14
-rw-r--r--video/decode/vd_lavc.c479
-rw-r--r--video/filter/vf.c27
-rw-r--r--video/filter/vf.h7
-rw-r--r--video/filter/vf_divtc.c5
-rw-r--r--video/filter/vf_dlopen.c42
-rw-r--r--video/filter/vf_flip.c5
-rw-r--r--video/filter/vf_gradfun.c2
-rw-r--r--video/filter/vf_hqdn3d.c2
-rw-r--r--video/filter/vf_lavfi.c343
-rw-r--r--video/filter/vf_phase.c2
-rw-r--r--video/filter/vf_pp.c10
-rw-r--r--video/filter/vf_rotate.c13
-rw-r--r--video/filter/vf_scale.c44
-rw-r--r--video/filter/vf_stereo3d.c70
-rw-r--r--video/filter/vf_sub.c7
-rw-r--r--video/filter/vf_vo.c10
-rw-r--r--video/filter/vf_yadif.c33
-rw-r--r--video/fmt-conversion.c9
-rw-r--r--video/image_writer.c42
-rw-r--r--video/img_format.c12
-rw-r--r--video/img_format.h10
-rw-r--r--video/img_fourcc.h10
-rw-r--r--video/mp_image.c150
-rw-r--r--video/mp_image.h12
-rw-r--r--video/out/aspect.c100
-rw-r--r--video/out/aspect.h10
-rw-r--r--video/out/bitmap_packer.c4
-rw-r--r--video/out/cocoa_common.h7
-rw-r--r--video/out/cocoa_common.m745
-rw-r--r--video/out/gl_cocoa.c75
-rw-r--r--video/out/gl_common.c758
-rw-r--r--video/out/gl_common.h70
-rw-r--r--video/out/gl_header_fixes.h15
-rw-r--r--video/out/gl_lcms.c219
-rw-r--r--video/out/gl_lcms.h16
-rw-r--r--video/out/gl_osd.c54
-rw-r--r--video/out/gl_osd.h14
-rw-r--r--video/out/gl_video.c1843
-rw-r--r--video/out/gl_video.h73
-rw-r--r--video/out/gl_video_shaders.glsl (renamed from video/out/vo_opengl_shaders.glsl)56
-rw-r--r--video/out/gl_w32.c218
-rw-r--r--video/out/gl_wayland.c254
-rw-r--r--video/out/gl_x11.c317
-rw-r--r--video/out/osx_common.m30
-rw-r--r--video/out/vo.c160
-rw-r--r--video/out/vo.h77
-rw-r--r--video/out/vo_caca.c129
-rw-r--r--video/out/vo_corevideo.m108
-rw-r--r--video/out/vo_direct3d.c31
-rw-r--r--video/out/vo_image.c9
-rw-r--r--video/out/vo_lavc.c5
-rw-r--r--video/out/vo_null.c5
-rw-r--r--video/out/vo_opengl.c2162
-rw-r--r--video/out/vo_opengl_old.c138
-rw-r--r--video/out/vo_sdl.c195
-rw-r--r--video/out/vo_vdpau.c18
-rw-r--r--video/out/vo_x11.c242
-rw-r--r--video/out/vo_xv.c52
-rw-r--r--video/out/w32_common.c230
-rw-r--r--video/out/w32_common.h7
-rw-r--r--video/out/wayland_common.c864
-rw-r--r--video/out/wayland_common.h135
-rw-r--r--video/out/x11_common.c1255
-rw-r--r--video/out/x11_common.h47
-rw-r--r--video/vfcap.h2
302 files changed, 19109 insertions, 23646 deletions
diff --git a/.gitignore b/.gitignore
index 7ceff799c5..79fa978ed4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,11 +10,10 @@
/mpv
/mpv.app
/version.h
-/core/codecs.conf.h
/core/input/input_conf.h
/tags
/TAGS
-/video/out/vo_opengl_shaders.h
+/video/out/gl_video_shaders.h
/video/out/vdpau_template.c
/demux/ebml_defs.c
/demux/ebml_types.h
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000..b932ae8463
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,29 @@
+language: c
+
+env:
+ - LIBAV=libav-stable
+ - LIBAV=libav-git
+ - LIBAV=ffmpeg-stable
+ - LIBAV=ffmpeg-git
+compiler:
+ - clang
+branches:
+ only:
+ - master
+
+before_install: ./travis-deps libass-stable $LIBAV
+script: ./configure && make
+
+notifications-policy: &notifications-policy
+ on_success: change
+ on_failure: always
+
+notifications:
+ email:
+ recipients:
+ - mpv-team@googlegroups.com
+ <<: *notifications-policy
+ irc:
+ channels:
+ - "irc.freenode.org#mpv-player-dev"
+ <<: *notifications-policy
diff --git a/Copyright b/Copyright
index c0f3970949..a907bf4346 100644
--- a/Copyright
+++ b/Copyright
@@ -19,77 +19,17 @@ license details are listed below:
Name: a couple of files copied from FFmpeg
Version: updated to different versions
URL: http://www.ffmpeg.org
-Directory: ffmpeg_files
+Directory: compat/x86_cpu.h
Copyright: Many, see individual files for copyright notices.
License: GNU Lesser General Public License
-Name: avifile DLL loader
-Version: 0.47 + patches + CVS updates
-URL: http://avifile.sourceforge.net/
-Directory: loader/
-Copyright: 1993 Robert J. Amstadt
- 1994 Eric Youndale & Erik Bos
- 1995 Thomas Sandford
- 1995-1996 Alexandre Julliard
- 1996-1998 Marcus Meissner
- 1996 Martin von Loewis
- 2000-2001 Eugene Kuznetsov (divx@euro.ru)
-License: GNU General Public License
-
-
Name: dvbstream
Version: 0.4.3-pre3 (CVS checkout)
URL: http://sourceforge.net/projects/dvbtools/
-Directory: stream/dvbin.h stream/rtp.c stream/stream_dvb.c
+Directory: stream/dvbin.h stream/stream_dvb.c
Copyright: 2001-2002 Dave Chapman <dave@dchapman.com>
License: GNU General Public License
-Name: librtsp
-Version: xine CVS 2003/04/10 + patches
-URL: http://www.xinehq.de
-Directory: stream/librtsp/
-Copyright: 2000-2002 the xine project
-License: GNU General Public License
-
-
-Name: realrtsp
-Version: xine CVS 2003/04/17 + patches
-URL: http://www.xinehq.de
-Directory: stream/realrtsp/
-Copyright: 2002 the xine project
-License: GNU General Public License
-
-
-Name: pnm protocol implementation
-Version: xine CVS 2002/12/26 + patches
-URL: http://www.xinehq.de
-Directory: stream/pnm.[ch]
-Copyright: 2000-2002 the xine project
-License: GNU General Public License
-
-
-Name: id3edit
-Version: 1.9 + patches
-URL: http://id3edit.sourceforge.net/
-Directory: libmpdemux/genres.h
-Copyright: 2001 Jason Carter
-License: GNU General Public License
-
-
-Name: FreeSDP
-Version: 0.4.1
-URL: https://savannah.nongnu.org/projects/freesdp/
-Directory: stream/freesdp/
-Copyright: 2001-2003 Federico Montesino Pouzols <fedemp@suidzer0.org>
-License: GNU General Public License
-
-
-Name: MJPEG Tools
-Version: post 2001-12-03 release or CVS snapshot
-URL: http://mjpeg.sourceforge.net/
-Directory: libmpdemux/yuv4mpeg*
-Copyright: 2001 Matthew J. Marjanovic <maddog@mir.com>
- 2001 Andrew Stevens <andrew.stevens@philips.com>
-License: GNU General Public License
+This is not a complete list. grep the sources for "Copyright".
diff --git a/DOCS/OUTDATED-tech/Doxyfile b/DOCS/OUTDATED-tech/Doxyfile
deleted file mode 100644
index 1a9a036bef..0000000000
--- a/DOCS/OUTDATED-tech/Doxyfile
+++ /dev/null
@@ -1,1142 +0,0 @@
-# Doxyfile 1.3.7
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME = MPlayer
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = DOCS/tech/doxygen
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 2 levels of 10 sub-directories under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of source
-# files, where putting all generated files in the same directory would otherwise
-# cause performance problems for the file system.
-
-CREATE_SUBDIRS = YES
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
-# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
-# (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese,
-# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
-
-OUTPUT_LANGUAGE = English
-
-# This tag can be used to specify the encoding used in the generated output.
-# The encoding is not always determined by the language that is chosen,
-# but also whether or not the output is meant for Windows or non-Windows users.
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
-# forces the Windows encoding (this is the default for the Windows binary),
-# whereas setting the tag to NO uses a Unix-style encoding (the default for
-# all platforms other than Windows).
-
-USE_WINDOWS_ENCODING = NO
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is used
-# as the annotated text. Otherwise, the brief description is used as-is. If left
-# blank, the following values are used ("$name" is automatically replaced with the
-# name of the entity): "The $name class" "The $name widget" "The $name file"
-# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
-# members of a class in the documentation of that class as if those members were
-# ordinary class members. Constructors, destructors and assignment operators of
-# the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = YES
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explicit @brief command for a brief description.
-
-JAVADOC_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member
-# documentation.
-
-DETAILS_AT_TOP = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 8
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
-# only. Doxygen will then generate output that is more tailored for Java.
-# For instance, namespaces will be presented as packages, qualified scopes
-# will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = YES
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = NO
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT =
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
-# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
-
-FILE_PATTERNS =
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE = DOCS TOOLS
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
-# that are symbolic links (a Unix filesystem feature) are excluded from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-
-EXCLUDE_PATTERNS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-
-INPUT_FILTER =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = YES
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES (the default)
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES (the default)
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = YES
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 2
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET =
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
-# probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse the
-# parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off. Note that this
-# option is superseded by the HAVE_DOT option below. This is only a fallback. It is
-# recommended to install and use dot, since it yields more powerful graphs.
-
-CLASS_DIAGRAMS = NO
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = NO
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a call dependency graph for every global function or class method.
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-
-CALL_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_WIDTH = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_HEIGHT = 1024
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes that
-# lay further from the root node will be omitted. Note that setting this option to
-# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that a graph may be further truncated if the graph's image dimensions are
-# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
-# If 0 is used for the depth value (the default), the graph is not depth-constrained.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE = NO
diff --git a/DOCS/OUTDATED-tech/codecs.conf.txt b/DOCS/OUTDATED-tech/codecs.conf.txt
deleted file mode 100644
index 75f480933f..0000000000
--- a/DOCS/OUTDATED-tech/codecs.conf.txt
+++ /dev/null
@@ -1,214 +0,0 @@
-Understanding MPlayer's etc/codecs.conf File
-
-Introduction
-------------
-MPlayer features a very flexible codec architecture which allows it to
-use its own open source codecs, as well as open source libraries, Win32
-codec DLLs and other binary codec modules. To the MPlayer user, the
-most visible piece of this architecture is the etc/codecs.conf file. This
-is a text-based configuration file that controls which MPlayer components
-are in charge of handling particular compressed data formats.
-
-The codecs.conf file is stored either in a shared directory for all system
-users to access, or in the .mplayer directory in a user's home
-directory. When MPlayer starts, it first looks for a codecs.conf file in a
-user's home directory. Failing that, it searches for the shared file. If
-no codecs.conf file is found MPlayer falls back on its internal hardcoded
-configuration. If the file is present but has syntax errors, MPlayer will
-report the error.
-
-The codecs.conf file is really quite simple. It is simply a collection of
-codec definition blocks that define how different media types should be
-handled. There are a number of keywords that can occur in a block. Not all
-of them are required and no particular order is enforced.
-
-Editing codecs.conf
--------------------
-You can edit codecs.conf using your favorite text editor. Anything that
-comes after a semicolon (;) on a line is regarded as a comment. For
-example:
-; this is a comment
- format 0x34616d69 ; "ima4" (MOV files)
-
-The codec blocks can be in any order; the file parser doesn't
-care. However, they are organized in a particular order for the benefit of
-human readers. For example, all of the open source decoders that MPlayer
-implements natively are grouped in one section.
-
-Release Number
---------------
-Your codecs.conf now requires a release number to avoid codec release
-incompatibilities. The format is simple: (YYYYMMDD)
-
-release 20020520
-
-Whenever changes are made to the codecs that *require* an updated
-codecs.conf, then MPlayer will no longer accept outdated versions.
-It is not recommended to change this line unless you know exactly
-what you are doing.
-
-Video Codecs
-------------
-Let's jump right in with an example. Here is an example video codec block:
-
-videocodec indeo5ds
- info "Intel Indeo 5"
- status working
- fourcc IV50,iv50
- driver dshow
- dll "ir50_32.dll"
- guid 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
- out YV12
- out YUY2
- out BGR32,BGR24,BGR16,BGR15
-
-This is a particularly full-featured video codec. The "videocodec" keyword
-identifies the fact that this is the start of a new video
-codec. "indeo5ds" is MPlayer's unique name for the codec. You have to use
-this name with the -vc/-ac option.
-
-The next line has the keyword "info" which specifies a human-readable
-comment accompanying this codec. This is printed by -vc help / -ac help.
-
-The "status" keyword carries information about the codec's functional
-status. MPlayer currently recognizes 4 status levels: working, buggy,
-crashing, and untested. When it gets to codec auto-selection, it tries
-untested first (to force users to test it for us and report results :)),
-then working and finally buggy ones. Codecs marked crashing won't be tried,
-unless explicitly (-vc/-ac) selected.
-
-The next line lists 4-character codes (FOURCCs) that are associated with
-this codec. There can be more than one FOURCC specified on a fourcc line
-as long as they are separated with a comma. There can also be multiple
-fourcc lines in the codec. A second fourcc can also be given, separated
-with a space. MPlayer will replace the original fourcc in the headers with
-this one before opening the codec. It's useful for win32 codecs checking for
-the fourccs.
-
-The "driver" keyword associates this codec with an internal MPlayer
-decoder module. MPlayer has a module named "dshow" that handles data
-encoded by the codec. See -vfm help / -afm help for the available module list.
-
-The "dll" keyword specifies which Win32/XAnim/Real/Quicktime binary
-module needs to be loaded. It's also used to specify which FFmpeg codec
-to load. The list of FFmpeg codecs can be found in libavcodec/allcodecs.c.
-
-The "guid" keyword identifies a 16-byte Microsoft GUID that some media
-files use to identify codecs. Used only for win32 dshow and DMO codecs.
-
-The "out" keyword identifies which output format the decoder is known
-to provide. Just like the fourcc line, there can be multiple out lines or
-multiple comma-separated output formats on the same line. The output
-formats should be listed in order of preference.
-
-The outfmt values can be followed by one or more flags, like flip, noflip,
-static, query. The flags are defined as follows:
-
-"flip":
- If this flag is set for a given format, then o_bih->biHeight will NOT be
- set to -bih->biHeight, i.e. the image will be decoded upside-down.
- Used only by vfw and vfwex codecs.
-
-"noflip":
- This flag is ignored (no effect) without "flip" being set!
- If this flag is set, it means the codec doesn't decode upside-down,
- although it's told to do so.
-
-"yuvhack":
- This flag is required for the old win32 ms-mpeg4 vfw codecs, including
- MP42 and DIV3 (DivX 3.11). These DLLs actually support YUV formats,
- but the query/begin functions are buggy and don't accept YUV fourccs
- (the decode function accepts it and works well!)
- If this flag is set, then o_bih->biCompression will be set to 0 for
- the initialization for the YUV modes. Used only by vfw/vfwex codecs.
-
-"query":
- This flag is used to control VDCTRL_QUERY_FORMAT for vfw/vfewx codecs.
- If this flag is set, the control() will query the codec for the csp
- support, otherwise it will assume a constant csp table. Required for
- some DLLs (like huffyuv, CRAM).
-
-"static",
- This flag forces STATIC (instead of TEMP) buffer allocation for the codec.
- Used for some very old DLLs like Indeo 3 and for some XAnim codecs like
- cinepak. See dr-methods.txt for details on buffer types.
-
-The "in" keyword -- UNDOCUMENTED
-
-Audio Codecs
-------------
-Here is an example of a rather full-featured audio codec block:
-
-audiocodec mp3
- info "MPEG layer-2, layer-3"
- status working
- comment "Optimized to MMX/SSE/3Dnow!"
- format 0x50
- format 0x55
- format 0x33706d2e ; ".mp3" CBR/VBR MP3 (MOV files)
- format 0x5500736d ; "ms\0\x55" older mp3 fcc (MOV files)
- driver mp3lib
- dll "mp3lib (mpglib)"
- flags seekable
-
-Many of the keywords are the same as a video codec block. However, we see
-a few that we haven't seen before. The "comment" keyword identifies
-another human-readable note for this codec.
-
-The "format" keyword performs a similar job as the fourcc line. However,
-since certain media file formats (notably AVI) identify audio formats with
-16-bit numbers rather than 32-bit FOURCCs, it's necessary to use this
-convention to accommodate them. However, as shown in this example, FOURCCs
-can also be specified with the format keyword as long as they're converted
-to their hex representation. It's important to note that this can be
-useful for video codecs as well if a FOURCC contains a space (such as
-Apple's "rle " codec).
-
-The "flags" keywords identifies any additional abilities of this
-codec. Currently, seekable is the only supported flag.
-
-
-Adding FFmpeg Codecs
--------------------
-example codec:
-
-videocodec ffmdec
- info "FFmpeg Sony PlayStation MDEC (Motion DECoder)"
- status working
- fourcc MDEC ; internal MPlayer FourCC
- driver ffmpeg
- dll mdec
- out YV12
-
-The "videocodec" name should start with ff to differentiate it from other
-libraries or binary codecs.
-
-The "dll" name comes from the codec source file or the libavcodec/allcodecs.c
-file.
-
-The "out" colorspace can be found in the codec source file in the PIX_FMT
-struct. Note that some codecs may have several pix_fmt structs.
-The pix_fmt can be converted to the codecs.conf "out" format by reading
-the fmt-conversion.c file.
-
-If there are BE and LE versions of a pix_fmt, ignore them and use the short
-native format instead. e.g. 422P16_LE becomes out 422P16. also to note that
-underscores cause parse errors, so 422P16_LE becomes out 422P16LE.
-
-libmpdemux/mp_taglists.c
---------------
-Sometimes the lavf demuxer will not pass on a fourcc (mostly video game
-formats or other containers that do not support isom/riff tags). You will have
-to make one based on the codec_id listed in the codec source file.
-
-Note that it is a good idea to mark any fourcc you create as
-' ; internal MPlayer FourCC'. In case another codec uses that fourcc,
-you can easily change the internal one. Also this will stop other projects
-from thinking of the internal tag as a real fourcc found in the wild.
-
-libmpdemux/demuxer.c
---------------
-Some audio codecs require a parser, you can see which ones do
-by reading the parsers section in libavcodec/allcodecs.c.
-
-EOF
diff --git a/DOCS/OUTDATED-tech/colorspaces.txt b/DOCS/OUTDATED-tech/colorspaces.txt
deleted file mode 100644
index eaf9d221e4..0000000000
--- a/DOCS/OUTDATED-tech/colorspaces.txt
+++ /dev/null
@@ -1,158 +0,0 @@
-In general
-==========
-
-There are planar and packed modes.
-- Planar mode means: You have 3 separate images, one for each component,
-each image 8 bits/pixel. To get the real colored pixel, you have to
-mix the components from all planes. The resolution of planes may differ!
-- Packed mode means: you have all components mixed/interleaved together,
-so you have small "packs" of components in a single, big image.
-
-There are RGB and YUV colorspaces.
-- RGB: Red, Green and Blue components. Used by analog VGA monitors.
-- YUV: Luminance (Y) and Chrominance (U,V) components. Used by some
- video systems, like PAL. Also most M(J)PEG/DCT based codecs use this.
-
-With YUV, they used to reduce the resolution of U,V planes:
-The most common YUV formats:
-FOURCC: bpp: IEEE: plane sizes: (w=width h=height of original image)
-444P 24 YUV 4:4:4 Y: w * h U,V: w * h
-YUY2,UYVY 16 YUV 4:2:2 Y: w * h U,V: (w/2) * h [MJPEG]
-YV12,I420 12 YUV 4:2:0 Y: w * h U,V: (w/2) * (h/2) [MPEG, H.263]
-411P 12 YUV 4:1:1 Y: w * h U,V: (w/4) * h [DV-NTSC, CYUV]
-YVU9,IF09 9 YUV 4:1:0 Y: w * h U,V: (w/4) * (h/4) [Sorenson, Indeo]
-
-The YUV a:b:c naming style means: for <a> samples of Y there are <b> samples
-of UV in odd lines and <c> samples of UV in even lines.
-
-conversion: (some cut'n'paste from www and maillist)
-
-RGB to YUV Conversion:
- Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
- Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
- Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
-YUV to RGB Conversion:
- B = 1.164(Y - 16) + 2.018(U - 128)
- G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
- R = 1.164(Y - 16) + 1.596(V - 128)
-
-In both these cases, you have to clamp the output values to keep them in
-the [0-255] range. Rumour has it that the valid range is actually a subset
-of [0-255] (I've seen an RGB range of [16-235] mentioned) but clamping the
-values into [0-255] seems to produce acceptable results to me.
-
-Julien (sorry, I can't recall his surname) suggests that there are
-problems with the above formula and proposes the following instead:
- Y = 0.299R + 0.587G + 0.114B
- Cb = U'= (B-Y)*0.565
- Cr = V'= (R-Y)*0.713
-with reciprocal versions:
- R = Y + 1.403V'
- G = Y - 0.344U' - 0.714V'
- B = Y + 1.770U'
-Note: This formula doesn't contain the +128 offsets of U,V values!
-
-Conclusion:
-Y = luminance, the weighted average of R G B components. (0=black 255=white)
-U = Cb = blue component (0=green 128=grey 255=blue)
-V = Cr = red component (0=green 128=grey 255=red)
-
-
-Huh. The planar YUV modes.
-==========================
-
-The most misunderstood thingie...
-
-In MPlayer, we usually have 3 pointers to the Y, U and V planes, so it
-doesn't matter what the order of the planes in the memory is:
- for mp_image_t and libvo's draw_slice():
- planes[0] = Y = luminance
- planes[1] = U = Cb = blue
- planes[2] = V = Cr = red
- Note: planes[1] is ALWAYS U, and planes[2] is V, the FOURCC
- (YV12 vs. I420) doesn't matter here! So, every codec using 3 pointers
- (not only the first one) normally supports YV12 and I420 (=IYUV), too!
-
-But there are some codecs (VfW, dshow) and vo drivers (xv) ignoring the 2nd
-and 3rd pointer that use only a single pointer to the planar YUV image. In
-this case we must know the right order and alignment of planes in the memory!
-
-from the webartz fourcc list:
-YV12: 12 bpp, full sized Y plane followed by 2x2 subsampled V and U planes
-I420: 12 bpp, full sized Y plane followed by 2x2 subsampled U and V planes
-IYUV: the same as I420
-YVU9: 9 bpp, full sized Y plane followed by 4x4 subsampled V and U planes
-
-Huh 2. RGB vs. BGR ?
-====================
-
-The 2nd most misunderstood thingie...
-
-You know, there are Intel and Motorola, and they use different byteorder.
-There are also others, like MIPS or Alpha, but all follow either Intel
-or Motorola byteorder.
-Unfortunately, the packed colorspaces depend on CPU byteorder. So, RGB
-on Intel and Motorola means different order of bytes.
-
-In MPlayer, we have constants IMGFMT_RGBxx and IMGFMT_BGRxx.
-Unfortunately, some codecs and vo drivers follow Intel, some follow Motorola
-byteorder, so they are incompatible. We had to find a stable base, so long
-time ago I've chosen OpenGL, as it's a wide-spreaded standard, and it well
-defines what RGB is and what BGR is. So, MPlayer's RGB is compatible with
-OpenGL's GL_RGB on all platforms, and the same goes for BGR - GL_BGR.
-Unfortunately, most of the x86 codecs call our BGR RGB, so it sometimes
-confuses developers.
-
-memory order: name
-lowest address .. highest address
-RGBA IMGFMT_RGBA
-ARGB IMGFMT_ARGB
-BGRA IMGFMT_BGRA
-ABGR IMGFMT_ABGR
-RGB IMGFMT_RGB24
-BGR IMGFMT_BGR24
-
-order in an int name
-most significant .. least significant bit
-8A8R8G8B IMGFMT_BGR32
-8A8B8G8R IMGFMT_RGB32
-5R6G5B IMGFMT_BGR16
-5B6G5R IMGFMT_RGB16
-1A5R5G5B IMGFMT_BGR15
-1A5B5G5R IMGFMT_RGB15
-
-The following are palettized formats, the palette is in the second plane.
-When they come out of the swscaler (this can be different when they
-come from a codec!), their palette is organized in such a way
-that you actually get:
-
-3R3G2B IMGFMT_BGR8
-2B3G3R IMGFMT_RGB8
-1R2G1B IMGFMT_BGR4_CHAR
-1B2G1R IMGFMT_RGB4_CHAR
-1R2G1B1R2G1B IMGFMT_BGR4
-1B2G1R1B2G1R IMGFMT_RGB4
-
-Depending upon the CPU being little- or big-endian, different 'in memory' and
-'in register' formats will be equal (LE -> BGRA == BGR32 / BE -> ARGB == BGR32)
-
-Practical coding guide:
-
-The 4, 8, 15, and 16 bit formats are defined so that the portable way to
-access them is to load the pixel into an integer and use bitmasks.
-
-The 24 bit formats are defined so that the portable way to access them is
-to address the 3 components as separate bytes, as in ((uint8_t *)pixel)[0],
-((uint8_t *)pixel)[1], ((uint8_t *)pixel)[2].
-
-When a 32-bit format is identified by the four characters A, R, G, and B in
-some order, the portable way to access it is by addressing the 4 components
-as separate bytes.
-
-When a 32-bit format is identified by the 3 characters R, G, and B in some
-order followed by the number 32, the portable way to access it is to load
-the pixel into an integer and use bitmasks.
-
-When the above portable access methods are not used, you will need to write
-2 versions of your code, and use #if HAVE_BIGENDIAN to choose the correct
-one.
diff --git a/DOCS/OUTDATED-tech/dr-methods.txt b/DOCS/OUTDATED-tech/dr-methods.txt
deleted file mode 100644
index c8eac2aae3..0000000000
--- a/DOCS/OUTDATED-tech/dr-methods.txt
+++ /dev/null
@@ -1,129 +0,0 @@
-DIRECT RENDERING METHODS -- by A'rpi
-======================== (based on a mail to -dev-eng)
-
-Ok. It seems none of you really knows what direct rendering means...
-I'll try to explain now! :)
-
-At first, there are 2 different way, both called direct rendering.
-The main point is the same, but they work different.
-
-method 1: decoding directly to externally provided buffers.
-so, the codec decodes macroblocks directly to the buffer provided by the
-caller. as this buffer will be read later (for MC of next frame) it's not
-a good idea to place such buffers in slow video ram. but.
-there are many video out drivers using buffers in system ram, and using some
-way of memcpy or DMA to blit it to video ram at display time.
-for example, Xv and X11 (normal and Shm too) are such thingie.
-XImage will be a buffer in system ram (!) and X*PutImage will copy it to
-video ram. Only nvidia and ati rage128 Xv drivers use DMA, others just
-memcpy it. Also some opengl drivers (including Matrox) uses DMA to copy from
-texsubimage to video ram.
-The current mplayer way mean: codec allocates some buffer, and decode image
-to that buffer. then this buffer is copied to X11's buffer. then Xserver
-copies this buffer to video ram. So one more memcpy than required...
-direct rendering can remove this extra memcpy, and use Xserver's memory
-buffers for decoding buffer. Note again: it helps only if the external
-buffer is in fast system ram.
-
-method 2: decoding to internal buffers, but blit after each macroblocks,
-including optional colorspace conversion.
-advantages: it can blit into video ram, as it keeps the copy in its internal
-buffers for next frame's MC. skipped macroblocks won't be copied again to
-video ram (except if video buffer address changes between frames -> hw
-double/triple buffering)
-Just avoiding blitting of skipped MBs mean about 100% speedup (2 times
-faster) for low bitrate (<700kbit) divxes. It even makes possible to watch
-VCD resolution divx on p200mmx with DGA.
-how does it work? the codec works as normally, decodes macroblocks into its
-internal buffer. but after each decoded macroblock, it immediatelly copies
-this macroblock to the video ram. it's in the L1 cache, so it will be fast.
-skipped macroblocks can be skipped easily -> less vram write -> more speedup.
-but, as it copies directly to video ram, it must do colorspace conversion if
-needed (for example divx -> rgb DGA), and cannot be used with scaling.
-another interesting question of such direct rendering is the planar formats.
-Eugene K. of Divx4 told me that he experienced worse performance blittig
-yv12 blocks (copied 3 blocks to 3 different (Y,U,V) buffers) than doing
-(really unneeded) yv12->yuy2 conversion on-the-fly.
-so, divx4 codec (with -vc divx4 api) converts from its internal yv12 buffer
-to the external yuy2.
-
-method 2a:
-libmpeg2 already uses simplified variation of this: when it finish decoding a
-slice (a horizontal line of MBs) it copies it to external (video ram) buffer
-(using callback to libvo), so at least it copies from L2 cache instead of
-slow ram. for non-predictive (B) frames it can re-use this cached memory
-for the next slice - so it uses less memory and has better cache utilization:
-it gave me 23% -> 20% VOB decoding speedup on p3. libavcodec supports
-per-slice callbacks too, but no slice-memory reusing for B frames yet.
-
-method 2b:
-some codecs (indeo vfw 3/4 using IF09, and libavcodec) can export the 'bitmap'
-of skipped macroblocks - so libvo driver can do selective blitting: copy only
-the changed macroblocks to slow vram.
-
-so, again: the main difference between method 1 and 2:
-method1 stores decoded data only once: in the external read/write buffer.
-method2 stores decoded data twice: in its internal read/write buffer (for
-later reading) and in the write-only slow video ram.
-
-both methods can make big speedup, depending on codec behaviour and libvo
-driver. for example, IPB mpegs could combine these, use method 2 for I/P
-frames and method 1 for B frams. mpeg2dec does already this.
-for I-only type video (like mjpeg) method 1 is better. for I/P type video
-with MC (like divx, h263 etc) method 2 is the best choice.
-for I/P type videos without MC (like FLI, CVID) could use method 1 with
-static buffer or method 2 with double/triple buffering.
-
-i hope it is clear now.
-and i hope even nick understand what are we talking about...
-
-ah, and at the end, the abilities of codecs:
-libmpeg2,libavcodec: can do method 1 and 2 (but slice level copy, not MB level)
-vfw, dshow: can do method 2, with static or variable address external buffer
-odivx, and most native codecs like fli, cvid, rle: can do method 1
-divx4: can do method 2 (with old odivx api it does method 1)
-xanim: they currently can't do DR, but they exports their
-internal buffers. but it's very easy to implement menthod 1 support,
-and a bit harder but possible without any rewrite to do method 2.
-
-so, dshow and divx4 already implements all requirements of method 2.
-libmpeg2 and libavcodec implements method 1 and 2a (lavc 2b too)
-
-anyway, in the ideal world, we need all codecs support both methods.
-anyway 2: in ideal world, there are no libvo drivers having buffer in system
-ram and memcpy to video ram...
-anyway 3: in our really ideal world, all libvo driver has its buffers in
-fast sytem ram and does blitting with DMA... :)
-
-============================================================================
-MPlayer NOW! -- The libmpcodecs way.
-
-libmpcodecs replaced old draw callbacks with mpi (mplayer image) struct.
-steps of decoding with libmpcodecs:
-1. codec requests an mpi from libmpcodecs core (vd.c)
-2. vd creates an mpi struct filled by codec's requirements (size, stride,
- colorspace, flags, type)
-3. vd asks libvo (control(VOCTRL_GET_IMAGE)), if it can provide such buffer:
- - if it can -> do direct rendering
- - it it can not -> allocate system ram area with memalign()/malloc()
- Note: codec may request EXPORT buffer, it means buffer allocation is
- done inside the codec, so we cannot do DR :(
-4. codec decodes one frame to the mpi struct (system ram or direct rendering)
-5. if it isn't DR, we call libvo's draw functions to blit image to video ram
-
-current possible buffer setups:
-- EXPORT - codec handles buffer allocation and it exports its buffer pointers
- used for opendivx, xanim and libavcodec
-- STATIC - codec requires a single static buffer with constant preserved content
- used by codecs which do partial updating of image, but doesn't require reading
- of previous frame. most rle-based codecs, like cvid, rle8, qtrle, qtsmc etc.
-- TEMP - codec requires a buffer, but it doesn't depend on previous frame at all
- used for I-only codecs (like mjpeg) and for codecs supporting method-2 direct
- rendering with variable buffer address (vfw, dshow, divx4).
-- IP - codec requires 2 (or more) read/write buffers. it's for codecs supporting
- method-1 direct rendering but using motion compensation (ie. reading from
- previous frame buffer). could be used for libavcodec (divx3/4,h263).
- IP buffer stays from 2 (or more) STATIC buffers.
-- IPB - similar to IP, but also have one (or more) TEMP buffers for B frames.
- it will be used for libmpeg2 and libavcodec (mpeg1/2/4).
- IPB buffer stays from 2 (or more) STATIC buffers and 1 (or more) TEMP buffer.
diff --git a/DOCS/OUTDATED-tech/libmpcodecs.txt b/DOCS/OUTDATED-tech/libmpcodecs.txt
deleted file mode 100644
index 9b627ced50..0000000000
--- a/DOCS/OUTDATED-tech/libmpcodecs.txt
+++ /dev/null
@@ -1,383 +0,0 @@
-NOTE: If you want to implement a new native codec, please add it to
-libavcodec. libmpcodecs is considered mostly deprecated, except for wrappers
-around external libraries and codecs requiring binary support.
-
-The libMPcodecs API details, hints - by A'rpi
-==================================
-
-See also: colorspaces.txt, codec-devel.txt, dr-methods.txt, codecs.conf.txt
-
-The VIDEO path:
-===============
-
- [MPlayer core]
- | (1)
- ______V______ (2) /~~~~~~~~~~\ (3,4) |~~~~~~|
- | | -----> | vd_XXX.c | -------> | vd.c |
- | dec_video | \__________/ <-(3a)-- |______|
- | | -----, ,.............(3a,4a).....:
- ~~~~~~~~~~~~~ (6) V V
- /~~~~~~~~\ /~~~~~~~~\ (8)
- | vf_X.c | --> | vf_Y.c | ----> vf_vo.c / ve_XXX.c
- \________/ \________/
- | ^
- (7) | |~~~~~~| : (7a)
- `-> | vf.c |...:
- |______|
-
-Short description of video path:
-1. MPlayer/MEncoder core requests the decoding of a compressed video frame:
- calls dec_video.c::decode_video().
-
-2. decode_video() calls the video codec previously selected in init_video().
- (vd_XXX.c file, where XXX == vfm name, see the 'driver' line of codecs.conf)
-
-3. The codec should initialize the output device before decoding the first
- frame. It may happen in init() or at the middle of the first decode(), see
- 3a. It means calling vd.c::mpcodecs_config_vo() with the image dimensions,
- and the _preferred_ (meaning: internal, native, best) colorspace.
- NOTE: This colorspace may not be equal to the colorspace that is actually
- used. It's just a _hint_ for the colorspace matching algorithm and mainly
- used as input format of the converter, but _only_ when colorspace
- conversion is required,
-
-3a. Selecting the best output colorspace:
- The vd.c::mpcodecs_config_vo() function will go through the outfmt list
- defined by the 'out' lines in codecs.conf and query both vd (codec) and
- vo (output device/filter/encoder) if the format is supported or not.
-
- For the vo, it calls the query_format() function of vf_XXX.c or ve_XXX.c.
- It should return a set of feature flags, the most important ones for this
- stage are: VFCAP_CSP_SUPPORTED (colorspace supported directly or by
- conversion) and VFCAP_CSP_SUPPORTED_BY_HW (colorspace supported
- WITHOUT any conversion).
-
- For the vd (codec), control() with VDCTRL_QUERY_FORMAT will be called.
- If it does not implement VDCTRL_QUERY_FORMAT, (i.e. answers CONTROL_UNKNOWN
- or CONTROL_NA), it is assumed to be CONTROL_TRUE (colorspace supported)!
-
- So, by default, if the list of supported colorspaces is constant and does
- not depend on the actual file/stream header, then it is enough to list the
- formats in codecs.conf ('out' field) and not implement VDCTRL_QUERY_FORMAT.
- This is the case for most codecs.
-
- If the supported colorspace list depends on the file being decoded, list
- the possible out formats (colorspaces) in codecs.conf and implement the
- VDCTRL_QUERY_FORMAT to test the availability of the given colorspace for
- the given video file/stream.
-
- The vd.c core will find the best matching colorspace, depending on the
- VFCAP_CSP_SUPPORTED_BY_HW flag (see vfcap.h). If no match can be found,
- it will try again with the 'scale' filter inserted between vd and vo.
- If this is unsuccessful, it will fail :(
-
-4. Requesting buffer for the decoded frame:
- The codec has to call mpcodecs_get_image() with proper imgtype & imgflag.
- It will find the optimal buffering setup (preferred stride, alignment etc)
- and return a pointer to the allocated and filled up mpi (mp_image_t*) struct.
- The 'imgtype' controls the buffering setup, i.e. STATIC (just one buffer that
- 'remembers' its content between frames), TEMP (write-only, full update),
- EXPORT (memory allocation is done by the codec, not recommended) and so on.
- The 'imgflags' set up the limits for the buffer, i.e. stride limitations,
- readability, remembering content etc. See mp_image.h for the short
- description. See dr-methods.txt for the explanation of buffer
- importing and mpi imgtypes.
-
- Always try to implement stride support! (stride == bytes per line)
- If no stride support, then stride==bytes_per_pixel*image_width.
- If you have stride support in your decoder, use the mpi->stride[] value
- for the byte_per_line for each plane.
- Also take care of other imgflags, like MP_IMGFLAG_PRESERVE and
- MP_IMGFLAG_READABLE, MP_IMGFLAG_COMMON_STRIDE and MP_IMGFLAG_COMMON_PLANE!
- The file mp_image.h contains flag descriptions in comments, read it!
- Ask for help on dev-eng, describing the behavior of your codec, if unsure.
-
-4.a. buffer allocation, vd.c::mpcodecs_get_image():
- If the requested buffer imgtype!=EXPORT, then vd.c will try to do
- direct rendering, i.e. ask the next filter/vo for the buffer allocation.
- It's done by calling get_image() of the vf_XXX.c file.
- If it was successful, the imgflag MP_IMGFLAG_DIRECT will be set, and one
- memcpy() will be saved when passing the data from vd to the next filter/vo.
- See dr-methods.txt for details and examples.
-
-5. Decode the frame, to the mpi structure requested in 4., then return the mpi
- to decvideo.c. Return NULL if the decoding failed or skipped the frame.
-
-6. decvideo.c::decode_video() will now pass the 'mpi' to the next filter (vf_X).
-
-7. The filter's (vf_X) put_image() then requests a new mpi buffer by calling
- vf.c::vf_get_image().
-
-7.a. vf.c::vf_get_image() will try to get direct rendering by asking the
- next filter to do the buffer allocation (calls vf_Y's get_image()).
- If it fails, it will fall back on normal system memory allocation.
-
-8. When we're past the whole filter chain (multiple filters can be connected,
- even the same filter multiple times) then the last, 'leaf' filters will be
- called. The only difference between leaf and non-leaf filters is that leaf
- filters have to implement the whole filter API.
- Currently leaf filters are: vf_vo.c (wrapper over libvo) and ve_XXX.c
- (video encoders used by MEncoder).
-
-
-Video Filters
-=============
-
-Video filters are plugin-like code modules implementing the interface
-defined in vf.h.
-
-Basically it means video output manipulation, i.e. these plugins can
-modify the image and the image properties (size, colorspace, etc) between
-the video decoders (vd.h) and the output layer (libvo or video encoders).
-
-The actual API is a mixture of the video decoder (vd.h) and libvo
-(video_out.h) APIs.
-
-main differences:
-- vf plugins may be "loaded" multiple times, with different parameters
- and context - it's new in MPlayer, old APIs weren't reentrant.
-- vf plugins don't have to implement all functions - all functions have a
- 'fallback' version, so the plugins only override these if wanted.
-- Each vf plugin has its own get_image context, and they can interchange
- images/buffers using these get_image/put_image calls.
-
-
-The VIDEO FILTER API:
-=====================
-filename: vf_FILTERNAME.c
-
-vf_info_t* info;
- pointer to the filter description structure:
-
- const char *info; // description of the filter
- const char *name; // short name of the filter, must be FILTERNAME
- const char *author; // name and email/URL of the author(s)
- const char *comment; // comment, URL to papers describing algorithm etc.
- int (*open)(struct vf_instance *vf,char* args);
- // pointer to the open() function:
-
-Sample:
-
-vf_info_t vf_info_foobar = {
- "Universal Foo and Bar filter",
- "foobar",
- "Ms. Foo Bar",
- "based on algorithm described at http://www.foo-bar.org",
- open
-};
-
-The open() function:
-
- open() is called when the filter is appended/inserted in the filter chain.
- It'll receive the handler (vf) and the optional filter parameters as
- char* string. Note that encoders (ve_*) and vo wrapper (vf_vo.c) have
- non-string arg, but it's specially handled by MPlayer/MEncoder.
-
- The open() function should fill the vf_instance_t structure with the
- implemented functions' pointers (see below).
- It can optionally allocate memory for its internal data (vf_priv_t) and
- store the pointer in vf->priv.
-
- The open() function should parse (or at least check syntax of) parameters,
- and fail (return 0) on error.
-
-Sample:
-
-static int open(vf_instance_t *vf, char* args)
-{
- vf->query_format = query_format;
- vf->config = config;
- vf->put_image = put_image;
- // allocate local storage:
- vf->priv = malloc(sizeof(struct vf_priv_s));
- vf->priv->w =
- vf->priv->h = -1;
- if(args) // parse args:
- if(sscanf(args, "%d:%d", &vf->priv->w, &vf->priv->h)!=2) return 0;
- return 1;
-}
-
-Functions in vf_instance:
-
-NOTE: All these are optional, their function pointer is either NULL or points
-to a default implementation. If you implement them, don't forget to set
-vf->FUNCNAME in your open() !
-
- int (*query_format)(struct vf_instance *vf, unsigned int fmt);
-
-The query_format() function is called one or more times before the config(),
-to find out the capabilities and/or support status of a given colorspace (fmt).
-For the return values, see vfcap.h!
-Normally, a filter should return at least VFCAP_CSP_SUPPORTED for all supported
-colorspaces it accepts as input, and 0 for the unsupported ones.
-If your filter does linear conversion, it should query the next filter,
-and merge in its capability flags. Note: You should always ensure that the
-next filter will accept at least one of your possible output colorspaces!
-
-Sample:
-
-static int query_format(struct vf_instance *vf, unsigned int fmt)
-{
- switch(fmt){
- case IMGFMT_YV12:
- case IMGFMT_I420:
- case IMGFMT_IYUV:
- case IMGFMT_422P:
- return vf_next_query_format(vf,IMGFMT_YUY2) & (~VFCAP_CSP_SUPPORTED_BY_HW);
- }
- return 0;
-}
-
-For the more complex case, when you have an N -> M colorspace mapping matrix,
-see vf_scale or vf_format for examples.
-
-
- int (*config)(struct vf_instance *vf,
- int width, int height, int d_width, int d_height,
- unsigned int flags, unsigned int outfmt);
-
-The config() is called to initialize/configure the filter before using it.
-Its parameters are already well-known from libvo:
- width, height: size of the coded image
- d_width, d_height: wanted display size (usually aspect corrected w/h)
- Filters should use width, height as input image dimension, but the
- resizing filters (crop, expand, scale, rotate, etc) should update
- d_width/d_height (display size) to preserve the correct aspect ratio!
- Filters should not rely on d_width, d_height as input parameters,
- the only exception is when a filter replaces some libvo functionality
- (like -vf scale with -zoom, or OSD rendering with -vf expand).
- flags: the "good" old libvo flag set:
- 0x01 - force fullscreen (-fs)
- 0x02 - allow mode switching (-vm)
- 0x04 - allow software scaling (-zoom)
- 0x08 - flipping (-flip)
- (Usually you don't have to worry about flags, just pass it to next config.)
- outfmt: the selected colorspace/pixelformat. You'll receive images in this
- format.
-
-Sample:
-
-static int config(struct vf_instance *vf,
- int width, int height, int d_width, int d_height,
- unsigned int flags, unsigned int outfmt)
-{
- // use d_width/d_height if not set by the user:
- if (vf->priv->w == -1)
- vf->priv->w = d_width;
- if (vf->priv->h == -1)
- vf->priv->h = d_height;
- // initialize your filter code
- ...
- // OK now config the rest of the filter chain, with our output parameters:
- return vf_next_config(vf,vf->priv->w,vf->priv->h,d_width,d_height,flags,outfmt);
-}
-
- void (*uninit)(struct vf_instance *vf);
-
-Okay, uninit() is the simplest, it's called at the end. You can free your
-private buffers etc here.
-
- int (*put_image)(struct vf_instance *vf, mp_image_t *mpi);
-
-Ah, put_image(). This is the main filter function, it should convert/filter/
-transform the image data from one format/size/color/whatever to another.
-Its input parameter is an mpi (mplayer image) structure, see mp_image.h.
-Your filter has to request a new image buffer for the output, using the
-vf_get_image() function. NOTE: Even if you don't want to modify the image,
-just pass it to the next filter, you have to either
-- not implement put_image() at all - then it will be skipped
-- request a new image with type==EXPORT and copy the pointers
-NEVER pass the mpi as-is, it's local to the filters and may cause trouble.
-
-If you completely copy/transform the image, then you probably want this:
-
- dmpi = vf_get_image(vf->next,mpi->imgfmt, MP_IMGTYPE_TEMP,
- MP_IMGFLAG_ACCEPT_STRIDE, vf->priv->w, vf->priv->h);
-
-It will allocate a new image and return an mp_image structure filled by
-buffer pointers and stride (bytes per line) values, in size of vf->priv->w
-times vf->priv->h. If your filter cannot handle stride, then leave out
-MP_IMGFLAG_ACCEPT_STRIDE. Note that you can do this, but it isn't recommended,
-the whole video path is designed to use strides to get optimal throughput.
-If your filter allocates output image buffers, then use MP_IMGTYPE_EXPORT
-and fill the returned dmpi's planes[], stride[] with your buffer parameters.
-Note, it is not recommended (no direct rendering), so if you can, use
-vf_get_image() for buffer allocation!
-For other image types and flags see mp_image.h, it has comments.
-If you are unsure, feel free to ask on the dev-eng mailing list. Please
-describe the behavior of your filter, and its limitations, so we can
-suggest the optimal buffer type + flags for your code.
-
-Now that you have the input (mpi) and output (dmpi) buffers, you can do
-the conversion. If you didn't notice yet, mp_image has some useful info
-fields. They may help you a lot creating if() or for() structures:
- flags: MP_IMGFLAG_PLANAR, MP_IMGFLAG_YUV, MP_IMGFLAG_SWAPPED
- helps you to handle various pixel formats in single code.
- bpp: bits per pixel
- WARNING! It's number of bits _allocated_ to store a pixel,
- it is not the number of bits actually used to keep colors!
- So it's 16 for both 15 and 16 bit color depth, and is 32 for
- 32bpp (actually 24 bit color depth) mode!
- It's 1 for 1bpp, 9 for YVU9, and is 12 for YV12 mode. Get it?
- For planar formats, you also have chroma_width, chroma_height and
- chroma_x_shift, chroma_y_shift too, they specify the chroma subsampling
- for YUV formats:
- chroma_width = luma_width >> chroma_x_shift;
- chroma_height = luma_height >> chroma_y_shift;
-
-If you're done, call the rest of the filter chain to process your output
-image:
- return vf_next_put_image(vf,dmpi);
-
-
-Ok, the rest is for advanced functionality only:
-
- int (*control)(struct vf_instance *vf, int request, void* data);
-
-You can control the filter at runtime from MPlayer/MEncoder/dec_video:
-#define VFCTRL_QUERY_MAX_PP_LEVEL 4 /* test for postprocessing support (max level) */
-#define VFCTRL_SET_PP_LEVEL 5 /* set postprocessing level */
-#define VFCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */
-#define VFCTRL_GET_EQUALIZER 8 /* get color options (brightness,contrast etc) */
-#define VFCTRL_DRAW_OSD 7
-
-
- void (*get_image)(struct vf_instance *vf, mp_image_t *mpi);
-
-This is for direct rendering support, works the same way as in libvo drivers.
-It makes in-place pixel modifications possible.
-If you implement it (vf->get_image!=NULL), then it will be called to do the
-buffer allocation. You SHOULD check the buffer restrictions (stride, type,
-readability etc) and if everything is OK, then allocate the requested buffer
-using the vf_get_image() function and copying the buffer pointers.
-
-NOTE: You HAVE TO save the dmpi pointer, as you'll need it in put_image()
-later on. It is not guaranteed that you'll get the same mpi for put_image() as
-in get_image() (think of out-of-order decoding, get_image is called in decoding
-order, while put_image is called for display) so the only safe place to save
-it is in the mpi struct itself: mpi->priv=(void*)dmpi;
-
-
- void (*draw_slice)(struct vf_instance *vf, unsigned char** src,
- int* stride, int w,int h, int x, int y);
-
-It's the good old draw_slice callback, already known from libvo.
-If your filter can operate on partial images, you can implement this one
-to improve performance (cache utilization).
-
-Ah, and there are two sets of capability/requirement flags (vfcap.h type)
-in vf_instance_t, used by the default query_format() implementation, and by
-the automatic colorspace/stride matching code (vf_next_config()).
-
- // caps:
- unsigned int default_caps; // used by default query_format()
- unsigned int default_reqs; // used by default config()
-
-BTW, you should avoid using global or static variables to store filter instance
-specific stuff, as filters might be used multiple times and in the future even
-multiple streams might be possible.
-
-
-The AUDIO path:
-===============
-TODO!!!
diff --git a/DOCS/OUTDATED-tech/manpage.txt b/DOCS/OUTDATED-tech/manpage.txt
deleted file mode 100644
index f3ad7fd355..0000000000
--- a/DOCS/OUTDATED-tech/manpage.txt
+++ /dev/null
@@ -1,283 +0,0 @@
-========================================
-A documentation about MPlayer's man page
-========================================
-
-
-About the documentation
------------------------
-
-Yes it's true: This is the documentation of the documentation (man page).
-This guide should be used as a reference for questions about the man page
-structure. It's not a strict guide but we recommend following it to get a
-uniform man page.
-
-
-
-What belongs in the man page?
------------------------------
-
- - option descriptions (all)
- - usage (options, configuration files, controls)
- - basic examples
-
-
-
-What doesn't belong in the man page?
-------------------------------------
-
- - instructions for installation, encoding and similar processes
- - detailed evaluations or hints
- - tutorials, guides
-
-
-
-How should patches look like?
------------------------------
-
-Follow the rules in patches.txt, they apply to the man page, too.
-Exceptions are:
-
- - Cosmetic patches are allowed but should be done separately from the real
- changes, be marked as cosmetic changes and shouldn't change the general
- style without reasons/permissions.
- - The same applies to spell checking.
-
-
-
-How do I create an HTML, text or other version of the man page?
----------------------------------------------------------------
-
-The man page was more or less designed for groff as it is the main tool for
-it. Therefore only groff produces acceptable results without changes.
-Additionally, the SS variable should be set to either very low or very high
-values to produce a better groff HTML output (Due to a bug of groff2html?).
-A setting of 4 should look readable. Here's an overview again:
-
- - groff:
- groff is the "official" tool to convert man pages. To get good results you
- need a recent version (1.18.2).
- groff -mman -Thtml mplayer.1 > mplayer.1.html
- groff -mman -Tlatin1 -rLL=78n mplayer.1 | col -bxp > mplayer.1.txt
- The groff man page lists other output formats to use with -T.
-
- Unfortunately groff is not able to handle UTF-8 input as of version 1.19.2.
- groff-utf8 is a wrapper that works around these deficiencies:
- http://www.haible.de/bruno/packages-groff-utf8.html
-
- - man2html:
- You can view it through a CGI script:
- http://localhost/cgi-bin/man2html?mplayer
- The output is unusable as the script doesn't seem to support the macro
- definitions. Maybe manually changing all leads to acceptable results.
-
- - rman:
- rman -f html mplayer.1 > man_page.rman.html
- The output is ugly as rman doesn't understand many of the macros used.
-
- - troffcvt:
- troff2html -man mplayer.1 > man_page.tcvt.html
- The (good) output is similar to groff but simplified...
-
-
-
-The structure
--------------
-
-The option descriptions are divided into sections. Inside a section options are
-alphabetically sorted. The sections are:
-
-(Header)
- not visible, copyright and author information
-(Macro definitions)
- not visible, some macro definitions
-NAME
- The man page is used for both mplayer and mencoder.
-SYNOPSIS
- a description of MPlayer's playtree
-DESCRIPTION
- a general description of MPlayer, MEncoder, GMPlayer and their features
-INTERACTIVE CONTROL
- description of MPlayer's input system and interactive controls
-USAGE
- some general notes about usage
-CONFIGURATION FILES
- description of the configuration file format
-GENERAL OPTIONS
- General options that are common to both MPlayer and MEncoder.
-PLAYER OPTIONS (MPLAYER ONLY)
- user interface option descriptions (MPlayer only)
-DEMUXER/STREAM OPTIONS
- demuxer and stream layer option descriptions
-OSD/SUBTITLE OPTIONS
- This section is special in that it contains all subtitle and OSD option
- descriptions even if they might belong to one of the other sections. It
- was created because of its size.
-AUDIO OUTPUT OPTIONS (MPLAYER ONLY)
- audio output layer (ao) option descriptions (MPlayer only)
-AUDIO OUTPUT DRIVERS (MPLAYER ONLY)
- audio output driver description (ao)
-VIDEO OUTPUT OPTIONS (MPLAYER ONLY)
- video output layer (vo) option descriptions (MPlayer only)
-VIDEO OUTPUT DRIVERS (MPLAYER ONLY)
- video output driver description (vo)
-DECODING/FILTERING OPTIONS
- decoding/filtering layer options (ad, vd, pl)
-VIDEO FILTERS
- video filter description (vf)
-GENERAL ENCODING OPTIONS (MENCODER ONLY)
- Encoding option descriptions (ve) (MEncoder only).
-CODEC SPECIFIC ENCODING OPTIONS (MENCODER ONLY)
- Codec specific option descriptions (lavc,divx4,xvid,lame) (MEncoder only).
-FILES
- a list and description of all installed/used files/directories
-EXAMPLES OF MPLAYER USAGE
- basic examples, again: no long descriptions/processes
-EXAMPLES OF MENCODER USAGE
- basic examples, again: no long descriptions/processes
-BUGS
-AUTHORS
-
-
-
-The man page/groff format
--------------------------
-
-Just read this and RTFS:
-
- man 7 roff
- http://www.tldp.org/HOWTO/mini/Man-Page.html
- man 7 man
- man 7 groff
-
-
-
-"Style" guidelines
-------------------
-
-This section was kept simple but there are certain guidelines/rules to get a
-uniform man page. The best way is to read (and understand) the source.
-
-
-General:
-
- - No line should contain more than 79 characters.
- - used commands: .TH, .SH, .TP, .IP, .PP, .[R]B, .I, .br, .RS, .RE, .na,
- .nh, .ad, .hy, macro definitions, comments and some more
- - Don't forget the quotation marks around expressions, etc...
- - Each new sentence should start on a line of its own.
- - There is a typographical difference between a hyphen, a minus and an
- en-dash or em-dash. For the man page this means that you should put a
- backslash before a '-' if it denotes a range (1\-10), an option (\-fs),
- stdin (\-), a dash (mplayer \- movie player) or a minus (\-1). Use just
- '-' if it is a hyphen (A-V).
- - Don't start a line with "'" or ".", nroff treats them specially.
- - To quickly check a manual page for markup errors, just run
- man DOCS/man/XX/mplayer.1 > /dev/null
-
-
-Option descriptions:
-
- - Options should be in alphabetical order.
- - Option and/or suboption parameters should be short, descriptive and put
- in angular brackets (e.g. \-vo <driver>).
- - If the option has a parameter in a certain range, specify it right after
- the option (e.g. \-subpos <0\-100>).
- - Optional things should be put in square brackets ([]).
- - Obsolete options are followed by (OBSOLETE), beta options by
- (BETA CODE), etc.
- - MPlayer-only options in a section which isn't marked this way
- are followed by (MPlayer only).
- - Add references to other options if they belong to each other, e.g.
- '(\-vo zr only)' or '(also see \-alang)' or are commonly used together.
- - If a nontrivial default parameter exists, mention it, e.g. (default: 24).
- - Put examples and notes at the end of the description (before suboptions).
- - The end of the suboptions _always_ has to be followed by a paragraph
- (BUG).
- - For flag options just document the non-default one of \-XXX and \-noXXX.
- If the option is not a flag, describe both, one below the other (this is
- an exception to the alphabetical order).
-
-
-Macro definitions (see beginning of man page):
-
- - .SS starting value of the suboption column
- - .IPs Add new suboption (we use .TP for normal options and .IP for
- the rest).
- - .RSs begin of suboptions, end with .RE
- - .RSss begin of suboptions in a suboption
- - .REss end of suboptions in a suboption
-
-
-Options, suboptions, examples structure:
-
- - Normal options (note the '<' and '>'):
-
- [...]
- .TP
- .B \-option <parameter>
- description
- [...]
-
- - Long suboptions:
-
- [...]
- description. Available options are:
- .
- .RSs
- .IPs "subopt1=<value>"
- description1
- .IPs "subopt2=<value>"
- description2
- [...]
- .IPs "last subopt=<value>"
- last description
- .RE
- .
- [...]
-
- - Short suboptions:
-
- [...]
- description. Available options are:
-
- .PD 0
- .RSs
- .IPs "subopt1=<value>"
- description1
- .IPs "subopt2=<value>"
- description2
- [...]
- .IPs "last subopt=<value>"
- last description
- .RE
- .PD 1
- .
- [...]
-
- - Suboptions in suboptions:
-
- [...]
- .IPs "subopt1=<value>"
- description1
- .RSss
- subsubopt1: description1
- .br
- subsubopt2: description2
- [...]
- .REss
- [...]
-
- - Examples:
-
- [...]
-
- .I EXAMPLE:
- .PD 0
- .RSs
- .IP "\-option used parameters"
- description
- [...]
- .RE
- .PD 1
- .
- [...]
diff --git a/DOCS/OUTDATED-tech/realcodecs/TODO b/DOCS/OUTDATED-tech/realcodecs/TODO
deleted file mode 100644
index 5ba035bfdd..0000000000
--- a/DOCS/OUTDATED-tech/realcodecs/TODO
+++ /dev/null
@@ -1,22 +0,0 @@
-TODO:
-
-- more docs are coming as I find the time to write them down
-- use RV20toYUV420Free()
-- audio support - nearly DONE (look below)
-- internet streaming support
-- searching - we need to take care of the audio interleaving -
- haven't taken steps to locate audio key frames (does such thing
- exist?)
-- some media files can't be played (mplayer crashes/fails) because
- it asks for decoded audio data, but the buffer in the audio
- demuxer packets are empty/missing. It seems that the necessary
- audio packets haven't been decoded completely (incomplete interleaving)
- the audio stream packets may get mixed with video stream packet - DONE ???
-- put variables for audio streaming inside real_priv_t
-- audio support for other formats than COOK - use a switch
- (like -forcereal) to activate it - no switch needed, win32 codecs
- doens't work (it was a nonworking attempt)
-- postprocessing support (see rp8 preferences->performance->cpu usage,
- also statistics->streams->video->POST FILTER: ON
- (i've found that custommessage calls differ wiht pp on/off, but adding
- these calls to mplayer didn't make a pixel difference between outputs)
diff --git a/DOCS/OUTDATED-tech/realcodecs/audio-codecs.txt b/DOCS/OUTDATED-tech/realcodecs/audio-codecs.txt
deleted file mode 100644
index fd28ab2a16..0000000000
--- a/DOCS/OUTDATED-tech/realcodecs/audio-codecs.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-all audio codecs (cook,atrk,14_4,28_8,dnet,sipr) have the same interface,
-but i have only analyzed the cook codec
-
-
-audio properties (hex)
-
-00 short text/description of the format (bitrate, when to use)
-01 bitrate (bits/s) //avg. bytes/sec output
-02 ulong: ?
- ulong: samples per second
- ushort: bits/sample
- ushort: number of channels
-03 same as 02 //constant 2
-04 long description
-05 constant 1 (always?)
-06 ulong: block align (input frame size for RADecode)
-07 string: minimum player version
-08 n/a
-09 n/a
-0A n/a
-0B n/a
-0C n/a
-0D ?
-0E ? leaf size
-0F ?
-10 ?
-11 ?
-12 ?
-13 min. output buffer size? max. number of samples?
-14 ?
-
-
-
-
-functions:
-
-ulong result=RAOpenCodec2(ra_main_t *raMain);
-
-ulong result=RAInitDecoder(ra_main_t *raMain, ra_init_struct *raInit);
-struct ra_init_struct {
- ulong sample_rate;
- ushort bits_per_sample; // unused by RAInitDecoder
- ushort number_of_channels;
- ushort unknown1; // 0
- ushort unknown2; // also unused (100)
- ulong leaf_size; // leaf size (used for interleaving, but
- // exists in audio stream description header (ASDH))
- ulong block_align; // packet size
- ulong bits_per_sample; // unused (always 16)
- char *ext_data; // 16 bytes located at the end of the
- // ASDH
-};
-
-There are some information missing that you usually need for playback,
-like bits per sample (the fileds aren't read by RAInitDecoder()). These
-are hard coded in the "flavors", i.e. the sub formats. A flavor is an entry
-in the list of available format variations like bitrate, number of channels,
-decoding algorithm, and so on.We can get those information with the
-following command:
-
-
-
-void *GetRAFlavorProperty(ra_main_t *raMain, ulong flavor, ulong property,
- short *property_length_in_bytes);
-returns property data for a specific data
-
-This is not important, because it's just a read only function.
-These flavor properties don't seem to exist in
-
-
-ulong RADecode(ra_main_t *raMain, char *input_buffer,
- ulong input_buffer_size, char *output_buffer,
- ulong *decoded_bytes, ulong p6=-1);
-
-RAFreeDecoder(ra_main_t *);
-
-RACloseCodec(ra_main_t *);
-
-
-ulong RASetFlavor(ra_main_t *ra_main, ulong flavor);
-
-Set the flavor of the stream.
-
-a flavor is an entry in the list of available format variations like
-bitrate, number of channels, decoding algorithm, and so on
-
-
-audio data storage:
--------------------
-
-With Real Audio V5 (or earlier?), the audio streams can be interleaved,
-i.e. the stream is striped amongst several data packets. The packets
-(which have a fixed size packet_len) are split up into a fixed number
-of num_parts equally sized parts - I call them leaves in lack of
-better name. The leaves have the size leaf_size = packet_len / num_parts.
-
-To create a bunch of packets, you need 2*num_parts stream packets.
-The first part of the first stream packet is stored in leaf number 0,
-the first part of the second into leaf number num_parts, the one of the
-next one into leaf number 1 etc. The following part of a stream packet
-is stored 2*num_packets behind the current part of the same stream packet.
-
-In short words: when you have a matrix with the leaves as the values,
-it's a transposition in conjunction with a permutation.
-
-packet | leaf | stream packet, part no.
--------+---------------+------------------------
-0 | 0 | (0,0)
-0 | 1 | (2,0)
-. | . | .
-. | . | .
-0 | num_parts-1 | (2*num_parts-2,0)
-0 | num_parts | (1,0)
-0 | num_parts+1 | (3,0)
-. | . | .
-. | . | .
-0 | 2*num_parts-1 | (2*num_parts-1,0)
-1 | 0 | (0,1)
-. | . | .
-. | . | .
-
-
-sequence of calls:
-------------------
-
-RAOpenCodec2()
-
-RAInitDecoder()
-
-RASetFlavor()
-
-RAGetFlavorProperty(0xE)
-
-sequence of RADecode()s
-
-once a RAGetFlavorProperty(0xE) after some RADecode()s
-
-and occasionally the following sequence:
-RAGetFlavorProperty(0)
-RAGetFlavorProperty(7)
-which is rather pointless because they only return
-cleartext audio descriptions
-
-RAFreeDecoder()
-
-RACloseCodec()
-
-
-
-RAFlush(ra_main_t *raMain, char *output_buffer, ulong *retval)
-will be called when seeking
-output_buffer points to the output buffer from the last
-decode operation.
-retval is unknown, returning always 0x18 in a specific sample
--> further investigation needed
diff --git a/DOCS/OUTDATED-tech/realcodecs/streaming.txt b/DOCS/OUTDATED-tech/realcodecs/streaming.txt
deleted file mode 100644
index a4af485b9b..0000000000
--- a/DOCS/OUTDATED-tech/realcodecs/streaming.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-In the RV30 format, another encapsulated data layer for the video stream
-has been introduced. In lack of a name I'll call them sub packets, the
-normal packets which exist in RV10 I'll call - well - packets. The stream
-of bytes which is put in one memory block is named block.
-
-The format extension has been * by wild guessing and comparing the
-received data between the original viewer and the demuxer.
-
-
-
-Every packet may contain one or more sub packets, and one block may
-be contained inside one or more adjacent (sub) packets.
-A sub packet (fragment) starts with a small header (two letters are one byte):
-
-
-aa(bb)[cccc{gggg}dddd{eeee}ff]
-
-aa: indicates the type of header
- the 2MSB indicate the header type (mask C0)
- C0: the [] part exists, but not () -> whole packet (not fragmented)
- 00, 80: the data block is encapsulated inside multiple packets.
- bb contains the sequence number, beginning with 1.
- 80 indicates the last sub packet containing data for the
- current block. no C0 or 40 sub packet follows until
- the block has been finished with a 80 sub packet.
- No packet with another stream than the current video stream
- is inside the sub packet chain, at least I haven't seen
- such case - the demuxer will shout in this case.
- 40: [] does not exist, the meaning of bb is unknown to me
- data follows to the end of the packet
- mask 3F: unknown
-bb: sub-seq - mask 0x7f: the sequence number of the _fragment_
- mask 0x80: unknown, seems to alternating between 00 and 80
-cccc: mask 3FFF: _total_ length of the packet
- mask C000: unknown, seems to be always 4000
- when it's all 0000, it indicates value >=0x4000, you should read {gggg}
- and use all 16 bits of it. dunno what happens when length>=65536...
-dddd: when it's 0, {} exists (only in this case)
- mask 3FFF: offset of fragment inside the whole packet. it's counted
- from the beginning of the packet, except when hdr&0x80,
- hten it's relative to the _end_ of the packet, so it's
- equal to fragment size!
- mask C000: like cccc, except the first case (always 4000)
- when it's all 0000, it indicates value >=0x4000, you should read {eeee}
- and use all 16 bits of it. dunno what happens when length>=65536...
-ff: sequence number of the assembled (defragmented) packets, beginning with 0
-
-NOTE: the demuxer should build a table of the subpacket offsets relative to the
-start of whole packet, it's required by the rv20/rv30 video decoders.
-
-
-packet header:
-
-ushort unknown
-ulong blocksize
-ushort streamid
-uchar reserved
-uchar flags 1=reliable, 2=keyframe
diff --git a/DOCS/OUTDATED-tech/realcodecs/video-codecs.txt b/DOCS/OUTDATED-tech/realcodecs/video-codecs.txt
deleted file mode 100644
index af2152061a..0000000000
--- a/DOCS/OUTDATED-tech/realcodecs/video-codecs.txt
+++ /dev/null
@@ -1,185 +0,0 @@
-The work has been based on the RV30 codec, but since RV20 has the same
-interface, it might work for it as well.
-
-
-
-
-error codes (the software uses redmond originated error codes)
-
-1. internal code (1-10)
-2. result
-
-0 00000000 success
-1 80004005 E_FAIL
-2 8007000E E_OUTOFMEMORY
-3,9 80004001 E_NOTIMPL
-4,5 80070005 E_ACCESSDENIED
-6 80004003 E_POINTER
-7,10 80070057 E_INVALIDREG
-8 80040FC1 (or 1FC?: CO_E_OBJISREG) - never occurred here
-
-
-
-
-
-I think the only relevant file is the decoder drv[23].so.6.0
-The rv[23]0 ones are just for streaming. We do this ourselves.
-
-
-The codec consists of several functions. The relevant ones are:
-
-RV20toYUV420Init()
-RV20toYUV420Transform()
-RV20toYUV420CustomMessage()
-RV20toYUV420Free()
-
-
-The others are irrelevant (seems to me). HiveMessage doesn't manipulate
-anything and is only called in the beginning.
-
-result=RV20toYUV420Init(struct init_data *, struct rvyuvMain **);
-
-struct init_data {
- short constant=0xb;
- short width, height;
- short 0, 0, 0;
- ulong format1;
- long 1;
- ulong format2;
-};
-
-format1 and format2 are stored in the .rm file's stream headers.
-(format1>>16)&3 seems to be a sub-codec id/selector, at least for rv30
-it's the only difference between low and high bitrate files.
-
-result=RV20toYUV420Transform(char *input_stream, char *output_data,
- struct transin *, struct transout *, struct rvyuvMain *);
-
-struct transin {
- ulong length_of_input_data;
- ulong null;
- ulong num_sub_packets_in_block_minus_one;
- ulong *sub_packets_list;
- ulong another_null;
- ulong timestamp_from_stream;
-};
-
-struct transout {
- ulong flag1; // ((var_94&2!=0)&&(result==0))?1:0
- ulong flag2; // 4 LBS from var_94
- ulong zero;
- ulong width, height;
-};
-
-The length of output_stream is 1.5*width*height (I420 planar yuv 4:2:0).
-input_stream is the exact data from the data block for one frame.
-
-sub_packets_list is a list of num_sub_packets pairs of long values, in form:
-1, 0,
-1, offset_2nd,
-1, offset_3rd,
-1, offset_4th,
-...
-
-where offset_* are the offsets or sub-packets relative to input_stream.
-
-
-result=RV20toYUV420CustomMessage(ulong *msg, struct rvyuvMain *);
-
-Messages used by RV30:
-
-A message is a triplet (cmd,val,ext) of ulong.
-
-NOTE:
-rv30 only requires the (0x24,2|3,{w,h,w,h}) message. others can be left out!
-rv20 only requires the (0x11,2,0) message in rp8, before each transform call.
-
-(3,2,0)
-returns always(?) an error, since a global variable inside the codec
-(which points to a function similar to custommessage), is always NULL
-
-(0x11,0|1|2,0)
-val=0|1: sets intern2 to val, when intern1 is non-zero
- return 3 when intern1 is zero and val is 1
- else returns 0
-val=2: return intern2
-what does intern[1,2] mean?
-
-(0x12,...)
-used by rv20, function unknown, can be ignored
-
-(0x1e,2|3,1)
-calls a subroutine and returns the result, purpose has to be detemined
-
-(0x24,subcodec,{...})
-copies 4 dwords to rvyuvMain+07c: { width, height, 0, 0 }
-subcodec must be 2 (low-bitrate) or 3 (high-bitrate) for rv30.
-the codec type (low vs high) can be determined from 1+((format1>>16)&3)
-for rv20, this call should be ignored! (makes codec crashing)
-
-(0x1c,a,b) - called inside transform
-to be analyzed
-
-(105,...)
-used by rv20, function unknown, can be ignored
-
-
-structure of rvyuvMain:
------------------------
-
-DWORDS (the entries are not always constant)
-there are two w/h pairs at 05C. the first is the size of the
-unscaled video stream, the second possibly image size
-
-000 1 6 3 1
-010 1 0 AEBFC0D1(magic) 0
-020 0 ptr->? 0 0
-030 0 0 ->rvyuvMain+0x050 ?
-040 width height 0x17 0x479
-050 ->rvyuvMain 0x17 0x17 width
-060 height width height 0
-070 0 1 0 0
-080 0 0xb w h
-090 w h 0 0
-0A0 1 0xb0(w?) 0x58 0x58
-0B0 ptr->? 0 0 1
-0C0 0x32 1 0 0
-0D0 0 0 0 0
-0E0 0 0 0 0
-0F0 0 0 0 0
-100 0 0 0 0
-110 p p p p p are pointers to several function, for
-120 p p p p example to the actual public functions
-130 p p p p (except init, the others are some kind of
-140 p p p p interfaces)
-150 p 0 0 0
-160 0 0x2000 1 0
-170 0 0 0 0
-180 1 1 0 0
-190 0 0 0 0
-1A0 0 0 0 0
-1B0 1 0 ptr->? ptr->?
-1C0 1 0 0 0
-1D0 0 0 0 0
-1E0 0 0 0 0
-...
-
-
-
-
-Order of calls:
----------------
-
-Init
-(0x11,0,0)
-(0x24,2,{...})
-
-[
-(3,2,0)->80004001
-(0x11,1,0)
-(0x1e,3,1)
-Transform (internally calls (0x1c,x,y))
-(11,2,0)
-]
-
-Free
diff --git a/DOCS/OUTDATED-tech/slave.txt b/DOCS/OUTDATED-tech/slave.txt
deleted file mode 100644
index db7fabc5ce..0000000000
--- a/DOCS/OUTDATED-tech/slave.txt
+++ /dev/null
@@ -1,592 +0,0 @@
-SLAVE MODE PROTOCOL
--------------------
-
-The -slave option switches on slave mode, in which MPlayer works as a backend
-for other programs. Instead of intercepting keyboard events, MPlayer will read
-commands separated by a newline (\n) from stdin.
-
-To try slave mode out by hand, run
-
- mplayer -slave -quiet <movie>
-
-and type slave commands into the console window.
-
-You can also use a fifo file (named pipe):
-
- mkfifo </tmp/fifofile>
- mplayer -slave -input file=</tmp/fifofile> <movie>
-
-Most slave mode commands are equivalent to command line options, though not
-necessarily under the same name. Detailed descriptions can be found in the
-man page.
-
-NOTE: the following paragraph is mostly obsolete; tricky pause handling
-was required in old MPlayer versions where all commands unpaused by default.
-Now running commands does not require leaving pause state any more, and
-the prefixes described here should not be required in normal use.
-All commands can be prefixed with one of "pausing ", "pausing_keep ", or
-"pausing_toggle ". "pausing " tells MPlayer to pause as soon as possible
-after processing the command. "pausing_keep " tells MPlayer to do so only if
-it was already in paused mode. "pausing_toggle " tells MPlayer to do so
-only if it was not already in paused mode. Please note that "as soon as
-possible" can be before the command is fully executed.
-As a temporary hack, there is also the _experimental_ "pausing_keep_force "
-prefix, with which MPlayer will not exit the pause loop at all.
-Like this you can avoid the "frame stepping" effect of "pausing_keep "
-but most commands will either not work at all or behave in unexpected ways.
-For "set_mouse_pos" and "key_down_event", "pausing_keep_force" is the default
-since other values do not make much sense for them.
-
-
-Various tips and tricks (please help expand it!):
-
-- To ensure the user can't control MPlayer "behind your back" use
- something like -input nodefault-bindings -noconfig all
-
-
-Available commands ('mplayer -input cmdlist' will print a list):
-
-af_add <filter_arguments_list> (comma separated list of audio filters with parameters)
- (experimental) Load the given list of audio filters.
-
-af_clr
- (experimental) Unload all loaded audio filters.
-
-af_cmdline <filter_name> <filter_arguments>
- (experimental) Send new command-line options to a filter with the given name.
-
-af_del <filter_name_list> (comma separated list of audio filter's names)
- (experimental) Unload the first occurrence of the filters, if loaded.
-
-af_switch <filter_arguments_list> (comma separated list of audio filters with parameters)
- (experimental) Remove all the audio filters and replace them with the given list.
-
-alt_src_step <value> (ASX playlist only)
- When more than one source is available it selects the next/previous one.
-
-audio_delay <value> [abs]
- Set/adjust the audio delay.
- If [abs] is not given or is zero, adjust the delay by <value> seconds.
- If [abs] is nonzero, set the delay to <value> seconds.
-
-[brightness|contrast|gamma|hue|saturation] <value> [abs]
- Set/adjust video parameters.
- If [abs] is not given or is zero, modifies parameter by <value>.
- If [abs] is non-zero, parameter is set to <value>.
- <value> is in the range [-100, 100].
-
-capturing [value]
- Toggle/set capturing the primary stream like -dumpstream.
- Requires the -capture parameter to be given.
-
-change_rectangle <val1> <val2>
- Change the position of the rectangle filter rectangle.
- <val1>
- Must be one of the following:
- 0 = width
- 1 = height
- 2 = x position
- 3 = y position
- <val2>
- If <val1> is 0 or 1:
- Integer amount to add/subtract from the width/height.
- Positive values add to width/height and negative values
- subtract from it.
- If <val1> is 2 or 3:
- Relative integer amount by which to move the upper left
- rectangle corner. Positive values move the rectangle
- right/down and negative values move the rectangle left/up.
-
-dvb_set_channel <channel_number> <card_number>
- Set DVB channel.
-
-dvdnav <button_name>
- Press the given dvdnav button.
- up
- down
- left
- right
- menu
- select
- prev
- mouse
-
-edl_mark
- Write the current position into the EDL file.
-
-frame_drop [value]
- Toggle/set frame dropping mode.
-
-get_audio_bitrate
- Print out the audio bitrate of the current file.
-
-get_audio_codec
- Print out the audio codec name of the current file.
-
-get_audio_samples
- Print out the audio frequency and number of channels of the current file.
-
-get_file_name
- Print out the name of the current file.
-
-get_meta_album
- Print out the 'Album' metadata of the current file.
-
-get_meta_artist
- Print out the 'Artist' metadata of the current file.
-
-get_meta_comment
- Print out the 'Comment' metadata of the current file.
-
-get_meta_genre
- Print out the 'Genre' metadata of the current file.
-
-get_meta_title
- Print out the 'Title' metadata of the current file.
-
-get_meta_track
- Print out the 'Track Number' metadata of the current file.
-
-get_meta_year
- Print out the 'Year' metadata of the current file.
-
-get_percent_pos
- Print out the current position in the file, as integer percentage [0-100).
-
-get_property <property>
- Print out the current value of a property.
-
-get_sub_visibility
- Print out subtitle visibility (1 == on, 0 == off).
-
-get_time_length
- Print out the length of the current file in seconds.
-
-get_time_pos
- Print out the current position in the file in seconds, as float.
-
-get_vo_fullscreen
- Print out fullscreen status (1 == fullscreened, 0 == windowed).
-
-get_video_bitrate
- Print out the video bitrate of the current file.
-
-get_video_codec
- Print out the video codec name of the current file.
-
-get_video_resolution
- Print out the video resolution of the current file.
-
-screenshot <each_frame> <full_window>
- Take a screenshot. Requires the screenshot filter to be loaded.
- each_frame:
- 0 Take a single screenshot. (Default.)
- 1 Start/stop taking screenshot of each frame.
- full_window:
- 0 Save the video image, in its original resolution. Typically without
- OSD or subtitles. (Default.)
- 1 Save the contents of the mplayer window. Typically with OSD and
- subtitles. If not available (no VO support), this may act as if 0 was
- passed.
-
-key_down_event <value>
- Inject <value> key code event into MPlayer.
-
-loadfile <file|url> <append>
- Load the given file/URL, stopping playback of the current file/URL.
- If <append> is nonzero playback continues and the file/URL is
- appended to the current playlist instead.
-
-loadlist <file> <append>
- Load the given playlist file, stopping playback of the current file.
- If <append> is nonzero playback continues and the playlist file is
- appended to the current playlist instead.
-
-loop <value> [abs]
- Adjust/set how many times the movie should be looped. -1 means no loop,
- and 0 forever.
-
-mute [value]
- Toggle sound output muting or set it to [value] when [value] >= 0
- (1 == on, 0 == off).
-
-osd [level]
- Toggle OSD mode or set it to [level] when [level] >= 0.
-
-osd_show_progression
- Show the progression bar, the elapsed time and the total duration of the
- movie on the OSD.
-
-osd_show_property_text <string> [duration] [level]
- Show an expanded property string on the OSD, see -playing-msg for a
- description of the available expansions. If [duration] is >= 0 the text
- is shown for [duration] ms. [level] sets the minimum OSD level needed
- for the message to be visible (default: 0 - always show).
-
-osd_show_text <string> [duration] [level]
- Show <string> on the OSD.
-
-panscan <-1.0 - 1.0> | <0.0 - 1.0> <abs>
- Increase or decrease the pan-and-scan range by <value>, 1.0 is the maximum.
- Negative values decrease the pan-and-scan range.
- If <abs> is != 0, then the pan-and scan range is interpreted as an
- absolute range.
-
-pause
- Pause/unpause the playback (use "set_property pause X" to set a particular
- value regardless of whether the player is already paused or not).
-
-frame_step
- Play one frame, then pause again.
-
-pt_step <value> [force]
- Go to the next/previous entry in the playtree. The sign of <value> tells
- the direction. If no entry is available in the given direction it will do
- nothing unless [force] is non-zero.
-
-pt_up_step <value> [force]
- Similar to pt_step but jumps to the next/previous entry in the parent list.
- Useful to break out of the inner loop in the playtree.
-
-quit [value]
- Quit MPlayer. The optional integer [value] is used as the return code
- for the mplayer process (default: 0).
-
-radio_set_channel <channel>
- Switch to <channel>. The 'channels' radio parameter needs to be set.
-
-radio_set_freq <frequency in MHz>
- Set the radio tuner frequency.
-
-radio_step_channel <-1|1>
- Step forwards (1) or backwards (-1) in channel list. Works only when the
- 'channels' radio parameter was set.
-
-radio_step_freq <value>
- Tune frequency by the <value> (positive - up, negative - down).
-
-run <value>
- Run <value> as shell command.
-
-seek <value> [type] [hr-seek]
- Seek to some place in the movie.
- type = 0 is a relative seek of +/- <value> seconds (default).
- type = 1 is a seek to <value> % in the movie.
- type = 2 is a seek to an absolute position of <value> seconds.
- The hr-seek parameter controls whether to use precise seeks (not limited
- to keyframe positions in video).
- hr-seek = 0 means use default set with option -hr-seek (default).
- hr-seek = 1 means force precise seek if possible.
- hr-seek = -1 means force non-precise seek.
-
-seek_chapter <value> [type]
- Seek to the start of a chapter.
- 0 is a relative seek of +/- <value> chapters (default).
- 1 is a seek to chapter <value>.
-
-switch_angle <value>
- Switch to the angle with the ID [value]. Cycle through the
- available angles if [value] is omitted or negative.
-
-set_mouse_pos <x> <y>
- Tells MPlayer the coordinates of the mouse in the window.
- This command doesn't move the mouse!
-
-set_property <property> <value>
- Set a property.
-
-set_property_osd <property> <value>
- Same as above, but show the new value on the OSD in the standard
- manner defined for that property (if any).
-
-speed_incr <value>
- Add <value> to the current playback speed.
-
-speed_mult <value>
- Multiply the current speed by <value>.
-
-speed_set <value>
- Set the speed to <value>.
-
-step_property <property> [value] [direction]
- Change a property by value, or increase by a default if value is
- not given or zero. The direction is reversed if direction is less
- than zero.
-
-step_property_osd <property> [value] [direction]
- Same as above, but show the new value on the OSD in the standard
- manner defined for that property (if any).
-
-stop
- Stop playback.
-
-sub_alignment [value]
- Toggle/set subtitle alignment.
- 0 top alignment
- 1 center alignment
- 2 bottom alignment
-
-sub_delay <value> [abs]
- Adjust the subtitle delay by +/- <value> seconds or set it to <value>
- seconds when [abs] is nonzero.
-
-sub_load <subtitle_file>
- Loads subtitles from <subtitle_file>.
-
-sub_log
- Logs the current or last displayed subtitle together with filename
- and time information to ~/.mplayer/subtitle_log. Intended purpose
- is to allow convenient marking of bogus subtitles which need to be
- fixed while watching the movie.
-
-sub_pos <value> [abs]
- Adjust/set subtitle position.
-
-sub_remove [value]
- If the [value] argument is present and non-negative, removes the subtitle
- file with index [value]. If the argument is omitted or negative, removes
- all subtitle files.
-
-sub_select [value]
- Display subtitle with index [value]. Turn subtitle display off if
- [value] is -1 or greater than the highest available subtitle index.
- Cycle through the available subtitles if [value] is omitted or less
- than -1 (forward or backward respectively).
- Supported subtitle sources are -sub options on the command
- line, VOBsubs, DVD subtitles, and Ogg and Matroska text streams.
- This command is mainly for cycling all subtitles, if you want to set
- a specific subtitle, use sub_file, sub_vob, or sub_demux.
-
-sub_source [source]
- Display first subtitle from [source]. Here [source] is an integer:
- SUB_SOURCE_SUBS (0) for file subs
- SUB_SOURCE_VOBSUB (1) for VOBsub files
- SUB_SOURCE_DEMUX (2) for subtitle embedded in the media file or DVD subs.
- If [source] is -1, will turn off subtitle display.
- If [value] is omitted or less than -1, will cycle between the first subtitle
- of each currently available source (forward or backward respectively).
-
-sub_file [value]
- Display subtitle specifid by [value] for file subs. The [value] is
- corresponding to ID_FILE_SUB_ID values reported by '-identify'.
- If [value] is -1, will turn off subtitle display.
- If [value] is omitted or less than -1, will cycle all file subs
- (forward or backward respectively).
-
-sub_vob [value]
- Display subtitle specifid by [value] for vobsubs. The [value] is
- corresponding to ID_VOBSUB_ID values reported by '-identify'.
- If [value] is -1, will turn off subtitle display.
- If [value] is omitted or less than -1, will cycle all vobsubs
- (forward or backward respectively).
-
-sub_demux [value]
- Display subtitle specifid by [value] for subtitles from DVD or embedded
- in media file. The [value] is corresponding to ID_SUBTITLE_ID values
- reported by '-identify'. If [value] is -1, will turn off subtitle display.
- If [value] is omitted or less than -1, will cycle all DVD subs or embedded subs
- (forward or backward respectively).
-
-sub_scale <value> [abs]
- Adjust the subtitle size by +/- <value> or set it to <value> when [abs]
- is nonzero.
-
-vobsub_lang
- This is a stub linked to sub_select for backwards compatibility.
-
-sub_step <value>
- Step forward in the subtitle list by <value> steps or backwards if <value>
- is negative.
-
-sub_visibility [value]
- Toggle/set subtitle visibility.
-
-forced_subs_only [value]
- Toggle/set forced subtitles only.
-
-switch_audio [value] (currently MPEG*, AVI, Matroska and streams handled by libavformat)
- Switch to the audio track with the ID [value]. Cycle through the
- available tracks if [value] is omitted or negative.
-
-switch_angle [value] (DVDs only)
- Switch to the DVD angle with the ID [value]. Cycle through the
- available angles if [value] is omitted or negative.
-
-switch_ratio [value]
- Change aspect ratio at runtime. [value] is the new aspect ratio expressed
- as a float (e.g. 1.77778 for 16/9).
- There might be problems with some video filters.
-
-switch_title [value] (DVDNAV only)
- Switch to the DVD title with the ID [value]. Cycle through the
- available titles if [value] is omitted or negative.
-
-switch_vsync [value]
- Toggle vsync (1 == on, 0 == off). If [value] is not provided,
- vsync status is inverted.
-
-teletext_add_digit <value>
- Enter/leave teletext page number editing mode and append given digit to
- previously entered one.
- 0..9 - Append apropriate digit. (Enables editing mode if called from normal
- mode, and switches to normal mode when third digit is entered.)
- - - Delete last digit from page number. (Backspace emulation, works only
- in page number editing mode.)
-
-teletext_go_link <1-6>
- Follow given link on current teletext page.
-
-tv_start_scan
- Start automatic TV channel scanning.
-
-tv_step_channel <channel>
- Select next/previous TV channel.
-
-tv_step_norm
- Change TV norm.
-
-tv_step_chanlist
- Change channel list.
-
-tv_set_channel <channel>
- Set the current TV channel.
-
-tv_last_channel
- Set the current TV channel to the last one.
-
-tv_set_freq <frequency in MHz>
- Set the TV tuner frequency.
-
-tv_step_freq <frequency offset in MHz>
- Set the TV tuner frequency relative to current value.
-
-tv_set_norm <norm>
- Set the TV tuner norm (PAL, SECAM, NTSC, ...).
-
-tv_set_brightness <-100 - 100> [abs]
- Set TV tuner brightness or adjust it if [abs] is set to 0.
-
-tv_set_contrast <-100 -100> [abs]
- Set TV tuner contrast or adjust it if [abs] is set to 0.
-
-tv_set_hue <-100 - 100> [abs]
- Set TV tuner hue or adjust it if [abs] is set to 0.
-
-tv_set_saturation <-100 - 100> [abs]
- Set TV tuner saturation or adjust it if [abs] is set to 0.
-
-use_master
- Switch volume control between master and PCM.
-
-vo_border [value]
- Toggle/set borderless display.
-
-vo_fullscreen [value]
- Toggle/set fullscreen mode.
-
-vo_ontop [value]
- Toggle/set stay-on-top.
-
-vo_rootwin [value]
- Toggle/set playback on the root window.
-
-volume <value> [abs]
- Increase/decrease volume or set it to <value> if [abs] is nonzero.
-
-show_chapters_osd
- Show the list of chapters in the currently played file on the OSD.
-
-show_tracks_osd
- Show the list audio and subtitle tracks in the currently played file on the OSD.
-
-Available properties:
-
-name type min max get set step comment
-=================================================================
-
-osdlevel int 0 3 X X X as -osdlevel
-speed float 0.01 100 X X X as -speed
-loop int -1 X X X as -loop
-hr_seek string X X X as -hr-seek
-pts_association_mode string X X X as -pts-association-mode
-pause flag 0 1 X 1 if paused
-filename string X file playing wo path
-path string X file playing
-demuxer string X demuxer used
-stream_pos pos 0 X X position in stream
-stream_start pos 0 X start pos in stream
-stream_end pos 0 X end pos in stream
-stream_length pos 0 X (end - start)
-stream_time_pos time 0 X present position in stream (in seconds)
-titles int X number of titles
-chapter int 0 X X X select chapter
-chapters int X number of chapters
-angle int 0 X X X select angle
-length time X length of file in seconds
-percent_pos int 0 100 X X X position in percent
-time_pos time 0 X X X position in seconds
-metadata str list X list of metadata key/value
-metadata/* string X metadata values
-volume float 0 100 X X X change volume
-balance float -1 1 X X X change audio balance
-mute flag 0 1 X X X
-audio_delay float -100 100 X X X
-audio_format int X
-audio_codec string X
-audio_bitrate int X
-samplerate int X
-channels int X
-switch_audio int -2 255 X X X select audio stream
-switch_angle int -2 255 X X X select DVD angle
-switch_title int -2 255 X X X select DVD title
-capturing flag 0 1 X X X dump primary stream if enabled
-fullscreen flag 0 1 X X X
-deinterlace flag 0 1 X X X
-ontop flag 0 1 X X X
-rootwin flag 0 1 X X X
-border flag 0 1 X X X
-framedropping int 0 2 X X X 1 = soft, 2 = hard
-gamma int -100 100 X X X
-brightness int -100 100 X X X
-contrast int -100 100 X X X
-saturation int -100 100 X X X
-hue int -100 100 X X X
-panscan float 0 1 X X X
-vsync flag 0 1 X X X
-colormatrix choice X X X as --colormatrix
-colormatrix_input_range choice X X X as --colormatrix-input-range
-colormatrix_output_range choice X X X as --colormatrix-output-range
-video_format int X
-video_codec string X
-video_bitrate int X
-width int X "display" width
-height int X "display" height
-fps float X
-aspect float X
-switch_video int -2 255 X X X select video stream
-switch_program int -1 65535 X X X (see TAB default keybind)
-sub int -1 X X X select subtitle stream
-sub_source int -1 2 X X X select subtitle source
-sub_file int -1 X X X select file subtitles
-sub_vob int -1 X X X select vobsubs
-sub_demux int -1 X X X select subs from demux
-sub_delay float X X X
-sub_pos int 0 100 X X X subtitle position
-sub_alignment int 0 2 X X X subtitle alignment
-sub_visibility flag 0 1 X X X show/hide subtitles
-sub_forced_only flag 0 1 X X X
-sub_scale float 0 100 X X X subtitles font size
-ass_vsfilter_aspect_compat flag 0 1 X X X SSA/ASS aspect ratio correction
-tv_brightness int -100 100 X X X
-tv_contrast int -100 100 X X X
-tv_saturation int -100 100 X X X
-tv_hue int -100 100 X X X
-teletext_page int 0 799 X X X
-teletext_subpage int 0 64 X X X
-teletext_mode flag 0 1 X X X 0 - off, 1 - on
-teletext_format int 0 3 X X X 0 - opaque,
- 1 - transparent,
- 2 - opaque inverted,
- 3 - transp. inv.
-teletext_half_page int 0 2 X X X 0 - off, 1 - top half,
- 2- bottom half
diff --git a/DOCS/OUTDATED-tech/subcp.txt b/DOCS/OUTDATED-tech/subcp.txt
deleted file mode 100644
index 50d9cc69f9..0000000000
--- a/DOCS/OUTDATED-tech/subcp.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-Ascii Subtitle / Font CODEPAGEs
-===============================
-
-The subtitle encoding issue seems a bit confusing, so I'll try to
-summarize it here.
-
-There are 2 approaches:
-
-1. (preferred) You can generate Unicode subtitles with:
- subfont --unicode <signle-byte encoding known by iconv> ...
-or
- subfont --unicode <path to custom encoding file> ...
- (this custom encoding file could list all iso-8859-* characters to create
-single font file for common encodings)
-
-and then run mplayer this way (-subcp and -utf8 expect Unicode font!):
- mplayer -subcp <any encoding known by iconv> ...
-or
- mplayer -utf8 ...
-
-2. (current) Generate subtitles for some specific encoding with:
- subfont <signle-byte encoding known by iconv> ...
-or
- subfont <path to custom signle-byte or EUC encoding file> ...
-
-and then run mplayer without any encoding options for signle-byte
-encodings, or with -unicode option for EUC (and the like) encodings
-(which is only partially implemented in mplayer).
-
-AFAIK, CJK encodings: EUC-*, BIG5 and GB2312 work more or less this way:
-- 0x8e (SINGLE-SHIFT TWO, SS2) begins a 2-byte character,
-- 0x8f (SINGLE-SHIFT THREE, SS3) begins a 3-byte character,
-- 0xa0-0xff begin 2-byte characters,
-- other characters are single-byte.
-
-
-I tested charmap2enc script only with /usr/share/i18n/charmaps/EUC-KR.gz
-(on RedHat). It wasn't intended to be perfect.
-
-
---
-Artur Zaprzala
diff --git a/DOCS/OUTDATED-tech/win32-codec-howto.txt b/DOCS/OUTDATED-tech/win32-codec-howto.txt
deleted file mode 100644
index 458a9191b3..0000000000
--- a/DOCS/OUTDATED-tech/win32-codec-howto.txt
+++ /dev/null
@@ -1,118 +0,0 @@
-============================
-Win32 codecs importing HOWTO
-============================
-
-This document describes how to extract the information necessary to hook
-up Win32 binary codecs in MPlayer from a Windows system. Different methods
-exist depending on which video API your codec uses and which Windows
-version you have.
-
-If you have gathered all the necessary information (fourcc, GUID, codec file,
-sample file) as described below, notify the mplayer-dev-eng mailing list.
-If you want to add a codec yourself, read DOCS/tech/codecs.conf.txt.
-
-
-
-VfW codecs
-~~~~~~~~~~
-
-VfW (Video for Windows) is the old video API for Windows. Its codecs have
-the '.dll' or (rarely) '.drv' extension. If MPlayer fails at playing your
-AVI with this kind of message:
-
-VIDEO: [HFYU] 352x288 24bpp 25.000 fps 4321.0 kbps (527.5 kbyte/s)
-Cannot find codec matching selected -vo and video format 0x55594648.
-
-It means your AVI is encoded with a codec which has the HFYU fourcc (HFYU =
-HuffYUV codec, DIV3 = DivX Low Motion, etc.). Now that you know this, you
-have to find out which DLL Windows loads in order to play this file.
-You can find the VfW codec by searching the internet for e.g. VIDC.HFYU.
-
-In our case, the 'system.ini' also contains this information in a line that reads:
-
-VIDC.HFYU=huffyuv.dll
-
-So you need the 'huffyuv.dll' file.
-
-
-
-ACM Codecs:
-~~~~~~~~~~~~
-MPlayer may fail at playing the audio in your file with this message:
-
-Cannot find codec for audio format 0x55.
-Audio: no sound
-
-MPlayer calls this the TwoCC format identifier. From the TwoCC list we find:
-
-0x0055 MPEG-1 Layer 3 (MP3)
-
-If you are lucky, you can then just search the internet for "codec acm"
-e.g. "mp3 acm". Or if the codec is already installed on Windows,
-it will show up in the system.ini as:
-
-msacm.l3acm=L3codeca.acm
-
-Note that the audio codecs are specified by the MSACM prefix:
-
-
-
-DirectShow codecs:
-~~~~~~~~~~~~~~~~~~
-
-DirectShow is the newer video API, which is even worse than its predecessor.
-Things are harder with DirectShow, since 'system.ini' does not contain the
-needed information, instead it is stored in the registry and we need the
-GUID of the codec.
-
-
-New Method:
------------
-
-Using Microsoft GraphEdit (fast)
-
-- Get GraphEdit from the Microsoft SDK, DirectX SDK or doom9.
-- Start 'graphedit.exe'.
-- From the menu select "Graph -> Insert Filters".
-- Expand item "DirectShow Filters".
-- Select the right codec name and expand item.
-- In the entry "DisplayName" look at the text in winged brackets after the
- backslash and write it down (five dash-delimited blocks, the GUID).
-- The codec binary is the file specified in the "Filename" entry.
-
-If there is no "Filename" and "DisplayName" contains something like
-'device:dmo', then it is a DMO-Codec.
-
-
-Old Method:
------------
-
-Take a deep breath and start searching the registry...
-
-- Start 'regedit'.
-- Press "Ctrl-F", disable the first two checkboxes, and enable the third.
- Type in the fourcc of the codec (e.g. "TM20").
-- You should see a field which contains the path and the filename (e.g.
- "C:\WINDOWS\SYSTEM\TM20DEC.AX").
-- Now that you have the file, we need the GUID. Try searching again, but
- now search for the codec's name, not the fourcc. Its name can be acquired
- when Media Player is playing the file, by checking
- "File -> Properties -> Advanced".
- If not, you are out of luck. Try guessing (e.g. search for TrueMotion).
-- If the GUID is found you should see a "FriendlyName" and a "CLSID" field.
- Write down the 16 byte CLSID, this is the GUID we need.
-
-If searching fails, try enabling all the checkboxes. You may have
-false hits, but you may get lucky...
-
-
-
-Tips:
-~~~~~~~
-If you get an error loading a new codec, it may need some more files to work.
-Start the filemon utility before loading MPlayer to find out which DLLs are
-trying to be loaded.
-
-Your codec may load some external DLL libraries. If the codec is already
-installed in Windows, run listdlls wmplayer.exe while Windows Media
-Player is playing your file to find out which.
diff --git a/DOCS/encoding.rst b/DOCS/encoding.rst
index bc301cfea7..979bc0b322 100644
--- a/DOCS/encoding.rst
+++ b/DOCS/encoding.rst
@@ -67,7 +67,7 @@ Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
mpv infile -o outfile.mkv \
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
- -oac vorbis -oacopts qscale=3
+ -oac libvorbis -oacopts qscale=3
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, MPEG-4 (MP4) container::
@@ -90,10 +90,12 @@ As the options for various devices can get complex, profiles can be used.
An example profile file for encoding is provided in
etc/encoding-example-profiles.conf in the source tree. You can include it into
-your configuration by doing, from the mpv-build directory::
+your configuration by doing::
mkdir -p ~/.mpv
- echo "include = $PWD/mpv/etc/encoding-example-profiles.conf" >> ~/.mpv/config
+ curl https://raw.github.com/mpv-player/mpv/master/etc/encoding-example-profiles.conf \
+ > ~/.mpv/encoding-profiles.conf
+ echo "include = $HOME/.mpv/encoding-profiles.conf" >> ~/.mpv/config
Refer to the top of that file for more comments - in a nutshell, the following
options are added by it::
diff --git a/DOCS/man/en/af.rst b/DOCS/man/en/af.rst
index aff84114d0..08e7853990 100644
--- a/DOCS/man/en/af.rst
+++ b/DOCS/man/en/af.rst
@@ -29,55 +29,32 @@ filter list.
Available filters are:
-resample[=srate[:sloppy[:type]]]
- Changes the sample rate of the audio stream. Can be used if you have a
- fixed frequency sound card or if you are stuck with an old sound card that
- is only capable of max 44.1kHz. This filter is automatically enabled if
- necessary. It only supports 16-bit integer and float in native-endian
- format as input.
-
- <srate>
- output sample frequency in Hz. The valid range for this parameter is
- 8000 to 192000. If the input and output sample frequency are the same
- or if this parameter is omitted the filter is automatically unloaded.
- A high sample frequency normally improves the audio quality,
- especially when used in combination with other filters.
- <sloppy>
- Allow (1) or disallow (0) the output frequency to differ slightly from
- the frequency given by <srate> (default: 1). Can be used if the
- startup of the playback is extremely slow.
- <type>
- Select which resampling method to use.
-
- :0: linear interpolation (fast, poor quality especially when
- upsampling)
- :1: polyphase filterbank and integer processing
- :2: polyphase filterbank and floating point processing
- (slow, best quality)
+lavrresample[=option1:option2:...]
+ This filter uses libavresample (or libswresample, depending on the build)
+ to change sample rate, sample format, or channel layout of the audio stream.
+ This filter is automatically enabled if the audio output doesn't support
+ the audio configuration of the file being played.
- *EXAMPLE*:
-
- ``mpv --af=resample=44100:0:0``
- would set the output frequency of the resample filter to 44100Hz using
- exact output frequency scaling and linear interpolation.
+ It supports only the following sample formats: u8, s16ne, s32ne, floatne.
-lavcresample[=srate[:length[:linear[:count[:cutoff]]]]]
- Changes the sample rate of the audio stream to an integer <srate> in Hz.
- It only supports the 16-bit native-endian format.
-
- <srate>
+ srate=<srate>
the output sample rate
- <length>
+ length=<length>
length of the filter with respect to the lower sampling rate (default:
16)
- <linear>
- if 1 then filters will be linearly interpolated between polyphase
- entries
- <count>
+ phase_shift=<count>
log2 of the number of polyphase entries (..., 10->1024, 11->2048,
12->4096, ...) (default: 10->1024)
- <cutoff>
+ cutoff=<cutoff>
cutoff frequency (0.0-1.0), default set depending upon filter length
+ linear
+ if set then filters will be linearly interpolated between polyphase
+ entries (default: no)
+ no-detach
+ don't detach if input and output audio format/rate/channels are the
+ same. You should add this option if you specify additional parameters,
+ as automatically inserted lavrresample instances will use the
+ default settings.
lavcac3enc[=tospdif[:bitrate[:minchn]]]
Encode multi-channel audio to AC-3 at runtime using libavcodec. Supports
@@ -233,6 +210,34 @@ channels=nch[:nr:from1:to1:from2:to2:from3:to3:...]
Would change the number of channels to 6 and set up 4 routes that copy
channel 0 to channels 0 to 3. Channel 4 and 5 will contain silence.
+force=in-format:in-srate:in-channels:out-format:out-srate:out-channels
+ Force a specific audio format/configuration without actually changing the
+ audio data. Keep in mind that the filter system might auto-insert actual
+ conversion filters before or after this filter if needed.
+
+ All parameters are optional. The ``in-`` variants restrict what the filter
+ accepts as input. The ``out-`` variants change the audio format, without
+ actually doing a conversion. The data will be 'reinterpreted' by the
+ filters or audio outputs following this filter.
+
+ <in-format>
+ Force conversion to this format. See ``format`` filter for valid audio
+ format values.
+
+ <in-srate>
+ Force conversion to a specific sample rate. The rate is an integer,
+ 48000 for example.
+
+ <in-channels>
+ Force mixing to a specific channel layout. See ``--channels`` option
+ for possible values.
+
+ <out-format>
+
+ <out-srate>
+
+ <out-channels>
+
format[=format]
Convert between different sample formats. Automatically enabled when
needed by the sound card or another filter. See also ``--format``.
@@ -247,7 +252,7 @@ format[=format]
rule that are also valid format specifiers: u8, s8, floatle, floatbe,
floatne, mpeg2, and ac3.
-volume[=v[:sc]]
+volume[=v[:sc[:fast]]]
Implements software volume control. Use this filter with caution since it
can reduce the signal to noise ratio of the sound. In most cases it is
best to set the level for the PCM sound to max, leave this filter out and
@@ -261,8 +266,7 @@ volume[=v[:sc]]
This filter has a second feature: It measures the overall maximum sound
level and prints out that level when mpv exits. This feature currently
- only works with floating-point data, use e.g. ``--af-adv=force=5``, or use
- ``--af=stats``.
+ only works with floating-point data.
*NOTE*: This filter is not reentrant and can therefore only be enabled
once for every audio stream.
@@ -278,6 +282,9 @@ volume[=v[:sc]]
*WARNING*: This feature creates distortion and should be considered a
last resort.
+ <fast>
+ Force S16 sample format if set to 1. Lower quality, but might be faster
+ in some situations.
*EXAMPLE*:
@@ -314,6 +321,11 @@ pan=n[:L00:L01:L02:...L10:L11:L12:...Ln0:Ln1:Ln2:...]
channels 0 and 1 into output channel 2 (which could be sent to a
subwoofer for example).
+ *NOTE*: if you just want to force remixing to a certain output channel
+ layout, it's easier to use the ``force`` filter. For example,
+ ``mpv '--af=force=channels=5.1' '--channels=5.1'`` would always force
+ remixing audio to 5.1 and output it like this.
+
sub[=fc:ch]
Adds a subwoofer channel to the audio stream. The audio data used for
creating the subwoofer channel is an average of the sound in channel 0 and
@@ -428,8 +440,9 @@ extrastereo[=mul]
(average of both channels), with 1.0 sound will be unchanged, with
-1.0 left and right channels will be swapped.
-volnorm[=method:target]
- Maximizes the volume without distorting the sound.
+drc[=method:target]
+ Applies dynamic range compression. This maximizes the volume by compressing
+ the audio signal's dynamic range.
<method>
Sets the used method.
@@ -445,6 +458,9 @@ volnorm[=method:target]
Sets the target amplitude as a fraction of the maximum for the sample
type (default: 0.25).
+ *NOTE*: This filter can cause distortion with audio signals that have a
+ very large dynamic range.
+
ladspa=file:label[:controls...]
Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin. This
filter is reentrant, so multiple LADSPA plugins can be used at once.
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index eb3f4d0d91..4c80af6b25 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -120,10 +120,17 @@ Command line switches
-vobsub --sub (pass the .idx file)
-ass-bottom-margin --vf=sub=bottom:top
-vc ffh264vdpau (etc.) --hwdec=vdpau
- -x, -y --geometry + --no-keepaspect
- -xy --autofit
+ -ac spdifac3 --ad=spdif:ac3 (see --ad=help)
+ -afm hwac3 --ad=spdif:ac3,spdif:dts
+ -x W, -y H --geometry=WxH + --no-keepaspect
+ -xy W --autofit=W
+ -a52drc level --ad-lavc-ac3drc=level
+ -dumpstream --stream-dump=<filename>
+ -capture --stream-capture=<filename>
=================================== ===================================
+*NOTE*: ``-opt val`` becomes ``--opt=val``.
+
input.conf and slave commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -154,7 +161,7 @@ input.conf and slave commands
| | a negative step instead. |
+--------------------------------+----------------------------------------+
| step_property <prop> <step> | Prefix cycle or add with no-osd: |
- | <dur> | no-osd cycle <prop> <step> |
+ | <dir> | no-osd cycle <prop> <step> |
+--------------------------------+----------------------------------------+
| osd_show_property_text <text> | show_text <text> |
| | The property expansion format string |
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
index f693436e53..59d48f5a28 100644
--- a/DOCS/man/en/input.rst
+++ b/DOCS/man/en/input.rst
@@ -14,7 +14,7 @@ with shift.
A list of special keys can be obtained with
-| **mpv** --input=keylist
+| **mpv** --input-keylist
In general, keys can be combined with ``Shift``, ``Ctrl`` and ``Alt``:
@@ -23,7 +23,7 @@ In general, keys can be combined with ``Shift``, ``Ctrl`` and ``Alt``:
**mpv** can be started in input test mode, which displays key bindings and the
commands they're bound to on the OSD, instead of running the commands:
-| **mpv** --input=test --demuxer=rawvideo --rawvideo=w=1280:h=720 /dev/zero
+| **mpv** --input-test --demuxer=rawvideo --rawvideo=w=1280:h=720 /dev/zero
(Commands which normally close the player will not work in this mode, and you
must kill **mpv** externally to make it exit.)
@@ -51,7 +51,7 @@ List of input commands
ignore
Use this to "block" keys that should be unbound, and do nothing. Useful for
disabling default bindings, without disabling all bindings with
- ``--input=default-bindings=no``.
+ ``--no-input-default-bindings``.
seek <seconds> [relative|absolute|absolute-percent|- [default-precise|exact|keyframes]]
Change the playback position. By default, seeks by a relative amount of
@@ -79,6 +79,17 @@ seek <seconds> [relative|absolute|absolute-percent|- [default-precise|exact|keyf
frame_step
Play one frame, then pause.
+frame_back_step
+ Go back by one frame, then pause. Note that this can be very slow (it tries
+ to be precise, not fast), and sometimes fails to behave as expected. How
+ well this works depends on whether precise seeking works correctly (e.g.
+ see the ``--hr-seek-demuxer-offset`` option). Video filters or other video
+ postprocessing that modifies timing of frames (e.g. deinterlacing) should
+ usually work, but might make backstepping silently behave incorrectly in
+ corner cases.
+
+ This doesn't work with audio-only playback.
+
set <property> "<value>"
Set the given property to the given value.
@@ -158,6 +169,10 @@ run "<command>"
quit [<code>]
Exit the player using the given exit code.
+quit_watch_later
+ Exit player, and store current playback position. Playing that file later
+ will seek to the previous position on start.
+
sub_add "<file>"
Load the given subtitle file. It's not selected as current subtitle after
loading.
@@ -205,13 +220,63 @@ show_tracks
Show a list of video/audio/subtitle tracks on the OSD.
+Input commands that are possibly subject to change
+--------------------------------------------------
+
+af_switch "filter1=params,filter2,..."
+ Replace the current filter chain with the given list.
+
+af_add "filter1=params,filter2,..."
+ Add the given list of audio filters to the audio filter chain.
+
+af_del "filter1,filter2,..."
+ Remove the given list of audio filters.
+
+af_clr
+ Remove all audio filters. (Conversion filters will be re-added
+ automatically if needed.)
+
+vf set|add|toggle|del "filter1=params,filter2,..."
+ Change video filter chain.
+
+ The first argument decides what happens:
+
+ set
+ Overwrite the previous filter chain with the new one.
+
+ add
+ Append the new filter chain to the previous one.
+
+ toggle
+ Check if the given filter (with the exact parameters) is already
+ in the video chain. If yes, remove the filter. If no, add the filter.
+ (If several filters are passed to the command, this is done for
+ each filter.)
+
+ del
+ Remove the given filters from the video chain. Unlike in the other
+ cases, the second parameter is a comma separated list of filter names
+ or integer indexes. ``0`` would denote the first filter. Negative
+ indexes start from the last filter, and ``-1`` denotes the last
+ filter.
+
+ You can assign labels to filter by prefixing them with ``@name:`` (where
+ ``name`` is a user-chosen arbitrary identifiers). Labels can be used to
+ refer to filters by name in all of the filter chain modification commands.
+ For ``add``, using an already used label will replace the existing filter.
+
+ *EXAMPLE for input.conf*:
+
+ - ``a vf set flip`` turn video upside-down on the ``a`` key
+ - ``b vf set ""`` remove all video filters on ``b``
+ - ``c vf toggle lavfi=gradfun`` toggle debanding on ``c``
+
Undocumented commands: tv_start_scan, tv_step_channel, tv_step_norm,
tv_step_chanlist, tv_set_channel, tv_last_channel, tv_set_freq, tv_step_freq,
tv_set_norm, dvb_set_channel, radio_step_channel, radio_set_channel,
radio_set_freq, radio_step_freq (all of these should be replaced by properties),
-edl_mark, stop (questionable use), get_property (?), af_switch, af_add, af_del,
-af_clr, af_cmdline, vo_cmdline (experimental).
+stop (questionable use), get_property (?), af_cmdline, vo_cmdline (experimental).
Input command prefixes
----------------------
@@ -229,10 +294,14 @@ osd-msg
value as text.
osd-msg-bar
Combine osd-bar and osd-msg.
+raw
+ Don't expand properties in string arguments. (Like ``"${property-name}"``.)
+expand-properties (default)
+ All string arguments are expanded like in ``--playing-msg``.
-
-All of these are still overridden by the global ``--osd-level`` settings.
+All of the osd prefixes are still overridden by the global ``--osd-level``
+settings.
Undocumented prefixes: pausing, pausing_keep, pausing_toggle,
pausing_keep_force. (Should these be made official?)
@@ -253,6 +322,7 @@ option.
Name W Comment
=========================== = ==================================================
osd-level x see ``--osd-level``
+osd-scale x osd font size multiplicator, see ``--osd-scale``
loop x see ``--loop``
speed x see ``--speed``
filename currently played file (path stripped)
@@ -269,6 +339,7 @@ length length of the current file in seconds
avsync last A/V synchronization difference
percent-pos x position in current file (0-100)
time-pos x position in current file in seconds
+time-remaining estimated remaining length of the file in seconds
chapter x current chapter number
edition x current MKV edition number
titles number of DVD titles
@@ -278,12 +349,13 @@ angle x current DVD angle
metadata metadata key/value pairs
metadata/<key> value of metadata entry <key>
pause x pause status (bool)
+cache network cache fill state (0-100)
pts-association-mode x see ``--pts-association-mode``
hr-seek x see ``--hr-seek``
volume x current volume (0-100)
mute x current mute status (bool)
audio-delay x see ``--audio-delay``
-audio-format audio format (codec tag)
+audio-format audio format (string)
audio-codec audio codec selected for decoding
audio-bitrate audio bitrate
samplerate audio samplerate
@@ -296,7 +368,6 @@ colormatrix x see ``--colormatrix``
colormatrix-input-range x see ``--colormatrix-input-range``
colormatrix-output-range x see ``--colormatrix-output-range``
ontop x see ``--ontop``
-rootwin x see ``--rootwin``
border x see ``--border``
framedrop x see ``--framedrop``
gamma x see ``--gamma``
@@ -305,17 +376,18 @@ contrast x see ``--contrast``
saturation x see ``--saturation``
hue x see ``--hue``
panscan x see ``--panscan``
-vsync x see ``--vsync``
-video-format video format (integer FourCC)
+video-format video format (string)
video-codec video codec selected for decoding
video-bitrate video bitrate
-width video width
+width video width (container or decoded size)
height video height
-fps FPS (may contain bogus values)
+fps container FPS (may contain bogus values)
+dwidth video width (after filters and aspect scaling)
+dheight video height
aspect x video aspect
video x current video track (similar to ``--vid``)
program x switch TS program (write-only)
-sub x current subttitle track (similar to ``--sid``)
+sub x current subtitle track (similar to ``--sid``)
sub-delay x see ``--sub-delay``
sub-pos x see ``--sub-pos``
sub-visibility x whether current subtitle is rendered
@@ -324,6 +396,7 @@ sub-scale x subtitle font size multiplicator
ass-use-margins x see ``--ass-use-margins``
ass-vsfilter-aspect-compat x see ``--ass-vsfilter-aspect-compat``
ass-style-override x see ``--ass-style-override``
+stream-capture x a filename, see ``--capture``
tv-brightness x
tv-contrast x
tv-saturation x
diff --git a/DOCS/man/en/mpv.rst b/DOCS/man/en/mpv.rst
index d8fa642546..2ebdcab506 100644
--- a/DOCS/man/en/mpv.rst
+++ b/DOCS/man/en/mpv.rst
@@ -49,7 +49,7 @@ INTERACTIVE CONTROL
mpv has a fully configurable, command-driven control layer which allows you
to control mpv using keyboard, mouse, joystick or remote control (with
-LIRC). See the ``--input`` option for ways to customize it.
+LIRC). See the ``--input-`` options for ways to customize it.
keyboard control
----------------
@@ -90,6 +90,10 @@ p / SPACE
q / ESC
Stop playing and quit.
+Q
+ Like ``q``, but store the current playback position. Playing the same file
+ later will resume at the old playback position if possible.
+
U
Stop playing (and quit if ``--idle`` is not used).
@@ -142,9 +146,6 @@ j and J
F
Toggle displaying "forced subtitles".
-a
- Toggle subtitle alignment: top / middle / bottom.
-
x and z
Adjust subtitle delay by +/- 0.1 seconds.
@@ -190,7 +191,7 @@ corresponding adjustment, or the software equalizer (``--vf=eq``).)
Adjust brightness.
5 and 6
- Adjust hue.
+ Adjust gamma.
7 and 8
Adjust saturation.
@@ -279,11 +280,11 @@ the *XXX* option or if *XXX* is compiled in.
GUIs.
| It has the following format:
| %n%string\_of\_length\_n
+
| *EXAMPLES*:
-| `mpv --ao pcm:file=%10%C:test.wav test.avi`
+| `mpv --ao=pcm:file=%10%C:test.wav test.avi`
| Or in a script:
-| `mpv --ao pcm:file=%\`expr length "$NAME"\`%"$NAME" test.avi`
-
+| `mpv --ao=pcm:file=%\`expr length "$NAME"\`%"$NAME" test.avi`
Per-file options
----------------
@@ -330,6 +331,9 @@ The option ``--a`` is never reset here.
CONFIGURATION FILES
===================
+Location and syntax
+-------------------
+
You can put all of the options in configuration files which will be read every
time mpv is run. The system-wide configuration file 'mpv.conf' is in
your configuration directory (e.g. ``/etc/mpv`` or
@@ -340,6 +344,34 @@ command line override either. The syntax of the configuration files is
that work without values can be enabled by setting them to *yes* and disabled by
setting them to *no*. Even suboptions can be specified in this way.
+*EXAMPLE CONFIGURATION FILE:*
+
+| # Use opengl video output by default.
+| vo=opengl
+| # Use quotes for text that can contain spaces:
+| status-msg="Time: ${time-pos}"
+
+Putting command line options into the configuration file
+--------------------------------------------------------
+
+Almost all command line options can be put into the configuration file. Here
+is a small guide:
+
++----------------------+--------------------------+
+| Option | Configuration file entry |
++======================+==========================+
+| --flag | flag |
++----------------------+--------------------------+
+| -opt val | opt=val |
++----------------------+--------------------------+
+| --opt=val | opt=val |
++----------------------+--------------------------+
+| -opt "has spaces" | opt="has spaces" |
++----------------------+--------------------------+
+
+File specific configuration files
+---------------------------------
+
You can also write file-specific configuration files. If you wish to have a
configuration file for a file called 'movie.avi', create a file named
'movie.avi.conf' with the file-specific options in it and put it in
@@ -352,21 +384,9 @@ file-specific configuration is loaded from ``~/.mpv``. In addition, the
For this, mpv first tries to load a mpv.conf from the same directory
as the file played and then tries to load any file-specific configuration.
-*EXAMPLE MPV CONFIGURATION FILE:*
-
-| # Use opengl video output by default.
-| vo=opengl
-| # I love practicing handstands while watching videos.
-| flip=yes
-| # Decode multiple files from PNG,
-| # start with mf://filemask
-| mf=type=png:fps=25
-| # Eerie negative images are cool.
-| vf=eq=1.0:-0.8
-
-PROFILES
-========
+Profiles
+--------
To ease working with different configurations profiles can be defined in the
configuration files. A profile starts with its name between square brackets,
@@ -377,6 +397,10 @@ option. To end the profile, start another one or use the profile name
*EXAMPLE MPV PROFILE:*
+| [vo.vdpau]
+| # Use hardware decoding (this might break playback of some h264 files)
+| hwdec=vdpau
+|
| [protocol.dvd]
| profile-desc="profile for dvd:// streams"
| vf=pp=hb/vb/dr/al/fd
@@ -565,7 +589,7 @@ FILES
mpv user settings
``~/.mpv/input.conf``
- input bindings (see ``--input=keylist`` for the full list)
+ input bindings (see ``--input-keylist`` for the full list)
``~/.mpv/DVDkeys/``
cached CSS keys
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index 107e3be377..8eec8408a7 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -1,4 +1,35 @@
---a52drc=<level>
+--abs=<value>
+ (``--ao=oss`` only) (OBSOLETE)
+ Override audio driver/card buffer size detection.
+
+--ad=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>
+ Specify a priority list of audio decoders to be used, according to their
+ family and decoder name. Entries like ``family:*`` prioritize all decoders
+ of the given family. When determining which decoder to use, the first
+ decoder that matches the audio format is selected. If that is unavailable,
+ the next decoder is used. Finally, it tries all other decoders that are not
+ explicitly selected or rejected by the option.
+
+ ``-`` at the end of the list suppresses fallback to other available
+ decoders not on the ``--ad`` list. ``+`` in front of an entry forces the
+ decoder. Both of these shouldn't normally be used, because they break
+ normal decoder auto-selection!
+
+ ``-`` in front of an entry disables selection of the decoder.
+
+ *EXAMPLE*:
+
+ ``--ad=lavc:mp3float``
+ Prefer the FFmpeg/Libav ``mp3float`` decoder over all other mp3
+ decoders.
+
+ ``--ad=spdif:ac3,lavc:*``
+ Always prefer spdif AC3 over FFmpeg/Libav over anything else.
+
+ ``--ad=help``
+ List all available decoders.
+
+--ad-lavc-ac3drc=<level>
Select the Dynamic Range Compression level for AC-3 audio streams. <level>
is a float value ranging from 0 to 1, where 0 means no compression and 1
(which is the default) means full compression (make loud passages more
@@ -6,18 +37,16 @@
experimental. This option only shows an effect if the AC-3 stream contains
the required range compression information.
---abs=<value>
- (``--ao=oss`` only) (OBSOLETE)
- Override audio driver/card buffer size detection.
+--ad-lavc-downmix=<yes|no>
+ Whether to request audio channel downmixing from the decoder (default: yes).
+ Some decoders, like AC-3, AAC and DTS, can remix audio on decoding. The
+ requested number of output channels is set with the ``--channels`` option.
+ Useful for playing surround audio on a stereo system.
---ac=<[-\|+]codec1,[-\|+]codec2,...[,]>
- Specify a priority list of audio codecs to be used, according to their
- codec name in codecs.conf. Use a '-' before the codec name to omit it.
- Use a '+' before the codec name to force it, this will likely crash! If
- the list has a trailing ',' mpv will fall back on codecs not contained
- in the list.
-
- *NOTE*: See ``--ac=help`` for a full list of available codecs.
+--ad-lavc-o=<key>=<value>[,<key>=<value>[,...]]
+ Pass AVOptions to libavcodec decoder. Note, a patch to make the o=
+ unneeded and pass all unknown options through the AVOption system is
+ welcome. A full list of AVOptions can be found in the FFmpeg manual.
--af=<filter1[=parameter1:parameter2:...],filter2,...>
Specify a list of audio filters to apply to the audio stream. See
@@ -26,51 +55,6 @@
``--af-clr`` exist to modify a previously specified list, but you
shouldn't need these for typical use.
---af-adv=<force=(0-7):list=(filters)>
- See also ``--af``.
- Specify advanced audio filter options:
-
- force=<0-7>
- Forces the insertion of audio filters to one of the following:
-
- 0
- Use completely automatic filter insertion (currently identical to
- 1).
- 1
- Optimize for accuracy (default).
- 2
- Optimize for speed. *Warning*: Some features in the audio filters
- may silently fail, and the sound quality may drop.
- 3
- Use no automatic insertion of filters and no optimization.
- *Warning*: It may be possible to crash mpv using this setting.
- 4
- Use automatic insertion of filters according to 0 above, but use
- floating point processing when possible.
- 5
- Use automatic insertion of filters according to 1 above, but use
- floating point processing when possible.
- 6
- Use automatic insertion of filters according to 2 above, but use
- floating point processing when possible.
- 7
- Use no automatic insertion of filters according to 3 above, and
- use floating point processing when possible.
-
- list=<filters>
- Same as ``--af``.
-
---afm=<driver1,driver2,...>
- Specify a priority list of audio codec families to be used, according to
- their codec name in codecs.conf. Falls back on the default codecs if none
- of the given codec families work.
-
- *NOTE*: See ``--afm=help`` for a full list of available codec families.
-
- *EXAMPLE*:
-
- :``--afm=ffmpeg``: Try FFmpeg's libavcodec codecs first.
-
--aid=<ID|auto|no>
Select audio channel. ``auto`` selects the default, ``no`` disables audio.
See also ``--alang``.
@@ -96,9 +80,6 @@
configuration files specifying a list of fallbacks may make sense. See
`audio_outputs` for details and descriptions of available drivers.
---ar, --no-ar
- Enable/disable AppleIR remote support. Enabled by default.
-
--aspect=<ratio>
Override movie aspect ratio, in case aspect information is incorrect or
missing in the file being played. See also ``--no-aspect``.
@@ -219,7 +200,7 @@
are applied after this option.
See ``--geometry`` for details how this is handled with multi-monitor
- setups, or if the ``--wid`` option is used.
+ setups.
Use ``--autofit-larger`` instead if you don't want the window to get larger.
Use ``--geometry`` if you want to force both window width and height to a
@@ -292,11 +273,6 @@
Some Blu-ray discs contain scenes that can be viewed from multiple angles.
Here you can tell mpv which angles to use (default: 1).
---bluray-chapter=<ID>
- (Blu-ray only)
- Tells mpv which Blu-ray chapter to start the current title from
- (default: 1).
-
--bluray-device=<path>
(Blu-ray only)
Specify the Blu-ray disc location. Must be a directory with Blu-ray
@@ -317,6 +293,12 @@
from slow media, but can also have negative effects, especially with file
formats that require a lot of seeking, such as mp4. See also ``--no-cache``.
+ Note that half the cache size will be used to allow fast seeking back. This
+ is also the reason why a full cache is usually reported as 50% full. The
+ cache fill display does not include the part of the cache reserved for
+ seeking back. Likewise, when starting a file the cache will be at 100%,
+ because no space is reserved for seeking back yet.
+
--cache-pause=<no|percentage>
If the cache percentage goes below the specified value, pause and wait
until the percentage set by ``--cache-min`` is reached, then resume
@@ -376,25 +358,24 @@
--cdrom-device=<path>
Specify the CD-ROM device (default: ``/dev/cdrom``).
---channels=<number>
+--channels=<number|layout>
Request the number of playback channels (default: 2). mpv asks the
decoder to decode the audio into as many channels as specified. Then it is
up to the decoder to fulfill the requirement. This is usually only
- important when playing videos with AC-3 audio (like DVDs). In that case
- liba52 does the decoding by default and correctly downmixes the audio into
- the requested number of channels. To directly control the number of output
- channels independently of how many channels are decoded, use the channels
- filter (``--af=channels``).
+ important when playing videos with AC-3, AAC or DTS audio. In that case
+ libavcodec downmixes the audio into the requested number of channels if
+ possible.
*NOTE*: This option is honored by codecs (AC-3 only), filters (surround)
and audio output drivers (OSS at least).
- Available options are:
+ The ``--channels`` option either takes a channel number or an explicit
+ channel layout. Channel numbers refer to default layouts, e.g. 2 channels
+ refer to stereo, 6 refers to 5.1.
- :2: stereo
- :4: surround
- :6: full 5.1
- :8: full 7.1
+ See ``--channels=help`` output for defined default layouts. This also
+ lists speaker names, which can be used to express arbitrary channel
+ layouts (e.g. ``fl-fr-lfe`` is 2.1).
--chapter=<start[-end]>
Specify which chapter to start playing at. Optionally specify which
@@ -409,10 +390,6 @@
the start of the next one then keep playing video normally over the
chapter change instead of doing a seek.
---codecs-file=<filename>
- Override the standard search path and use the specified file instead of
- the builtin codecs.conf.
-
--colormatrix=<colorspace>
Controls the YUV to RGB color space conversion when playing video. There
are various standards. Normally, BT.601 should be used for SD video, and
@@ -528,6 +505,13 @@
Time in milliseconds to recognize two consecutive button presses as a
double-click (default: 300).
+--dtshd, --no-dtshd
+ When using DTS passthrough, output any DTS-HD track as-is.
+ With ``--no-dtshd`` (the default) only the DTS Core parts will be output.
+
+ DTS-HD tracks can be sent over HDMI but not over the original
+ coax/toslink S/PDIF system.
+
--dvbin=<options>
Pass the following parameters to the DVB input module, in order to
override the default ones:
@@ -566,15 +550,6 @@
to -1 (the default), mpv will choose the first edition declared as a
default, or if there is no default, the first edition defined.
---edlout=<filename>
- Creates a new file and writes edit decision list (EDL) records to it.
- During playback, the user hits 'i' to mark the start or end of a skip
- block. This provides a starting point from which the user can fine-tune
- EDL entries later. See http://www.mplayerhq.hu/DOCS/HTML/en/edl.html for
- details.
-
- *NOTE*: broken.
-
--embeddedfonts, --no-embeddedfonts
Use fonts embedded in Matroska container files and ASS scripts (default:
enabled). These fonts can be used for SSA/ASS subtitle rendering
@@ -650,11 +625,29 @@
*NOTE*: Practical use of this feature is questionable. Disabled by default.
--frames=<number>
- Play/convert only first <number> frames, then quit.
+ Play/convert only first <number> video frames, then quit. For audio only,
+ run <number> iteration of the playback loop, which is most likely not what
+ you want. (This behavior also applies to the corner case when there are
+ less video frames than <number>, and audio is longer than the video.)
--fullscreen, --fs
Fullscreen playback (centers movie, and paints black bands around it).
+
+--fs-screen=<all|current|0-32>
+ In multi-monitor configurations (i.e. a single desktop that spans across
+ multiple displays) this option tells mpv which screen to go fullscreen to.
+ If ``default`` is provided mpv will fallback to using the behaviour
+ depending on what the user provided with the ``screen`` option.
+
+ *NOTE (X11)*: this option does not work properly with all window managers.
+ ``all`` in particular will usually only work with ``--fstype=-fullscreen``
+ or ``--fstype=none``, and even then only with some window managers.
+
+ *NOTE (OSX)*: ``all`` doesn't work on OSX and will behave like ``current``.
+
+ See also ``--screen``.
+
--fsmode-dontuse=<0-31>
OBSOLETE, use the ``--fs`` option.
Try this option if you still experience fullscreen problems.
@@ -695,6 +688,13 @@
``--fstype=fullscreen``
Fixes fullscreen switching on OpenBox 1.x.
+--native-fs
+ (OS X only)
+ Use OSX's Mission Control's fullscreen feature instead of the custom one
+ provided by mpv. This can potentially break a lot of stuff like
+ ``--geometry`` and is disabled by default. On the other hand it provides
+ a more 'OS X-like' user experience.
+
--gamma=<-100-100>
Adjust the gamma of the video signal (default: 0). Not supported by all
video output drivers.
@@ -728,11 +728,11 @@
lower border" and "--20+-10" means "place 20 pixels beyond the right and
10 pixels beyond the top border".
- If an external window is specified using the ``--wid`` option,
- then the x and y coordinates are relative to the top-left corner of the
- window rather than the screen. The coordinates are relative to the screen
- given with ``--screen`` for the video output drivers that fully
- support ``--screen``.
+ If an external window is specified using the ``--wid`` option, this
+ option is ignored.
+
+ The coordinates are relative to the screen given with ``--screen`` for the
+ video output drivers that fully support ``--screen``.
*NOTE*: Generally only supported by GUI VOs. Ignored for encoding.
@@ -740,6 +740,8 @@
located on the the bottom-left corner. For instance, ``0:0`` will place the
window at the bottom-left of the screen.
+ *NOTE (X11)*: this option does not work properly with all window managers.
+
*EXAMPLE*:
``50:40``
@@ -768,7 +770,8 @@
--heartbeat-cmd
Command that is executed every 30 seconds during playback via *system()* -
- i.e. using the shell.
+ i.e. using the shell. The time between the commands can be customized with
+ the ``--heartbeat-interval`` option.
*NOTE*: mpv uses this command without any checking. It is your
responsibility to ensure it does not cause security problems (e.g. make
@@ -787,6 +790,9 @@
*EXAMPLE for GNOME screensaver*: ``mpv
--heartbeat-cmd="gnome-screensaver-command -p" file``
+--heartbeat-interval=<sec>
+ Time between ``--heartbeat-cmd`` invocations in seconds (default: 30).
+
--help
Show short summary of options.
@@ -851,13 +857,25 @@
:vda: OSX
:crystalhd: Broadcom Crystal HD
+--hwdec-codecs=<codec1,codec2,...|all>
+ Allow hardware decoding for a given list of codecs only. The default is the
+ special value ``all``, which always allows all codecs.
+
+ This is usually only needed with broken GPUs, where fallback to software
+ decoding doesn't work properly.
+
+ *EXAMPLE*:
+
+ - ``mpv --hwdec=vdpau --vo=vdpau --hwdec-codecs=h264,mpeg2video``
+ Enable vdpau decoding for h264 and mpeg2 only.
+
--identify
Deprecated. Use ``TOOLS/mpv_identify.sh``.
--idle
Makes mpv wait idly instead of quitting when there is no file to play.
Mostly useful in slave mode where mpv can be controlled through input
- commands (see also ``--slave``).
+ commands (see also ``--slave-broken``).
--idx
Rebuilds index of files if no index was found, allowing seeking. Useful
@@ -885,56 +903,43 @@
their start timestamps differ, and then video timing is gradually adjusted
if necessary to reach correct synchronization later.
---input=<commands>
- This option can be used to configure certain parts of the input system.
- Paths are relative to ``~/.mpv/``.
-
- *NOTE*: Autorepeat is currently only supported by joysticks.
-
- Available commands are:
-
- conf=<filename>
- Specify input configuration file other than the default
- ``~/.mpv/input.conf``. ``~/.mpv/<filename>`` is assumed if no
- full path is given.
+--input-conf=<filename>
+ Specify input configuration file other than the default
+ ``~/.mpv/input.conf``.
- ar-dev=<device>
- Device to be used for Apple IR Remote (default is autodetected, Linux
- only).
+--input-ar-delay
+ Delay in milliseconds before we start to autorepeat a key (0 to
+ disable).
- ar-delay
- Delay in milliseconds before we start to autorepeat a key (0 to
- disable).
+--input-ar-rate
+ Number of key presses to generate per second on autorepeat.
- ar-rate
- Number of key presses to generate per second on autorepeat.
+--no-input-default-bindings
+ Disable mpv default (builtin) key bindings.
- (no-)default-bindings
- Use the key bindings that mpv ships with by default.
+--input-keylist
+ Prints all keys that can be bound to commands.
- keylist
- Prints all keys that can be bound to commands.
+--input-cmdlist
+ Prints all commands that can be bound to keys.
- cmdlist
- Prints all commands that can be bound to keys.
+--input-js-dev
+ Specifies the joystick device to use (default: ``/dev/input/js0``).
- js-dev
- Specifies the joystick device to use (default: ``/dev/input/js0``).
+--input-file=<filename>
+ Read commands from the given file. Mostly useful with a FIFO.
+ See also ``--slave-broken``.
- file=<filename>
- Read commands from the given file. Mostly useful with a FIFO.
- See also ``--slave``.
+ *NOTE*: When the given file is a FIFO mpv opens both ends so you
+ can do several `echo "seek 10" > mp_pipe` and the pipe will stay
+ valid.
- *NOTE*: When the given file is a FIFO mpv opens both ends so you
- can do several `echo "seek 10" > mp_pipe` and the pipe will stay
- valid.
-
- test
- Input test mode. Instead of executing commands on key presses, mpv
- will show the keys and the bound commands on the OSD. Has to be used
- with a dummy video, and the normal ways to quit the player will not
- work (key bindings that normally quit will be shown on OSD only, just
- like any other binding).
+--input-test
+ Input test mode. Instead of executing commands on key presses, mpv
+ will show the keys and the bound commands on the OSD. Has to be used
+ with a dummy video, and the normal ways to quit the player will not
+ work (key bindings that normally quit will be shown on OSD only, just
+ like any other binding).
--ipv4-only-proxy
Skip any HTTP proxy for IPv6 addresses. It will still be used for IPv4
@@ -1160,6 +1165,29 @@
:fps=<value>: output fps (default: 25)
:type=<value>: input file type (available: jpeg, png, tga, sgi)
+--mkv-subtitle-preroll
+ Try harder to show embedded soft subtitles when seeking somewhere. Normally,
+ it can happen that the subtitle at the seek target is not shown due to how
+ some container file formats are designed. The subtitles appear only if
+ seeking before or exactly to the position a subtitle first appears. To
+ make this worse, subtitles are often timed to appear a very small amount
+ before the associated video frame, so that seeking to the video frame
+ typically does not demux the subtitle at that position.
+
+ Enabling this option makes the demuxer start reading data a bit before the
+ seek target, so that subtitles appear correctly. Note that this makes
+ seeking slower, and is not guaranteed to always work. It only works if the
+ subtitle is close enough to the seek target.
+
+ Works with the internal Matroska demuxer only. Always enabled for absolute
+ and hr-seeks, and this option changes behavior with relative or imprecise
+ seeks only.
+
+ See also ``--hr-seek-demuxer-offset`` option. This option can achieve a
+ similar effect, but only if hr-seek is active. It works with any demuxer,
+ but makes seeking much slower, as it has to decode audio and video data,
+ instead of just skipping over it.
+
--mixer=<device>
Use a mixer device different from the default ``/dev/mixer``. For ALSA
this is the mixer name.
@@ -1239,6 +1267,12 @@
--name
Set the window class name for X11-based video output methods.
+--native-keyrepeat
+ Use system settings for keyrepeat delay and rate, instead of
+ ``--input-ar-delay`` and ``--input-ar-rate``. (Whether this applies
+ depends on the VO backend and how it handles keyboard input. Does not
+ apply to terminal input.)
+
--avi-ni
(Internal AVI demuxer which is not used by default only)
Force usage of non-interleaved AVI parser (fixes playback of some bad AVI
@@ -1260,17 +1294,16 @@
Disables colorkeying. Only supported by the xv (see ``--vo=xv:ck``) video
output driver.
---no-config=<options>
- Do not parse selected configuration files.
+--no-config
+ Do not load default configuration files. This prevents loading of
+ ``~/.mpv/config`` and ``~/.mpv/input.conf``, as well as loading the
+ same files from system wide configuration directories.
- *NOTE*: If ``--include`` or ``--use-filedir-conf`` options are specified
- at the command line, they will be honoured.
+ Loading of some configuration files is not affected by this option, such
+ as configuration files for cddb, DVB code and fontconfig.
- Available options are:
-
- :all: all configuration files
- :system: system configuration file
- :user: user configuration file
+ *NOTE*: Files explicitly requested by command line options, like
+ ``--include`` or ``--use-filedir-conf``, will still be loaded.
--no-idx
Do not use index present in the file even if one is present.
@@ -1279,6 +1312,10 @@
Do not play sound. With some demuxers this may not work. In those cases
you can try ``--ao=null`` instead.
+--no-resume-playback
+ Do not restore playback position from ``~/.mpv/watch_later/``.
+ See ``quit_watch_later`` input command.
+
--no-sub
Disables display of internal and external subtitles.
@@ -1296,9 +1333,33 @@
search for video segments from other files, and will also ignore any
chapter order specified for the main file.
+--no-osd-bar, --osd-bar
+ Disable display of the OSD bar. This will make some things (like seeking)
+ use OSD text messages instead of the bar.
+
+ You can configure this on a per-command basis in input.conf using ``osd-``
+ prefixes, see ``Input command prefixes``. If you want to disable the OSD
+ completely, use ``--osd-level=0``.
+
+--osd-bar-align-x=<-1-1>
+ Position of the OSD bar. -1 is far left, 0 is centered, 1 is far right.
+
+--osd-bar-align-y=<-1-1>
+ Position of the OSD bar. -1 is top, 0 is centered, 1 is bottom.
+
+--osd-bar-w=<1-100>
+ Width of the OSD bar, in percentage of the screen width (default: 75).
+ A value of 0.5 means the bar is half the screen wide.
+
+--osd-bar-h=<0.1-50>
+ Height of the OSD bar, in percentage of the screen height (default: 3.125).
+
--osd-back-color=<#RRGGBB>, --sub-text-back-color=<#RRGGBB>
See ``--osd-color``. Color used for OSD/sub text background.
+--osd-blur=<0..20.0>, --sub-text-blur=<0..20.0>
+ Gaussian blur factor. 0 means no blur applied (default).
+
--osd-border-color=<#RRGGBB>, --sub-text-border-color=<#RRGGBB>
See ``--osd-color``. Color used for the OSD/sub font border.
@@ -1382,6 +1443,9 @@
Default: 10.
+--osd-scale=<factor>
+ OSD font size multiplicator, multiplied with ``--osd-font-size`` value.
+
--osd-shadow-color=<#RRGGBB>, --sub-text-shadow-color=<#RRGGBB>
See ``--osd-color``. Color used for OSD/sub text shadow.
@@ -1398,6 +1462,12 @@
Default: 0.
+--osd-status-msg=<string>
+ Show a custom string during playback instead of the standard status text.
+ This overrides the status text used for ``--osd-level=3``, when using the
+ ``show_progress`` command (by default mapped to ``P``), or in some
+ non-default cases when seeking. Expands properties. See ``--playing-msg``.
+
--overlapsub
Allows the next subtitle to be displayed while the current one is still
visible (default is to enable the support only for specific formats). This
@@ -1424,8 +1494,8 @@
*WARNING*: works with the deprecated ``mp_http://`` protocol only.
--playing-msg=<string>
- Print out a string before starting playback. The string is expanded for
- properties, e.g. ``--playing-msg=file: \${filename}`` will print the string
+ Print out a string after starting playback. The string is expanded for
+ properties, e.g. ``--playing-msg=file: ${filename}`` will print the string
``file:`` followed by a space and the currently played filename.
The following expansions are supported:
@@ -1433,7 +1503,7 @@
\${NAME}
Expands to the value of the property ``NAME``. If ``NAME`` starts with
``=``, use the raw value of the property. If retrieving the property
- fails, expand to an error string. (Use ``\${NAME:}`` with a trailing
+ fails, expand to an error string. (Use ``${NAME:}`` with a trailing
``:`` to expand to an empty string instead.)
\${NAME:STR}
Expands to the value of the property ``NAME``, or ``STR`` if the
@@ -1444,18 +1514,36 @@
\${?NAME:STR}
Expands to ``STR`` (recursively) if the property ``NAME`` is available.
\$\$
- Expands to ``\$``.
+ Expands to ``$``.
\$}
Expands to ``}``. (To produce this character inside recursive
expansion.)
\$>
- Disable property expansion and special handling of ``\$`` for the rest
+ Disable property expansion and special handling of ``$`` for the rest
of the string.
+ This option also parses C-style escapes. Example:
+
+ - ``\n`` becomes a newline character
+ - ``\\`` expands to ``\``
+
--status-msg=<string>
Print out a custom string during playback instead of the standard status
line. Expands properties. See ``--playing-msg``.
+--stream-capture=<filename>
+ Allows capturing the primary stream (not additional audio tracks or other
+ kind of streams) into the given file. Capturing can also be started and
+ stopped changing the filename with the ``stream-capture`` slave property.
+ Generally this will not produce usable results for anything else than MPEG
+ or raw streams, unless capturing includes the file headers and is not
+ interrupted. Note that, due to cache latencies, captured data may begin and
+ end somewhat delayed compared to what you see displayed.
+
+--stream-dump=<filename>
+ Same as ``--stream-capture``, but don't start playback. Instead, the full
+ file is dumped.
+
--playlist=<filename>
Play files according to a playlist file (ASX, Winamp, SMIL, or
one-file-per-line format).
@@ -1607,12 +1695,6 @@
volume=<0..100>
sound volume for radio device (default 100)
- freq_min=<value> (\*BSD BT848 only)
- minimum allowed frequency (default: 87.50)
-
- freq_max=<value> (\*BSD BT848 only)
- maximum allowed frequency (default: 108.00)
-
channels=<frequency>-<name>,<frequency>-<name>,...
Set channel list. Use _ for spaces in names (or play with quoting ;-).
The channel names will then be written using OSD and the slave
@@ -1657,7 +1739,6 @@
Available options are:
:fps=<value>: rate in frames per second (default: 25.0)
- :sqcif|qcif|cif|4cif|pal|ntsc: set standard image size
:w=<value>: image width in pixels
:h=<value>: image height in pixels
:format=<value>: colorspace (fourcc) in hex or string
@@ -1665,13 +1746,12 @@
:mp-format=<value>: colorspace by internal video format
Use ``--rawvideo=mp-format=help``
for a list of possible formats.
+ :codec: set the video codec (instead of selecting
+ the rawvideo codec)
:size=<value>: frame size in Bytes
*EXAMPLE*:
- - ``mpv foreman.qcif --demuxer=rawvideo --rawvideo=qcif`` Play the
- famous "foreman" sample video.
-
- ``mpv sample-720x576.yuv --demuxer=rawvideo --rawvideo=w=720:h=576``
Play a raw YUV sample.
@@ -1681,24 +1761,64 @@
--referrer=<string>
Specify a referrer path or URL for HTTP requests.
+--reset-on-next-file=<all|option1,option2,...>
+ Normally, mpv will try to keep all settings when playing the next file on
+ the playlist, even if they were changed by the user during playback. (This
+ behavior is the opposite of MPlayer's, which tries to reset all settings
+ when starting next file.)
+
+ This can be changed with this option. It accepts a list of options, and
+ mpv will reset the value of these options on playback start to the initial
+ value. The initial value is either the default value, or as set by the
+ config file or command line.
+
+ In some cases, this might not work as expected. For example, ``--volume``
+ will only be reset the volume if it's explicitly set in the config file
+ or the command line.
+
+ The special name ``all`` resets as many options as possible.
+
+ *EXAMPLE*:
+
+ - ``--reset-on-next-file=fullscreen,speed`` Reset fullscreen and playback
+ speed settings if they were changed during playback.
+ - ``--reset-on-next-file=all`` Try to reset all settings that were changed
+ during playback.
+
--reuse-socket
(udp:// only)
Allows a socket to be reused by other processes as soon as it is closed.
---rootwin
- Play movie in the root window (desktop background). Desktop background
- images may cover the movie window, though. May not work with all video
- output drivers.
-
--saturation=<-100-100>
Adjust the saturation of the video signal (default: 0). You can get
grayscale output with this option. Not supported by all video output
drivers.
+--save-position-on-quit
+ Always save the current playback position on quit. When this file is
+ played again later, the player will seek to the old playback position on
+ start. This affects any form of stopping playback (quitting, going to the
+ next file).
+
+ This behavior is disabled by default, but is always available when quitting
+ the player with Shift+Q.
+
--sb=<n>
Seek to byte position. Useful for playback from CD-ROM images or VOB files
with junk at the beginning. See also ``--start``.
+--screen=<default|0-32>
+ In multi-monitor configurations (i.e. a single desktop that spans across
+ multiple displays) this option tells mpv which screen to display the
+ movie on.
+
+ This option doesn't always work. In these cases, try to use ``--geometry``
+ to position the window explicitly.
+
+ *NOTE (X11)*: this option does not work properly with all window managers.
+
+ See also ``--fs-screen``.
+
--screenshot-format=<type>
Set the image file type used for saving screenshots.
@@ -1857,9 +1977,8 @@
--srate=<Hz>
Select the output sample rate to be used (of course sound cards have
limits on this). If the sample frequency selected is different from that
- of the current media, the resample or lavcresample audio filter will be
- inserted into the audio filter layer to compensate for the difference. The
- type of resampling can be controlled by the ``--af-adv`` option.
+ of the current media, the lavrresample audio filter will be
+ inserted into the audio filter layer to compensate for the difference.
--start=<relative time>
Seek to given time position.
@@ -2068,13 +2187,10 @@
driver=<value>
See ``--tv=driver=help`` for a list of compiled-in TV input drivers.
- available: dummy, v4l, v4l2, bsdbt848 (default: autodetect)
+ available: dummy, v4l2 (default: autodetect)
device=<value>
- Specify TV device (default: ``/dev/video0``). NOTE: For the bsdbt848
- driver you can provide both bktr and tuner device names separating
- them with a comma, tuner after bktr (e.g. ``--tv
- device=/dev/bktr1,/dev/tuner1``).
+ Specify TV device (default: ``/dev/video0``).
input=<value>
Specify input (default: 0 (TV), see console output for available
@@ -2102,8 +2218,7 @@
maximum size of the capture buffer in megabytes (default: dynamical)
norm=<value>
- For bsdbt848 and v4l, PAL, SECAM, NTSC are available. For v4l2, see
- the console output for a list of all available norms, also see the
+ See the console output for a list of all available norms, also see the
normid option below.
normid=<value> (v4l2 only)
@@ -2278,14 +2393,16 @@
Increment verbosity level, one level for each ``-v`` found on the command
line.
---vc=<[-\|+]codec1,[-\|+]codec2,...[,]>
- Specify a priority list of video codecs to be used, according to their
- codec name in ``codecs.conf``. Use a '-' before the codec name to omit it.
- Use a '+' before the codec name to force it, this will likely crash! If
- the list has a trailing ',' mpv will fall back on codecs not contained
- in the list.
+--vd=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>
+ Specify a priority list of video decoders to be used, according to their
+ family and name. See ``--ad`` for further details. Both of these options
+ use the same syntax and semantics, the only difference is that they
+ operate on different codec lists.
- *NOTE*: See ``--vc=help`` for a full list of available codecs.
+ *NOTE*: See ``--vd=help`` for a full list of available decoders.
+
+--version, -V
+ Print version string and exit.
--vf=<filter1[=parameter1:parameter2:...],filter2,...>
Specify a list of video filters to apply to the video stream. See
@@ -2294,20 +2411,9 @@
``--vf-clr`` exist to modify a previously specified list, but you
shouldn't need these for typical use.
---vfm=<driver1,driver2,...>
- Specify a priority list of video codec families to be used, according to
- their names in codecs.conf. Falls back on the default codecs if none of
- the given codec families work.
-
- *NOTE*: See ``--vfm=help`` for a full list of available codec families.
-
--vid=<ID|auto|no>
Select video channel. ``auto`` selects the default, ``no`` disables video.
---vm
- Try to change to a different video mode. Supported by the x11 and xv video
- output drivers.
-
--vo=<driver1[:suboption1[=value]:...],driver2,...[,]>
Specify a priority list of video output drivers to be used. For
interactive use you'd normally specify a single one to use, but in
@@ -2322,21 +2428,12 @@
Set the startup volume. A value of -1 (the default) will not change the
volume. See also ``--softvol``.
---no-vsync
- Tries to disable vsync. (Effective with some video outputs only.)
-
--wid=<ID>
(X11 and win32 only)
- This tells mpv to attach to an existing window.See ``--slave-broken``.
+ This tells mpv to attach to an existing window. The ID is interpreted as
+ "Window" on X11, and as HWND on win32. If a VO is selected that supports
+ this option, a new window will be created and the given window will be set
+ as parent. The window will always be resized to cover the parent window
+ fully, and will add black bars to compensate for the video aspect ratio.
---screen=<all|current|0-32>
- In multi-monitor configurations (i.e. a single desktop that spans across
- multiple displays) this option tells mpv which screen to display the
- movie on. A value of ``all`` means fullscreen across the whole virtual display
- (in this case system provided information is completely ignored), ``current`` means
- fullscreen on the display the window currently is on. The initial position
- set via the ``--geometry`` option is relative to the specified screen.
- Will usually only work with ``--fstype=-fullscreen`` or ``--fstype=none``.
- This option is not suitable to only set the startup screen (because it
- will always display on the given screen in fullscreen mode),
- ``--geometry`` is the best that is available for that purpose currently.
+ See ``--slave-broken``.
diff --git a/DOCS/man/en/vf.rst b/DOCS/man/en/vf.rst
index e993f8ec59..846d3ffac6 100644
--- a/DOCS/man/en/vf.rst
+++ b/DOCS/man/en/vf.rst
@@ -97,7 +97,7 @@ rotate[=<0-7>]
:2: Rotate by 90 degrees counterclockwise.
:3: Rotate by 90 degrees counterclockwise and flip.
-scale[=w:h[:interlaced[:chr_drop[:par[:par2[:presize[:noup[:arnd]]]]]]]]
+scale[=w:h[:interlaced[:chr_drop[:par[:par2[:noup[:arnd]]]]]]]
Scales the image with the software scaler (slow) and performs a YUV<->RGB
colorspace conversion (see also ``--sws``).
@@ -142,16 +142,6 @@ scale[=w:h[:interlaced[:chr_drop[:par[:par2[:presize[:noup[:arnd]]]]]]]]
--sws=9 (lanczos): filter length (1-10)
- <presize>
- Scale to preset sizes.
-
- :qntsc: 352x240 (NTSC quarter screen)
- :qpal: 352x288 (PAL quarter screen)
- :ntsc: 720x480 (standard NTSC)
- :pal: 720x576 (standard PAL)
- :sntsc: 640x480 (square pixel NTSC)
- :spal: 768x576 (square pixel PAL)
-
<noup>
Disallow upscaling past the original dimensions.
@@ -377,6 +367,45 @@ pp[=filter1[:option1[:option2...]]/[-]filter2...]
Horizontal deblocking on luminance only, and switch vertical
deblocking on or off automatically depending on available CPU time.
+lavfi=graph[:sws_flags]
+ Filter video using ffmpeg's libavfilter.
+
+ <graph>
+ The libavfilter graph string. The filter must have a single video input
+ pad and a single video output pad.
+
+ See ``https://ffmpeg.org/ffmpeg-filters.html`` for syntax and available
+ filters.
+
+ *WARNING*: if you want to use the full filter syntax with this option,
+ you have to quote the filter graph in order to prevent mpv's syntax
+ and the filter graph syntax from clashing.
+
+ *EXAMPLE*:
+
+ ``-vf lavfi=[gradfun=20:30,vflip]``
+ gradfun filter with nonsense parameters, followed by a vflip
+ filter. (This demonstrates how libavfilter takes a graph and not
+ just a single filter.) The filter graph string is quoted with
+ ``[`` and ``]``. This requires no additional quoting or escaping
+ with some shells (like bash), while others (like zsh) require
+ additional ``"`` quotes around the option string.
+
+ ``'--vf=lavfi="gradfun=20:30,vflip"'``
+ same as before, but uses quoting that should be safe with all
+ shells. The outer ``'`` quotes make sure that the shell doesn't
+ remove the ``"`` quotes needed by mpv.
+
+ ``'--vf=lavfi=graph="gradfun=radius=30:strength=20,vflip"'``
+ same as before, but uses named parameters for everything.
+
+ <sws_flags>
+ If libavfilter inserts filters for pixel format conversion, this
+ option gives the flags which should be passed to libswscale. This
+ option is numeric and takes a bit-wise combination of ``SWS_`` flags.
+
+ See ``http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libswscale/swscale.h``.
+
noise[=luma[u][t|a][h][p]:chroma[u][t|a][h][p]]
Adds noise.
@@ -611,7 +640,7 @@ phase[=t|b|p|a|u|T|B|A|U][:v]
average squared difference between fields for t, b, and p
alternatives.
-yadif=[mode[:field_dominance]]
+yadif=[mode[:enabled=yes|no]]
Yet another deinterlacing filter
<mode>
@@ -620,11 +649,10 @@ yadif=[mode[:field_dominance]]
:2: Like 0 but skips spatial interlacing check.
:3: Like 1 but skips spatial interlacing check.
- <field_dominance> (DEPRECATED)
- Operates like tfields.
-
- *NOTE*: This option will possibly be removed in a future version. Use
- ``--field-dominance`` instead.
+ <enabled>
+ :yes: Filter is active (default).
+ :no: Filter is not active, but can be deactivated with the ``D`` key
+ (or any other key that toggles the ``deinterlace`` property).
down3dright[=lines]
Reposition and resize stereoscopic images. Extracts both stereo fields and
diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst
index e15436a061..6e39e57793 100644
--- a/DOCS/man/en/vo.rst
+++ b/DOCS/man/en/vo.rst
@@ -171,11 +171,6 @@ direct3d_shaders (Windows only)
Never render YUV video with more than 8 bits per component.
(Using this flag will force software conversion to 8 bit.)
- disable-osd
- Disable OSD rendering for subtitles.
- (Using this flag might force the insertion of the 'ass' video filter,
- which will render the subtitles in software.)
-
disable-texture-align
Normally texture sizes are always aligned to 16. With this option
enabled, the video texture will always have exactly the same size as
@@ -324,12 +319,12 @@ opengl
Enable use of PBOs. This is faster, but can sometimes lead to
sporadic and temporary image corruption.
- dither-depth=<n>
- Positive non-zero values select the target bit depth. Default: 0.
+ dither-depth=<N|no|auto>
+ Set dither target depth to N. Default: no.
- \-1
+ no
Disable any dithering done by mpv.
- 0
+ auto
Automatic selection. If output bit depth can't be detected,
8 bits per component are assumed.
8
@@ -386,6 +381,8 @@ opengl
Win32/WGL
x11
X11/GLX
+ wayland
+ Wayland/EGL
indirect
Do YUV conversion and scaling as separate passes. This will
@@ -401,7 +398,8 @@ opengl
Selects the internal format of textures used for FBOs. The format can
influence performance and quality of the video output. (FBOs are not
always used, and typically only when using extended scalers.)
- fmt can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f
+ fmt can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f,
+ rgba12, rgba16, rgba16f, rgba32f.
Default: rgb.
gamma
@@ -433,15 +431,23 @@ opengl
dimension. Default is 128x256x64.
Sizes must be a power of two, and 256 at most.
+ alpha
+ Try to create a framebuffer with alpha component. This only makes sense
+ if the video contains alpha information (which is extremely rare). May
+ not be supported on all platforms. If alpha framebuffers are
+ unavailable, it silently falls back to a normal framebuffer. Note
+ that when using FBO indirections (such as with ``opengl-hq``), a FBO
+ format with alpha must be specified with the ``fbo-format`` option.
+
opengl-hq
Same as ``opengl``, but with default settings for high quality rendering.
This is equivalent to:
- | --vo=opengl:lscale=lanczos2:dither-depth=0:pbo:fbo-format=rgb16
+ | --vo=opengl:lscale=lanczos2:dither-depth=auto:pbo:fbo-format=rgb16
Note that some cheaper LCDs do dithering that gravely interferes with
- vo_opengl's dithering. Disabling dithering with ``dither-depth=-1`` helps.
+ vo_opengl's dithering. Disabling dithering with ``dither-depth=no`` helps.
Unlike ``opengl``, ``opengl-hq`` makes use of FBOs by default. Sometimes you
can achieve better quality or performance by changing the fbo-format
@@ -468,7 +474,7 @@ opengl-old
(no-)force-pbo
Always uses PBOs to transfer textures even if this involves an extra
copy. Currently this gives a little extra speed with NVidia drivers
- and a lot more speed with ATI drivers. May need ``--no-slices`` and
+ and a lot more speed with ATI drivers. May need
the ati-hack suboption to work correctly.
(no-)scaled-osd
Changes the way the OSD behaves when the size of the window changes
@@ -620,17 +626,6 @@ opengl-old
slice-height=<0-...>
Number of lines copied to texture in one piece (default: 0). 0 for
whole image.
-
- *NOTE*: If YUV colorspace is used (see `yuv` suboption), special rules
- apply: If the decoder uses slice rendering (see ``--no-slices``), this
- setting has no effect, the size of the slices as provided by the
- decoder is used. If the decoder does not use slice rendering, the
- default is 16.
- (no-)osd
- Enable or disable support for OSD rendering via OpenGL (default:
- enabled). This option is for testing; to disable the OSD use
- ``--osd-level=0`` instead.
-
sw
Continue even if a software renderer is detected.
@@ -643,6 +638,8 @@ opengl-old
Win32/WGL
x11
X11/GLX
+ wayland
+ Wayland/EGL
sdl
SDL 2.0+ Render video output driver, depending on system with or without
@@ -652,6 +649,9 @@ sdl
sw
Continue even if a software renderer is detected.
+ switch-mode
+ Instruct SDL to switch the monitor video mode when going fullscreen.
+
null
Produces no video output. Useful for benchmarking.
diff --git a/DOCS/tech-overview.txt b/DOCS/tech-overview.txt
index 0fb20e7e81..9582caaea4 100644
--- a/DOCS/tech-overview.txt
+++ b/DOCS/tech-overview.txt
@@ -203,7 +203,5 @@ core/timeline/:
segments for playing an ordered chapters file is in tl_matroska.c.
etc/:
- The files codecs.conf and input.conf are actually integrated into the
- mplayer binary by the build system. These files define the default settings.
- codecs.conf maps video/audio formats to decoders. input.conf contains
- the default keybindings.
+ The file input.conf is actually integrated into the mpv binary by the
+ build system. It contains the default keybindings.
diff --git a/Makefile b/Makefile
index 6fe5fad4ad..8488a2e5b8 100644
--- a/Makefile
+++ b/Makefile
@@ -45,11 +45,10 @@ SOURCES-$(LIBBS2B) += audio/filter/af_bs2b.c
SOURCES-$(LIBPOSTPROC) += video/filter/vf_pp.c
SOURCES-$(LIBSMBCLIENT) += stream/stream_smb.c
-SOURCES-$(MACOSX_FINDER) += osdep/macosx_finder_args.m
SOURCES-$(MACOSX_BUNDLE) += osdep/macosx_bundle.m
SOURCES-$(COCOA) += video/out/osx_common.m \
video/out/cocoa_common.m \
- osdep/cocoa_events.m
+ osdep/macosx_application.m
SOURCES-$(MNG) += demux/demux_mng.c
SOURCES-$(MPG123) += audio/decode/ad_mpg123.c
SOURCES-$(LIBXMP) += demux/demux_libxmp.c
@@ -74,7 +73,6 @@ SOURCES-$(STREAM_CACHE) += stream/cache2.c
SOURCES-$(TV) += stream/stream_tv.c stream/tv.c \
stream/frequencies.c stream/tvi_dummy.c
-SOURCES-$(TV_BSDBT848) += stream/tvi_bsdbt848.c
SOURCES-$(TV_V4L2) += stream/tvi_v4l2.c stream/audio_in.c
SOURCES-$(VCD) += stream/stream_vcd.c
@@ -83,8 +81,6 @@ SOURCES-$(DUMMY_OSD) += sub/osd_dummy.c
SOURCES-$(LIBASS_OSD) += sub/osd_libass.c
SOURCES-$(ALSA) += audio/out/ao_alsa.c
-SOURCES-$(APPLE_IR) += core/input/appleir.c
-SOURCES-$(APPLE_REMOTE) += core/input/ar.c
SOURCES-$(CACA) += video/out/vo_caca.c
SOURCES-$(SDL) += audio/out/ao_sdl.c
SOURCES-$(SDL2) += video/out/vo_sdl.c
@@ -94,14 +90,19 @@ SOURCES-$(DIRECT3D) += video/out/vo_direct3d.c \
video/out/w32_common.c
SOURCES-$(DSOUND) += audio/out/ao_dsound.c
SOURCES-$(GL) += video/out/gl_common.c video/out/gl_osd.c \
- video/out/vo_opengl.c \
+ video/out/vo_opengl.c video/out/gl_lcms.c \
+ video/out/gl_video.c \
video/out/vo_opengl_old.c \
video/out/pnm_loader.c
SOURCES-$(ENCODING) += video/out/vo_lavc.c audio/out/ao_lavc.c \
core/encode_lavc.c
-SOURCES-$(GL_WIN32) += video/out/w32_common.c
-SOURCES-$(GL_X11) += video/out/x11_common.c
+
+SOURCES-$(GL_WIN32) += video/out/w32_common.c video/out/gl_w32.c
+SOURCES-$(GL_X11) += video/out/x11_common.c video/out/gl_x11.c
+SOURCES-$(GL_COCOA) += video/out/gl_cocoa.c
+SOURCES-$(GL_WAYLAND) += video/out/wayland_common.c \
+ video/out/gl_wayland.c
SOURCES-$(JACK) += audio/out/ao_jack.c
SOURCES-$(JOYSTICK) += core/input/joystick.c
@@ -117,8 +118,17 @@ SOURCES-$(VDPAU) += video/out/vo_vdpau.c
SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c
SOURCES-$(XV) += video/out/vo_xv.c
+SOURCES-$(VF_LAVFI) += video/filter/vf_lavfi.c
+
+ifeq ($(HAVE_AVUTIL_REFCOUNTING),no)
+ SOURCES-yes += video/decode/lavc_dr1.c
+endif
SOURCES = talloc.c \
+ audio/audio.c \
+ audio/chmap.c \
+ audio/chmap_sel.c \
+ audio/fmt-conversion.c \
audio/format.c \
audio/mixer.c \
audio/reorder_ch.c \
@@ -133,20 +143,20 @@ SOURCES = talloc.c \
audio/filter/af_dummy.c \
audio/filter/af_equalizer.c \
audio/filter/af_extrastereo.c \
+ audio/filter/af_force.c \
audio/filter/af_format.c \
audio/filter/af_hrtf.c \
audio/filter/af_karaoke.c \
audio/filter/af_lavcac3enc.c \
- audio/filter/af_lavcresample.c \
+ audio/filter/af_lavrresample.c \
audio/filter/af_pan.c \
- audio/filter/af_resample.c \
audio/filter/af_scaletempo.c \
audio/filter/af_sinesuppress.c \
audio/filter/af_sub.c \
audio/filter/af_surround.c \
audio/filter/af_sweep.c \
audio/filter/af_tools.c \
- audio/filter/af_volnorm.c \
+ audio/filter/af_drc.c \
audio/filter/af_volume.c \
audio/filter/filter.c \
audio/filter/window.c \
@@ -154,10 +164,11 @@ SOURCES = talloc.c \
audio/out/ao_null.c \
audio/out/ao_pcm.c \
core/asxparser.c \
+ core/av_common.c \
core/av_log.c \
core/av_opts.c \
core/bstr.c \
- core/codec-cfg.c \
+ core/codecs.c \
core/command.c \
core/cpudetect.c \
core/defaultopts.c \
@@ -184,6 +195,7 @@ SOURCES = talloc.c \
demux/asfheader.c \
demux/aviheader.c \
demux/aviprint.c \
+ demux/codec_tags.c \
demux/demux.c \
demux/demux_asf.c \
demux/demux_avi.c \
@@ -202,7 +214,6 @@ SOURCES = talloc.c \
demux/ebml.c \
demux/extension.c \
demux/mf.c \
- demux/mp_taglists.c \
demux/video.c \
osdep/numcores.c \
osdep/io.c \
@@ -231,7 +242,6 @@ SOURCES = talloc.c \
video/mp_image_pool.c \
video/sws_utils.c \
video/decode/dec_video.c \
- video/decode/lavc_dr1.c \
video/decode/vd.c \
video/decode/vd_lavc.c \
video/filter/vf.c \
@@ -346,10 +356,6 @@ mpv$(EXESUF): $(OBJECTS)
mpv$(EXESUF):
$(CC) -o $@ $^ $(EXTRALIBS)
-core/codec-cfg.c: core/codecs.conf.h
-core/codecs.conf.h: TOOLS/file2string.pl etc/codecs.conf
- ./$^ >$@
-
core/input/input.c: core/input/input_conf.h
core/input/input_conf.h: TOOLS/file2string.pl etc/input.conf
./$^ >$@
@@ -372,12 +378,12 @@ demux/ebml.c: demux/ebml_defs.c
demux/ebml_defs.c: TOOLS/matroska.pl $(MKVLIB_DEPS)
./$< --generate-definitions > $@
-video/out/vo_opengl.c: video/out/vo_opengl_shaders.h
-video/out/vo_opengl_shaders.h: TOOLS/file2string.pl video/out/vo_opengl_shaders.glsl
+video/out/gl_video.c: video/out/gl_video_shaders.h
+video/out/gl_video_shaders.h: TOOLS/file2string.pl video/out/gl_video_shaders.glsl
./$^ >$@
sub/osd_libass.c: sub/osd_font.h
-sub/osd_font.h: TOOLS/file2string.pl sub/osd_font.pfb
+sub/osd_font.h: TOOLS/file2string.pl sub/osd_font.otf
./$^ >$@
# ./configure must be rerun if it changed
@@ -445,11 +451,10 @@ clean:
-$(RM) $(call ADD_ALL_EXESUFS,mpv)
-$(RM) DOCS/man/en/mpv.1
-$(RM) version.h
- -$(RM) core/codecs.conf.h
-$(RM) core/input/input_conf.h
-$(RM) video/out/vdpau_template.c
-$(RM) demux/ebml_types.h demux/ebml_defs.c
- -$(RM) video/out/vo_opengl_shaders.h
+ -$(RM) video/out/gl_video_shaders.h
-$(RM) sub/osd_font.h
distclean: clean
@@ -464,6 +469,9 @@ tags:
osxbundle:
@TOOLS/osxbundle.py mpv
+osxbundle-skip-deps:
+ @TOOLS/osxbundle.py --skip-deps mpv
+
-include $(DEP_FILES)
.PHONY: all *install* *clean .version
diff --git a/README.rst b/README.md
index d8a962282b..ba3fab5360 100644
--- a/README.rst
+++ b/README.md
@@ -1,24 +1,26 @@
mpv
-###
+===
+
+[![Build Status](https://api.travis-ci.org/mpv-player/mpv.png)](https://travis-ci.org/mpv-player/mpv)
Overview
-========
+--------
**mpv** is a movie player based on MPlayer and mplayer2. It supports a wide
variety of video file formats, audio and video codecs, and subtitle types.
If you are wondering what's different from mplayer2 and MPlayer you can read
-more about the changes_.
+more about the [changes][changes].
Compilation
-===========
+-----------
Compiling with full features requires development files for several
external libraries. Below is a list of some important requirements. For
-more information see the output of ``./configure --help`` for a list of options,
+more information see the output of `./configure --help` for a list of options,
or look at the list of enabled and disabled features printed after running
-``./configure``. If you think you have support for some feature installed
-but configure fails to detect it, the file ``config.log`` may contain
+`./configure`. If you think you have support for some feature installed
+but configure fails to detect it, the file `config.log` may contain
information about the reasons for the failure.
Essential dependencies (incomplete list):
@@ -37,33 +39,33 @@ Essential dependencies (incomplete list):
Most of the above libraries are available in suitable versions on normal
Linux distributions. However FFmpeg is an exception (distro versions may be
too old to work at all or work well). For that reason you may want to use
-the separately available build wrapper (mpv-build_) that first compiles FFmpeg
+the separately available build wrapper ([mpv-build][mpv-build]) that first compiles FFmpeg
libraries and libass, and then compiles the player statically linked against
those.
-If you are running Mac OSX and using homebrew we provide homebrew-mpv_, an up
+If you are running Mac OSX and using homebrew we provide [homebrew-mpv][homebrew-mpv], an up
to date formula that compiles mpv with sensible dependencies and defaults for
OSX.
Bug reports
-===========
+-----------
-Please use the `issues tracker`_ provided by GitHub to send us bug reports or
-feature requests.
+Please use the [issue tracker][issue tracker] provided by GitHub to send us bug
+reports or feature requests.
Contributing
-============
+------------
For small changes you can just send us pull requests through GitHub. For bigger
changes come and talk to us on IRC before you start working on them. It will
make code review easier for both parties later on.
Contacts
-========
+--------
-You can find us on IRC in ``#mpv-player`` on ``irc.freenode.net``
+You can find us on IRC in `#mpv-player` on `irc.freenode.net`
-.. _changes: https://github.com/mpv-player/mpv/blob/master/DOCS/man/en/changes.rst
-.. _mpv-build: https://github.com/mpv-player/mpv-build
-.. _homebrew-mpv: https://github.com/mpv-player/homebrew-mpv
-.. _issues tracker: https://github.com/mpv-player/mpv/issues
+[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/en/changes.rst
+[mpv-build]: https://github.com/mpv-player/mpv-build
+[homebrew-mpv]: https://github.com/mpv-player/homebrew-mpv
+[issue tracker]: https://github.com/mpv-player/mpv/issues
diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh
index b3bc0481ef..0c4dfc5b02 100755
--- a/TOOLS/mpv_identify.sh
+++ b/TOOLS/mpv_identify.sh
@@ -45,6 +45,10 @@ if [ $# -lt 2 ]; then
exit 1
fi
+if [ -z "$MPV" ]; then
+ MPV="mpv"
+fi
+
__midentify__LF="
"
@@ -86,6 +90,8 @@ __midentify__allprops="
fps
width
height
+ dwidth
+ dheight
sub
"
@@ -98,7 +104,7 @@ for __midentify__key in $__midentify__allprops; do
eval unset $__midentify__nextprefix$__midentify__key
done
-__midentify__output=`mpv --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=0 "$@"`
+__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet "$@"`
__midentify__fileindex=0
__midentify__prefix=
while :; do
diff --git a/TOOLS/osxbundle.py b/TOOLS/osxbundle.py
index 8005f8c8c4..e0f240797f 100755
--- a/TOOLS/osxbundle.py
+++ b/TOOLS/osxbundle.py
@@ -4,6 +4,7 @@ import os
import re
import shutil
import sys
+from optparse import OptionParser
def sh(command):
return os.popen(command).read()
@@ -28,27 +29,27 @@ def user_dylib_lst(input_file):
return [lib for lib in dylib_lst(input_file).split("\n") if
is_user_lib(lib, input_file)]
-def bundle_name():
+def bundle_name(binary_name):
return "%s.app" % binary_name
-def target_plist():
- return os.path.join(bundle_name(), 'Contents', 'Info.plist')
+def target_plist(binary_name):
+ return os.path.join(bundle_name(binary_name), 'Contents', 'Info.plist')
-def target_directory():
- return os.path.join(bundle_name(), 'Contents', 'MacOS')
+def target_directory(binary_name):
+ return os.path.join(bundle_name(binary_name), 'Contents', 'MacOS')
-def target_binary():
- return os.path.join(target_directory(), binary_name)
+def target_binary(binary_name):
+ return os.path.join(target_directory(binary_name), binary_name)
-def copy_bundle():
- if os.path.isdir(bundle_name()):
- shutil.rmtree(bundle_name())
+def copy_bundle(binary_name):
+ if os.path.isdir(bundle_name(binary_name)):
+ shutil.rmtree(bundle_name(binary_name))
shutil.copytree(
- os.path.join('TOOLS', 'osxbundle', bundle_name()),
- bundle_name())
+ os.path.join('TOOLS', 'osxbundle', bundle_name(binary_name)),
+ bundle_name(binary_name))
-def copy_binary():
- shutil.copy(binary_name, target_binary())
+def copy_binary(binary_name):
+ shutil.copy(binary_name, target_binary(binary_name))
def run_install_name_tool(target_file, dylib_path, dest_dir, root=True):
new_dylib_path = os.path.join("@executable_path", "lib",
@@ -83,12 +84,40 @@ def fix_dylibs_paths(target_file, dest_dir, root=True):
def apply_plist_template(plist_file, version):
sh("sed -i -e 's/{{VERSION}}/%s/g' %s" % (version, plist_file))
-version = sh("TOOLS/osxbundle/version.sh").strip()
+def bundle_dependencies(binary_name):
+ lib_bundle_directory = os.path.join(target_directory(binary_name), "lib")
+ cp_dylibs(binary_name, lib_bundle_directory)
+ fix_dylibs_paths(target_binary(binary_name), lib_bundle_directory)
-print("Creating Mac OS X application bundle (version: %s)..." % version)
+def main():
+ version = sh("TOOLS/osxbundle/version.sh").strip()
-copy_bundle()
-copy_binary()
-apply_plist_template(target_plist(), version)
-cp_dylibs(sys.argv[1], os.path.join(target_directory(), "lib"))
-fix_dylibs_paths(target_binary(), os.path.join(target_directory(), "lib"))
+ usage = "usage: %prog [options] arg"
+ parser = OptionParser(usage)
+ parser.add_option("-s", "--skip-deps", action="store_false", dest="deps",
+ default=True,
+ help="don't bundle the dependencies")
+
+ (options, args) = parser.parse_args()
+
+ if len(args) != 1:
+ parser.error("incorrect number of arguments")
+ else:
+ binary_name = args[0]
+
+ print("Creating Mac OS X application bundle (version: %s)..." % version)
+ print("> copying bundle skeleton")
+ copy_bundle(binary_name)
+ print("> copying binary")
+ copy_binary(binary_name)
+ print("> generating Info.plist")
+ apply_plist_template(target_plist(binary_name), version)
+
+ if options.deps:
+ print("> bundling dependencies")
+ bundle_dependencies(binary_name)
+
+ print("done.")
+
+if __name__ == "__main__":
+ main()
diff --git a/TOOLS/osxbundle/mpv.app/Contents/Info.plist b/TOOLS/osxbundle/mpv.app/Contents/Info.plist
index 472542fe92..d19c83564e 100644
--- a/TOOLS/osxbundle/mpv.app/Contents/Info.plist
+++ b/TOOLS/osxbundle/mpv.app/Contents/Info.plist
@@ -173,7 +173,7 @@
<key>CFBundleIconFile</key>
<string>icon</string>
<key>CFBundleIdentifier</key>
- <string>org.mpv-player.standalone</string>
+ <string>io.mpv</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
diff --git a/TOOLS/uncrustify.cfg b/TOOLS/uncrustify.cfg
index b5133be203..837d9a1770 100644
--- a/TOOLS/uncrustify.cfg
+++ b/TOOLS/uncrustify.cfg
@@ -1,3 +1,10 @@
+# Usage:
+# uncrustify -l C -c TOOLS/uncrustify.cfg --no-backup --replace file.c
+#
+# Keep in mind that this uncrustify configuration still produces some
+# bad/broken formatting.
+#
+
code_width=80
indent_align_string=false
indent_braces=false
diff --git a/TOOLS/vf_dlopen/Makefile b/TOOLS/vf_dlopen/Makefile
index ed315fe365..c1eb5e0c9f 100644
--- a/TOOLS/vf_dlopen/Makefile
+++ b/TOOLS/vf_dlopen/Makefile
@@ -1,4 +1,25 @@
-FILTERS = showqscale telecine tile rectangle
+#
+# Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+#
+# This file is part of mpv's vf_dlopen examples.
+#
+# mpv's vf_dlopen examples are free software; you can redistribute them and/or
+# modify them under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# mpv's vf_dlopen examples are distributed in the hope that they will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with mpv's vf_dlopen examples; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+#
+
+FILTERS = showqscale telecine tile rectangle framestep
COMMON = filterutils.o
OBJECTS = $(patsubst %,%.o,$(FILTERS)) $(COMMON)
@@ -7,7 +28,7 @@ OUT = $(patsubst %,%.so,$(FILTERS))
CFLAGS ?= -Wall -Wextra -O3 -march=native -mtune=native -ffast-math
-CPPFLAGS += -I../../libmpcodecs
+CPPFLAGS += -I../../video/filter
CFLAGS += -fPIC
LDFLAGS += -shared -fPIC
diff --git a/TOOLS/vf_dlopen/filterutils.c b/TOOLS/vf_dlopen/filterutils.c
index e2f14092de..2bafd93dba 100644
--- a/TOOLS/vf_dlopen/filterutils.c
+++ b/TOOLS/vf_dlopen/filterutils.c
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <assert.h>
#include <string.h>
diff --git a/TOOLS/vf_dlopen/filterutils.h b/TOOLS/vf_dlopen/filterutils.h
index 4b4229d8ea..791adae50d 100644
--- a/TOOLS/vf_dlopen/filterutils.h
+++ b/TOOLS/vf_dlopen/filterutils.h
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
void copy_plane(
unsigned char *dest, unsigned dest_stride,
const unsigned char *src, unsigned src_stride,
diff --git a/TOOLS/vf_dlopen/framestep.c b/TOOLS/vf_dlopen/framestep.c
new file mode 100644
index 0000000000..531d11b018
--- /dev/null
+++ b/TOOLS/vf_dlopen/framestep.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vf_dlopen.h"
+#include "filterutils.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+/*
+ * frame stepping filter
+ *
+ * usage: -vf dlopen=./framestep.so:5
+ *
+ * outputs every 5th frame
+ *
+ * usage: -vf dlopen=./framestep.so:5:3
+ *
+ * outputs every 5th frame, starting with frame index 3 (default: 0)
+ */
+
+typedef struct {
+ int step, pos;
+} framestep_data_t;
+
+static int framestep_put_image(struct vf_dlopen_context *ctx)
+{
+ framestep_data_t *framestep = ctx->priv;
+
+ // stepping
+ if (framestep->pos < 0)
+ return 0;
+ --framestep->pos;
+ if (framestep->pos >= 0)
+ return 0;
+ framestep->pos += framestep->step;
+
+ // copying
+ assert(ctx->inpic.planes == ctx->outpic[0].planes);
+ int np = ctx->inpic.planes;
+ int p;
+ for (p = 0; p < np; ++p) {
+ assert(ctx->inpic.planewidth[p] == ctx->outpic->planewidth[p]);
+ assert(ctx->inpic.planeheight[p] == ctx->outpic->planeheight[p]);
+ copy_plane(
+ ctx->outpic->plane[p],
+ ctx->outpic->planestride[p],
+ ctx->inpic.plane[p],
+ ctx->inpic.planestride[p],
+ MIN(ctx->inpic.planestride[p], ctx->outpic->planestride[p]),
+ ctx->inpic.planeheight[p]
+ );
+ }
+ ctx->outpic->pts = ctx->inpic.pts;
+
+ return 1;
+}
+
+void framestep_uninit(struct vf_dlopen_context *ctx)
+{
+ free(ctx->priv);
+}
+
+int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **argv)
+{
+ VF_DLOPEN_CHECK_VERSION(ctx);
+
+ if (argc != 1 && argc != 2)
+ return -1;
+
+ framestep_data_t *framestep = malloc(sizeof(framestep_data_t));
+ memset(framestep, 0, sizeof(*framestep));
+
+ framestep->step = atoi(argv[0]);
+ framestep->pos = (argc >= 2) ? atoi(argv[1]) : 0;
+
+ ctx->priv = framestep;
+ ctx->put_image = framestep_put_image;
+ ctx->uninit = framestep_uninit;
+
+ return 1;
+}
diff --git a/TOOLS/vf_dlopen/rectangle.c b/TOOLS/vf_dlopen/rectangle.c
index 758ad7701c..1492ec221e 100644
--- a/TOOLS/vf_dlopen/rectangle.c
+++ b/TOOLS/vf_dlopen/rectangle.c
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/TOOLS/vf_dlopen/showqscale.c b/TOOLS/vf_dlopen/showqscale.c
index 9bece60a4f..df1f65d51e 100644
--- a/TOOLS/vf_dlopen/showqscale.c
+++ b/TOOLS/vf_dlopen/showqscale.c
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/TOOLS/vf_dlopen/telecine.c b/TOOLS/vf_dlopen/telecine.c
index 1b3db26a20..5a6a2115bc 100644
--- a/TOOLS/vf_dlopen/telecine.c
+++ b/TOOLS/vf_dlopen/telecine.c
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/TOOLS/vf_dlopen/tile.c b/TOOLS/vf_dlopen/tile.c
index 0e9a14fb62..ad9f72ebdc 100644
--- a/TOOLS/vf_dlopen/tile.c
+++ b/TOOLS/vf_dlopen/tile.c
@@ -1,3 +1,24 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
+ *
+ * This file is part of mpv's vf_dlopen examples.
+ *
+ * mpv's vf_dlopen examples are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * mpv's vf_dlopen examples are distributed in the hope that they will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv's vf_dlopen examples; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/audio/audio.c b/audio/audio.c
new file mode 100644
index 0000000000..c9d5c9231c
--- /dev/null
+++ b/audio/audio.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "core/mp_talloc.h"
+#include "audio.h"
+
+void mp_audio_set_format(struct mp_audio *mpa, int format)
+{
+ mpa->format = format;
+ mpa->bps = af_fmt2bits(format) / 8;
+}
+
+void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels)
+{
+ struct mp_chmap map;
+ mp_chmap_from_channels(&map, num_channels);
+ mp_audio_set_channels(mpa, &map);
+}
+
+// Use old MPlayer/ALSA channel layout.
+void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels)
+{
+ struct mp_chmap map;
+ mp_chmap_from_channels_alsa(&map, num_channels);
+ mp_audio_set_channels(mpa, &map);
+}
+
+void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap)
+{
+ assert(mp_chmap_is_empty(chmap) || mp_chmap_is_valid(chmap));
+ mpa->channels = *chmap;
+ mpa->nch = mpa->channels.num;
+}
+
+void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src)
+{
+ mp_audio_set_format(dst, src->format);
+ mp_audio_set_channels(dst, &src->channels);
+ dst->rate = src->rate;
+}
+
+bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b)
+{
+ return a->format == b->format && a->rate == b->rate &&
+ mp_chmap_equals(&a->channels, &b->channels);
+}
+
+char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
+{
+ char *chstr = mp_chmap_to_str(chmap);
+ char *res = talloc_asprintf(NULL, "%dHz %s %dch %s", srate, chstr,
+ chmap->num, af_fmt2str_short(format));
+ talloc_free(chstr);
+ return res;
+}
+
+char *mp_audio_config_to_str(struct mp_audio *mpa)
+{
+ return mp_audio_fmt_to_str(mpa->rate, &mpa->channels, mpa->format);
+}
diff --git a/audio/audio.h b/audio/audio.h
new file mode 100644
index 0000000000..de35e697c8
--- /dev/null
+++ b/audio/audio.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MP_AUDIO_H
+#define MP_AUDIO_H
+
+#include "format.h"
+#include "chmap.h"
+
+// Audio data chunk
+struct mp_audio {
+ void *audio; // data buffer
+ int len; // buffer length (in bytes)
+ int rate; // sample rate
+ struct mp_chmap channels; // channel layout, use mp_audio_set_*() to set
+ int format; // format (AF_FORMAT_...), use mp_audio_set_format() to set
+ // Redundant fields, for convenience
+ int nch; // number of channels (redundant with chmap)
+ int bps; // bytes per sample (redundant with format)
+};
+
+void mp_audio_set_format(struct mp_audio *mpa, int format);
+void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels);
+void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels);
+void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap);
+void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
+bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
+
+char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format);
+char *mp_audio_config_to_str(struct mp_audio *mpa);
+
+#endif
diff --git a/audio/chmap.c b/audio/chmap.c
new file mode 100644
index 0000000000..254d9b38da
--- /dev/null
+++ b/audio/chmap.c
@@ -0,0 +1,489 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "core/mp_msg.h"
+#include "chmap.h"
+
+// Names taken from libavutil/channel_layout.c (Not accessible by API.)
+// Use of these names is hard-coded in some places (e.g. ao_alsa.c)
+static const char *speaker_names[MP_SPEAKER_ID_COUNT][2] = {
+ [MP_SPEAKER_ID_FL] = {"fl", "front left"},
+ [MP_SPEAKER_ID_FR] = {"fr", "front right"},
+ [MP_SPEAKER_ID_FC] = {"fc", "front center"},
+ [MP_SPEAKER_ID_LFE] = {"lfe", "low frequency"},
+ [MP_SPEAKER_ID_BL] = {"bl", "back left"},
+ [MP_SPEAKER_ID_BR] = {"br", "back right"},
+ [MP_SPEAKER_ID_FLC] = {"flc", "front left-of-center"},
+ [MP_SPEAKER_ID_FRC] = {"frc", "front right-of-center"},
+ [MP_SPEAKER_ID_BC] = {"bc", "back center"},
+ [MP_SPEAKER_ID_SL] = {"sl", "side left"},
+ [MP_SPEAKER_ID_SR] = {"sr", "side right"},
+ [MP_SPEAKER_ID_TC] = {"tc", "top center"},
+ [MP_SPEAKER_ID_TFL] = {"tfl", "top front left"},
+ [MP_SPEAKER_ID_TFC] = {"tfc", "top front center"},
+ [MP_SPEAKER_ID_TFR] = {"tfr", "top front right"},
+ [MP_SPEAKER_ID_TBL] = {"tbl", "top back left"},
+ [MP_SPEAKER_ID_TBC] = {"tbc", "top back center"},
+ [MP_SPEAKER_ID_TBR] = {"tbr", "top back right"},
+ [MP_SPEAKER_ID_DL] = {"dl", "downmix left"},
+ [MP_SPEAKER_ID_DR] = {"dr", "downmix right"},
+ [MP_SPEAKER_ID_WL] = {"wl", "wide left"},
+ [MP_SPEAKER_ID_WR] = {"wr", "wide right"},
+ [MP_SPEAKER_ID_SDL] = {"sdl", "surround direct left"},
+ [MP_SPEAKER_ID_SDR] = {"sdr", "surround direct right"},
+ [MP_SPEAKER_ID_LFE2] = {"lfe2", "low frequency 2"},
+};
+
+// Names taken from libavutil/channel_layout.c (Not accessible by API.)
+// Channel order corresponds to lavc/waveex, except for the alsa entries.
+static const char *std_layout_names[][2] = {
+ {"empty", ""}, // not in lavc
+ {"mono", "fc"},
+ {"stereo", "fl-fr"},
+ {"2.1", "fl-fr-lfe"},
+ {"3.0", "fl-fr-fc"},
+ {"3.0(back)", "fl-fr-bc"},
+ {"4.0", "fl-fr-fc-bc"},
+ {"quad", "fl-fr-bl-br"},
+ {"quad(side)", "fl-fr-sl-sr"},
+ {"3.1", "fl-fr-fc-lfe"},
+ {"5.0", "fl-fr-fc-bl-br"},
+ {"5.0(alsa)", "fl-fr-bl-br-fc"}, // not in lavc
+ {"5.0(side)", "fl-fr-fc-sl-sr"},
+ {"4.1", "fl-fr-fc-lfe-bc"},
+ {"4.1(alsa)", "fl-fr-bl-br-lfe"}, // not in lavc
+ {"5.1", "fl-fr-fc-lfe-bl-br"},
+ {"5.1(alsa)", "fl-fr-bl-br-fc-lfe"}, // not in lavc
+ {"5.1(side)", "fl-fr-fc-lfe-sl-sr"},
+ {"6.0", "fl-fr-fc-bc-sl-sr"},
+ {"6.0(front)", "fl-fr-flc-frc-sl-sr"},
+ {"hexagonal", "fl-fr-fc-bl-br-bc"},
+ {"6.1", "fl-fr-fc-lfe-bc-sl-sr"},
+ {"6.1(back)", "fl-fr-fc-lfe-bl-br-bc"}, // lavc calls this "6.1" too
+ {"6.1(front)", "fl-fr-lfe-flc-frc-sl-sr"},
+ {"7.0", "fl-fr-fc-bl-br-sl-sr"},
+ {"7.0(front)", "fl-fr-fc-flc-frc-sl-sr"},
+ {"7.1", "fl-fr-fc-lfe-bl-br-sl-sr"},
+ {"7.1(alsa)", "fl-fr-bl-br-fc-lfe-sl-sr"}, // not in lavc
+ {"7.1(wide)", "fl-fr-fc-lfe-bl-br-flc-frc"},
+ {"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
+ {"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
+ {"downmix", "dl-dr"},
+ {0}
+};
+
+static const struct mp_chmap default_layouts[MP_NUM_CHANNELS + 1] = {
+ {0}, // empty
+ MP_CHMAP_INIT_MONO, // mono
+ MP_CHMAP2(FL, FR), // stereo
+ MP_CHMAP3(FL, FR, LFE), // 2.1
+ MP_CHMAP4(FL, FR, FC, BC), // 4.0
+ MP_CHMAP5(FL, FR, FC, BL, BR), // 5.0
+ MP_CHMAP6(FL, FR, FC, LFE, BL, BR), // 5.1
+ MP_CHMAP7(FL, FR, FC, LFE, BC, SL, SR), // 6.1
+ MP_CHMAP8(FL, FR, FC, LFE, BL, BR, SL, SR), // 7.1
+};
+
+// The channel order was lavc/waveex, but differs from lavc for 5, 6 and 8
+// channels. 3 and 7 channels were likely undefined (no ALSA support).
+// I'm not sure about the 4 channel case: ALSA uses "quad", while the ffmpeg
+// default layout is "4.0".
+static const char *mplayer_layouts[MP_NUM_CHANNELS + 1] = {
+ [1] = "mono",
+ [2] = "stereo",
+ [4] = "quad",
+ [5] = "5.0(alsa)",
+ [6] = "5.1(alsa)",
+ [8] = "7.1(alsa)",
+};
+
+// Returns true if speakers are mapped uniquely, and there's at least 1 channel.
+bool mp_chmap_is_valid(const struct mp_chmap *src)
+{
+ bool mapped[MP_SPEAKER_ID_COUNT] = {0};
+ for (int n = 0; n < src->num; n++) {
+ int sp = src->speaker[n];
+ if (sp >= MP_SPEAKER_ID_COUNT || mapped[sp])
+ return false;
+ mapped[sp] = true;
+ }
+ return src->num > 0;
+}
+
+bool mp_chmap_is_empty(const struct mp_chmap *src)
+{
+ return src->num == 0;
+}
+
+// Return true if the channel map defines the number of the channels only, and
+// the channels have to meaning associated with them.
+bool mp_chmap_is_unknown(const struct mp_chmap *src)
+{
+ for (int n = 0; n < src->num; n++) {
+ int speaker = src->speaker[n];
+ if (speaker >= MP_SPEAKER_ID_UNKNOWN0 &&
+ speaker <= MP_SPEAKER_ID_UNKNOWN_LAST)
+ return true;
+ }
+ return false;
+}
+
+// Note: empty channel maps compare as equal. Invalid ones can equal too.
+bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b)
+{
+ if (a->num != b->num)
+ return false;
+ for (int n = 0; n < a->num; n++) {
+ if (a->speaker[n] != b->speaker[n])
+ return false;
+ }
+ return true;
+}
+
+// Whether they use the same speakers (even if in different order).
+bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b)
+{
+ struct mp_chmap t1 = *a, t2 = *b;
+ mp_chmap_reorder_norm(&t1);
+ mp_chmap_reorder_norm(&t2);
+ return mp_chmap_equals(&t1, &t2);
+}
+
+bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b)
+{
+ if (mp_chmap_equals(a, b))
+ return true;
+ if (a->num == b->num && (mp_chmap_is_unknown(a) || mp_chmap_is_unknown(b)))
+ return true;
+ return false;
+}
+
+bool mp_chmap_is_stereo(const struct mp_chmap *src)
+{
+ static const struct mp_chmap stereo = MP_CHMAP_INIT_STEREO;
+ return mp_chmap_equals(src, &stereo);
+}
+
+static int comp_uint8(const void *a, const void *b)
+{
+ return *(const uint8_t *)a - *(const uint8_t *)b;
+}
+
+// Reorder channels to normal order, with monotonically increasing speaker IDs.
+// We define this order as the same order used with waveex.
+void mp_chmap_reorder_norm(struct mp_chmap *map)
+{
+ uint8_t *arr = &map->speaker[0];
+ qsort(arr, map->num, 1, comp_uint8);
+}
+
+// Set *dst to a standard layout with the given number of channels.
+// If the number of channels is invalid, an invalid map is set, and
+// mp_chmap_is_valid(dst) will return false.
+void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels)
+{
+ if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
+ *dst = (struct mp_chmap) {0};
+ } else {
+ *dst = default_layouts[num_channels];
+ }
+}
+
+// Try to do what mplayer/mplayer2/mpv did before channel layouts were
+// introduced, i.e. get the old default channel order.
+void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels)
+{
+ if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
+ *dst = (struct mp_chmap) {0};
+ } else {
+ mp_chmap_from_str(dst, bstr0(mplayer_layouts[num_channels]));
+ if (!dst->num)
+ mp_chmap_from_channels(dst, num_channels);
+ }
+}
+
+// Set *dst to an unknown layout for the given numbers of channels.
+// If the number of channels is invalid, an invalid map is set, and
+// mp_chmap_is_valid(dst) will return false.
+void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels)
+{
+ if (num_channels < 0 || num_channels > MP_NUM_CHANNELS) {
+ *dst = (struct mp_chmap) {0};
+ } else {
+ dst->num = num_channels;
+ for (int n = 0; n < dst->num; n++)
+ dst->speaker[n] = MP_SPEAKER_ID_UNKNOWN0 + n;
+ }
+}
+
+// Return channel index of the given speaker, or -1.
+static int mp_chmap_find_speaker(const struct mp_chmap *map, int speaker)
+{
+ for (int n = 0; n < map->num; n++) {
+ if (map->speaker[n] == speaker)
+ return n;
+ }
+ return -1;
+}
+
+static void mp_chmap_remove_speaker(struct mp_chmap *map, int speaker)
+{
+ int index = mp_chmap_find_speaker(map, speaker);
+ if (index >= 0) {
+ for (int n = index; n < map->num - 1; n++)
+ map->speaker[n] = map->speaker[n + 1];
+ map->num--;
+ }
+}
+
+// Some decoders output additional, redundant channels, which are usually
+// useless and will mess up proper audio output channel handling.
+// map: channel map from which the channels should be removed
+// requested: if not NULL, and if it contains any of the "useless" channels,
+// don't remove them (this is for convenience)
+void mp_chmap_remove_useless_channels(struct mp_chmap *map,
+ const struct mp_chmap *requested)
+{
+ if (requested &&
+ mp_chmap_find_speaker(requested, MP_SPEAKER_ID_DL) >= 0)
+ return;
+
+ if (map->num > 2) {
+ mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DL);
+ mp_chmap_remove_speaker(map, MP_SPEAKER_ID_DR);
+ }
+}
+
+// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
+// Warning: this ignores the order of the channels, and will return a channel
+// mask even if the order is different from libavcodec's.
+uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src)
+{
+ // lavc has no concept for unknown layouts yet, so pick a default
+ struct mp_chmap t = *src;
+ if (mp_chmap_is_unknown(&t))
+ mp_chmap_from_channels(&t, t.num);
+ uint64_t mask = 0;
+ for (int n = 0; n < t.num; n++)
+ mask |= 1ULL << t.speaker[n];
+ return mask;
+}
+
+// Return the ffmpeg/libav channel layout as in <libavutil/channel_layout.h>.
+// Returns 0 if the channel order doesn't match lavc's or if it's invalid.
+uint64_t mp_chmap_to_lavc(const struct mp_chmap *src)
+{
+ if (!mp_chmap_is_lavc(src))
+ return 0;
+ return mp_chmap_to_lavc_unchecked(src);
+}
+
+// Set channel map from the ffmpeg/libav channel layout as in
+// <libavutil/channel_layout.h>.
+// If the number of channels exceed MP_NUM_CHANNELS, set dst to empty.
+void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src)
+{
+ dst->num = 0;
+ for (int n = 0; n < 64; n++) {
+ if (src & (1ULL << n)) {
+ if (dst->num >= MP_NUM_CHANNELS) {
+ dst->num = 0;
+ return;
+ }
+ dst->speaker[dst->num] = n;
+ dst->num++;
+ }
+ }
+}
+
+bool mp_chmap_is_lavc(const struct mp_chmap *src)
+{
+ if (!mp_chmap_is_valid(src))
+ return false;
+ if (mp_chmap_is_unknown(src))
+ return true;
+ // lavc's channel layout is a bit mask, and channels are always ordered
+ // from LSB to MSB speaker bits, so speaker IDs have to increase.
+ assert(src->num > 0);
+ for (int n = 1; n < src->num; n++) {
+ if (src->speaker[n - 1] >= src->speaker[n])
+ return false;
+ }
+ for (int n = 0; n < src->num; n++) {
+ if (src->speaker[n] >= 64)
+ return false;
+ }
+ return true;
+}
+
+void mp_chmap_reorder_to_lavc(struct mp_chmap *map)
+{
+ if (!mp_chmap_is_valid(map))
+ return;
+ uint64_t mask = mp_chmap_to_lavc_unchecked(map);
+ mp_chmap_from_lavc(map, mask);
+}
+
+// Get reordering array for from->to reordering. from->to must have the same set
+// of speakers (i.e. same number and speaker IDs, just different order). Then,
+// for each speaker n, dst[n] will be set such that:
+// to->speaker[dst[n]] = from->speaker[n]
+// (dst[n] gives the source channel for destination channel n)
+void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
+ const struct mp_chmap *to)
+{
+ assert(from->num == to->num);
+ if (mp_chmap_is_unknown(from) || mp_chmap_is_unknown(to)) {
+ for (int n = 0; n < from->num; n++)
+ dst[n] = n;
+ return;
+ }
+ // Same set of speakers required
+ assert(mp_chmap_equals_reordered(from, to));
+ for (int n = 0; n < from->num; n++) {
+ int src = from->speaker[n];
+ dst[n] = -1;
+ for (int i = 0; i < to->num; i++) {
+ if (src == to->speaker[i]) {
+ dst[n] = i;
+ break;
+ }
+ }
+ assert(dst[n] != -1);
+ }
+ for (int n = 0; n < from->num; n++)
+ assert(to->speaker[dst[n]] == from->speaker[n]);
+}
+
+// Returns something like "fl-fr-fc". If there's a standard layout in lavc
+// order, return that, e.g. "3.0" instead of "fl-fr-fc".
+// Unassigned but valid speakers get names like "sp28".
+char *mp_chmap_to_str(const struct mp_chmap *src)
+{
+ char *res = talloc_strdup(NULL, "");
+
+ if (mp_chmap_is_unknown(src))
+ return talloc_asprintf_append_buffer(res, "unknown%d", src->num);
+
+ for (int n = 0; n < src->num; n++) {
+ int sp = src->speaker[n];
+ const char *s = sp < MP_SPEAKER_ID_COUNT ? speaker_names[sp][0] : NULL;
+ char buf[10];
+ if (!s) {
+ snprintf(buf, sizeof(buf), "sp%d", sp);
+ s = buf;
+ }
+ res = talloc_asprintf_append_buffer(res, "%s%s", n > 0 ? "-" : "", s);
+ }
+
+ // To standard layout name
+ for (int n = 0; std_layout_names[n][0]; n++) {
+ if (res && strcmp(res, std_layout_names[n][1]) == 0) {
+ talloc_free(res);
+ res = talloc_strdup(NULL, std_layout_names[n][0]);
+ break;
+ }
+ }
+
+ return res;
+}
+
+// If src can be parsed as channel map (as produced by mp_chmap_to_str()),
+// return true and set *dst. Otherwise, return false and don't change *dst.
+// Note: call mp_chmap_is_valid() to test whether the returned map is valid
+// the map could be empty, or contain multiply mapped channels
+bool mp_chmap_from_str(struct mp_chmap *dst, bstr src)
+{
+ // Single number corresponds to mp_chmap_from_channels()
+ if (src.len > 0) {
+ bstr t = src;
+ bool unknown = bstr_eatstart0(&t, "unknown");
+ bstr rest;
+ long long count = bstrtoll(t, &rest, 10);
+ if (rest.len == 0) {
+ struct mp_chmap res;
+ if (unknown) {
+ mp_chmap_set_unknown(&res, count);
+ } else {
+ mp_chmap_from_channels(&res, count);
+ }
+ if (mp_chmap_is_valid(&res)) {
+ *dst = res;
+ return true;
+ }
+ }
+ }
+
+ // From standard layout name
+ for (int n = 0; std_layout_names[n][0]; n++) {
+ if (bstr_equals0(src, std_layout_names[n][0])) {
+ src = bstr0(std_layout_names[n][1]);
+ break;
+ }
+ }
+
+ // Explicit speaker list (separated by "-")
+ struct mp_chmap res = {0};
+ while (src.len) {
+ bstr s;
+ bstr_split_tok(src, "-", &s, &src);
+ int speaker = -1;
+ for (int n = 0; n < MP_SPEAKER_ID_COUNT; n++) {
+ const char *name = speaker_names[n][0];
+ if (name && bstr_equals0(s, name)) {
+ speaker = n;
+ break;
+ }
+ }
+ if (speaker < 0) {
+ if (bstr_eatstart0(&s, "sp")) {
+ long long sp = bstrtoll(s, &s, 0);
+ if (s.len == 0 && sp >= 0 && sp < MP_SPEAKER_ID_COUNT)
+ speaker = sp;
+ }
+ if (speaker < 0)
+ return false;
+ }
+ if (res.num >= MP_NUM_CHANNELS)
+ return false;
+ res.speaker[res.num] = speaker;
+ res.num++;
+ }
+
+ *dst = res;
+ return true;
+}
+
+void mp_chmap_print_help(int msgt, int msgl)
+{
+ mp_msg(msgt, msgl, "Speakers:\n");
+ for (int n = 0; n < MP_SPEAKER_ID_COUNT; n++) {
+ if (speaker_names[n][0])
+ mp_msg(msgt, msgl, " %-16s (%s)\n",
+ speaker_names[n][0], speaker_names[n][1]);
+ }
+ mp_msg(msgt, msgl, "Standard layouts:\n");
+ for (int n = 0; std_layout_names[n][0]; n++) {
+ mp_msg(msgt, msgl, " %-16s (%s)\n",
+ std_layout_names[n][0], std_layout_names[n][1]);
+ }
+ for (int n = 0; n < MP_NUM_CHANNELS; n++)
+ mp_msg(msgt, msgl, " unknown%d\n", n);
+}
diff --git a/audio/chmap.h b/audio/chmap.h
new file mode 100644
index 0000000000..1848c86efd
--- /dev/null
+++ b/audio/chmap.h
@@ -0,0 +1,132 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MP_CHMAP_H
+#define MP_CHMAP_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include "core/bstr.h"
+
+#define MP_NUM_CHANNELS 8
+
+// Speaker a channel can be assigned to.
+// This corresponds to WAVEFORMATEXTENSIBLE channel mask bit indexes.
+// E.g. channel_mask = (1 << MP_SPEAKER_ID_FL) | ...
+enum {
+ // Official WAVEFORMATEXTENSIBLE (shortened names)
+ MP_SPEAKER_ID_FL = 0, // FRONT_LEFT
+ MP_SPEAKER_ID_FR, // FRONT_RIGHT
+ MP_SPEAKER_ID_FC, // FRONT_CENTER
+ MP_SPEAKER_ID_LFE, // LOW_FREQUENCY
+ MP_SPEAKER_ID_BL, // BACK_LEFT
+ MP_SPEAKER_ID_BR, // BACK_RIGHT
+ MP_SPEAKER_ID_FLC, // FRONT_LEFT_OF_CENTER
+ MP_SPEAKER_ID_FRC, // FRONT_RIGHT_OF_CENTER
+ MP_SPEAKER_ID_BC, // BACK_CENTER
+ MP_SPEAKER_ID_SL, // SIDE_LEFT
+ MP_SPEAKER_ID_SR, // SIDE_RIGHT
+ MP_SPEAKER_ID_TC, // TOP_CENTER
+ MP_SPEAKER_ID_TFL, // TOP_FRONT_LEFT
+ MP_SPEAKER_ID_TFC, // TOP_FRONT_CENTER
+ MP_SPEAKER_ID_TFR, // TOP_FRONT_RIGHT
+ MP_SPEAKER_ID_TBL, // TOP_BACK_LEFT
+ MP_SPEAKER_ID_TBC, // TOP_BACK_CENTER
+ MP_SPEAKER_ID_TBR, // TOP_BACK_RIGHT
+ // Inofficial/libav* extensions
+ MP_SPEAKER_ID_DL = 29, // STEREO_LEFT (stereo downmix special speakers)
+ MP_SPEAKER_ID_DR, // STEREO_RIGHT
+ MP_SPEAKER_ID_WL, // WIDE_LEFT
+ MP_SPEAKER_ID_WR, // WIDE_RIGHT
+ MP_SPEAKER_ID_SDL, // SURROUND_DIRECT_LEFT
+ MP_SPEAKER_ID_SDR, // SURROUND_DIRECT_RIGHT
+ MP_SPEAKER_ID_LFE2, // LOW_FREQUENCY_2
+
+ // Special mpv-specific speaker entries reserved for channels which have no
+ // known meaning.
+ MP_SPEAKER_ID_UNKNOWN0 = 64,
+ MP_SPEAKER_ID_UNKNOWN_LAST = MP_SPEAKER_ID_UNKNOWN0 + MP_NUM_CHANNELS - 1,
+
+ // Including the unassigned IDs in between. This is not a valid ID anymore.
+ MP_SPEAKER_ID_COUNT,
+};
+
+struct mp_chmap {
+ uint8_t num; // number of channels
+ // Given a channel n, speaker[n] is the speaker ID driven by that channel.
+ // Entries after speaker[num - 1] are undefined.
+ uint8_t speaker[MP_NUM_CHANNELS];
+};
+
+#define MP_SP(speaker) MP_SPEAKER_ID_ ## speaker
+
+#define MP_CHMAP2(a, b) \
+ {2, {MP_SP(a), MP_SP(b)}}
+#define MP_CHMAP3(a, b, c) \
+ {3, {MP_SP(a), MP_SP(b), MP_SP(c)}}
+#define MP_CHMAP4(a, b, c, d) \
+ {4, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d)}}
+#define MP_CHMAP5(a, b, c, d, e) \
+ {5, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e)}}
+#define MP_CHMAP6(a, b, c, d, e, f) \
+ {6, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f)}}
+#define MP_CHMAP7(a, b, c, d, e, f, g) \
+ {7, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f), MP_SP(g)}}
+#define MP_CHMAP8(a, b, c, d, e, f, g, h) \
+ {8, {MP_SP(a), MP_SP(b), MP_SP(c), MP_SP(d), MP_SP(e), MP_SP(f), MP_SP(g), MP_SP(h)}}
+
+#define MP_CHMAP_INIT_MONO {1, {MP_SPEAKER_ID_FC}}
+#define MP_CHMAP_INIT_STEREO MP_CHMAP2(FL, FR)
+
+bool mp_chmap_is_valid(const struct mp_chmap *src);
+bool mp_chmap_is_empty(const struct mp_chmap *src);
+bool mp_chmap_is_unknown(const struct mp_chmap *src);
+bool mp_chmap_equals(const struct mp_chmap *a, const struct mp_chmap *b);
+bool mp_chmap_equals_reordered(const struct mp_chmap *a, const struct mp_chmap *b);
+bool mp_chmap_is_compatible(const struct mp_chmap *a, const struct mp_chmap *b);
+bool mp_chmap_is_stereo(const struct mp_chmap *src);
+
+void mp_chmap_reorder_norm(struct mp_chmap *map);
+
+void mp_chmap_from_channels(struct mp_chmap *dst, int num_channels);
+void mp_chmap_set_unknown(struct mp_chmap *dst, int num_channels);
+void mp_chmap_from_channels_alsa(struct mp_chmap *dst, int num_channels);
+
+void mp_chmap_remove_useless_channels(struct mp_chmap *map,
+ const struct mp_chmap *requested);
+
+uint64_t mp_chmap_to_lavc(const struct mp_chmap *src);
+uint64_t mp_chmap_to_lavc_unchecked(const struct mp_chmap *src);
+void mp_chmap_from_lavc(struct mp_chmap *dst, uint64_t src);
+
+bool mp_chmap_is_lavc(const struct mp_chmap *src);
+void mp_chmap_reorder_to_lavc(struct mp_chmap *map);
+
+void mp_chmap_get_reorder(int dst[MP_NUM_CHANNELS], const struct mp_chmap *from,
+ const struct mp_chmap *to);
+
+char *mp_chmap_to_str(const struct mp_chmap *src);
+bool mp_chmap_from_str(struct mp_chmap *dst, bstr src);
+void mp_chmap_print_help(int msgt, int msgl);
+
+// Use these to avoid chaos in case lavc's definition should diverge from MS.
+#define mp_chmap_to_waveext mp_chmap_to_lavc
+#define mp_chmap_from_waveext mp_chmap_from_lavc
+#define mp_chmap_is_waveext mp_chmap_is_lavc
+#define mp_chmap_reorder_to_waveext mp_chmap_reorder_to_lavc
+
+#endif
diff --git a/audio/chmap_sel.c b/audio/chmap_sel.c
new file mode 100644
index 0000000000..8e5be5c86e
--- /dev/null
+++ b/audio/chmap_sel.c
@@ -0,0 +1,210 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "chmap_sel.h"
+
+// 5.1 and 5.1(side) are practically the same. It doesn't make much sense to
+// reject either of them.
+static const int replaceable_speakers[][2] = {
+ {MP_SPEAKER_ID_SL, MP_SPEAKER_ID_BL},
+ {MP_SPEAKER_ID_SR, MP_SPEAKER_ID_BR},
+ {-1},
+};
+
+// list[] contains a list of speaker pairs, with each pair indicating how
+// a speaker can be swapped for another speaker. Try to replace speakers from
+// the left of the list with the ones on the right, or the other way around.
+static bool replace_speakers(struct mp_chmap *map, const int list[][2])
+{
+ if (!mp_chmap_is_valid(map))
+ return false;
+ for (int dir = 0; dir < 2; dir++) {
+ int from = dir ? 0 : 1;
+ int to = dir ? 1 : 0;
+ bool replaced = false;
+ struct mp_chmap t = *map;
+ for (int n = 0; n < t.num; n++) {
+ for (int i = 0; list[i][0] != -1; i++) {
+ if (t.speaker[n] == list[i][from]) {
+ t.speaker[n] = list[i][to];
+ replaced = true;
+ break;
+ }
+ }
+ }
+ if (replaced && mp_chmap_is_valid(&t)) {
+ *map = t;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Allow all channel layouts that can be expressed with mp_chmap.
+// (By default, all layouts are rejected.)
+void mp_chmap_sel_add_any(struct mp_chmap_sel *s)
+{
+ s->allow_any = true;
+}
+
+// Allow all waveext formats, and force waveext channel order.
+void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s)
+{
+ s->allow_waveext = true;
+}
+
+void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s)
+{
+ for (int n = 0; n < MP_NUM_CHANNELS; n++) {
+ struct mp_chmap t;
+ mp_chmap_from_channels_alsa(&t, n);
+ if (t.num)
+ mp_chmap_sel_add_map(s, &t);
+ }
+}
+
+#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
+
+// Add a channel map that should be allowed.
+void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map)
+{
+ assert(s->num_chmaps < ARRAY_LEN(s->chmaps));
+ if (mp_chmap_is_valid(map))
+ s->chmaps[s->num_chmaps++] = *map;
+}
+
+// Allow all waveext formats in default order.
+void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s)
+{
+ for (int n = 1; n < MP_NUM_CHANNELS; n++) {
+ struct mp_chmap map;
+ mp_chmap_from_channels(&map, n);
+ mp_chmap_sel_add_map(s, &map);
+ }
+}
+
+// Whitelist a speaker (MP_SPEAKER_ID_...). All layouts that contain whitelisted
+// speakers are allowed.
+void mp_chmap_sel_add_speaker(struct mp_chmap_sel *s, int id)
+{
+ assert(id >= 0 && id < MP_SPEAKER_ID_COUNT);
+ s->speakers[id] = true;
+}
+
+static bool test_speakers(const struct mp_chmap_sel *s, struct mp_chmap *map)
+{
+ for (int n = 0; n < map->num; n++) {
+ if (!s->speakers[map->speaker[n]])
+ return false;
+ }
+ return true;
+}
+
+static bool test_maps(const struct mp_chmap_sel *s, struct mp_chmap *map)
+{
+ for (int n = 0; n < s->num_chmaps; n++) {
+ if (mp_chmap_equals_reordered(&s->chmaps[n], map)) {
+ *map = s->chmaps[n];
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool test_waveext(const struct mp_chmap_sel *s, struct mp_chmap *map)
+{
+ if (s->allow_waveext) {
+ struct mp_chmap t = *map;
+ mp_chmap_reorder_to_waveext(&t);
+ if (mp_chmap_is_waveext(&t)) {
+ *map = t;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool test_layout(const struct mp_chmap_sel *s, struct mp_chmap *map)
+{
+ if (!mp_chmap_is_valid(map))
+ return false;
+
+ return s->allow_any || test_waveext(s, map) || test_speakers(s, map) ||
+ test_maps(s, map);
+}
+
+// Determine which channel map to use given a source channel map, and various
+// parameters restricting possible choices. If the map doesn't match, select
+// a fallback and set it.
+// If no matching layout is found, a reordered layout may be returned.
+// If that is not possible, a fallback for up/downmixing may be returned.
+// If no choice is possible, set *map to empty.
+bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map)
+{
+ if (test_layout(s, map))
+ return true;
+ if (mp_chmap_is_unknown(map)) {
+ struct mp_chmap t = {0};
+ if (mp_chmap_sel_get_def(s, &t, map->num) && test_layout(s, &t)) {
+ *map = t;
+ return true;
+ }
+ }
+ // 5.1 <-> 5.1(side)
+ if (replace_speakers(map, replaceable_speakers) && test_layout(s, map))
+ return true;
+ // Fallback to mono/stereo as last resort
+ if (map->num == 1) {
+ *map = (struct mp_chmap) MP_CHMAP_INIT_MONO;
+ } else if (map->num >= 2) {
+ *map = (struct mp_chmap) MP_CHMAP_INIT_STEREO;
+ }
+ if (test_layout(s, map))
+ return true;
+ *map = (struct mp_chmap) {0};
+ return false;
+}
+
+// Set map to a default layout with num channels. Used for audio APIs that
+// return a channel count as part of format negotiation, but give no
+// information about the channel layout.
+// If the channel count is correct, do nothing and leave *map untouched.
+bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
+ int num)
+{
+ if (map->num != num) {
+ *map = (struct mp_chmap) {0};
+ // Set of speakers or waveext might allow it.
+ struct mp_chmap t;
+ mp_chmap_from_channels(&t, num);
+ mp_chmap_reorder_to_waveext(&t);
+ if (test_layout(s, &t)) {
+ *map = t;
+ } else {
+ for (int n = 0; n < s->num_chmaps; n++) {
+ if (s->chmaps[n].num == num) {
+ *map = s->chmaps[n];
+ break;
+ }
+ }
+ }
+ }
+ return map->num > 0;
+}
diff --git a/audio/chmap_sel.h b/audio/chmap_sel.h
new file mode 100644
index 0000000000..c9d75196a5
--- /dev/null
+++ b/audio/chmap_sel.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MP_CHMAP_SEL_H
+#define MP_CHMAP_SEL_H
+
+#include <stdbool.h>
+
+#include "chmap.h"
+
+struct mp_chmap_sel {
+ // should be considered opaque
+ bool allow_any, allow_waveext;
+ bool speakers[MP_SPEAKER_ID_COUNT];
+ struct mp_chmap chmaps[20];
+ int num_chmaps;
+};
+
+void mp_chmap_sel_add_any(struct mp_chmap_sel *s);
+void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s);
+void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s);
+void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s);
+void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map);
+void mp_chmap_sel_add_speaker(struct mp_chmap_sel *s, int id);
+bool mp_chmap_sel_adjust(const struct mp_chmap_sel *s, struct mp_chmap *map);
+bool mp_chmap_sel_get_def(const struct mp_chmap_sel *s, struct mp_chmap *map,
+ int num);
+
+#endif
diff --git a/audio/decode/ad.c b/audio/decode/ad.c
index 9af7112bf0..846cd146d1 100644
--- a/audio/decode/ad.c
+++ b/audio/decode/ad.c
@@ -32,7 +32,7 @@
/* Missed vorbis, mad, dshow */
extern const ad_functions_t mpcodecs_ad_mpg123;
-extern const ad_functions_t mpcodecs_ad_ffmpeg;
+extern const ad_functions_t mpcodecs_ad_lavc;
extern const ad_functions_t mpcodecs_ad_spdif;
const ad_functions_t * const mpcodecs_ad_drivers[] =
@@ -40,7 +40,7 @@ const ad_functions_t * const mpcodecs_ad_drivers[] =
#ifdef CONFIG_MPG123
&mpcodecs_ad_mpg123,
#endif
- &mpcodecs_ad_ffmpeg,
+ &mpcodecs_ad_lavc,
&mpcodecs_ad_spdif,
NULL
};
diff --git a/audio/decode/ad.h b/audio/decode/ad.h
index 2de0e0641a..ff51ecbe35 100644
--- a/audio/decode/ad.h
+++ b/audio/decode/ad.h
@@ -19,19 +19,22 @@
#ifndef MPLAYER_AD_H
#define MPLAYER_AD_H
-#include "core/mpc_info.h"
+#include "core/codecs.h"
#include "demux/stheader.h"
typedef struct mp_codec_info ad_info_t;
+struct mp_decoder_list;
+
/* interface of video decoder drivers */
typedef struct ad_functions
{
- const ad_info_t *info;
+ const char *name;
+ void (*add_decoders)(struct mp_decoder_list *list);
int (*preinit)(sh_audio_t *sh);
- int (*init)(sh_audio_t *sh);
+ int (*init)(sh_audio_t *sh, const char *decoder);
void (*uninit)(sh_audio_t *sh);
- int (*control)(sh_audio_t *sh,int cmd,void* arg, ...);
+ int (*control)(sh_audio_t *sh, int cmd, void *arg);
int (*decode_audio)(sh_audio_t *sh, unsigned char *buffer, int minlen,
int maxlen);
} ad_functions_t;
@@ -45,10 +48,4 @@ extern const ad_functions_t * const mpcodecs_ad_drivers[];
// fallback if ADCTRL_SKIP not implemented: ds_fill_buffer(sh_audio->ds);
#define ADCTRL_SKIP_FRAME 2 // skip block/frame, called while seeking
-// fallback if ADCTRL_QUERY_FORMAT not implemented: sh_audio->sample_format
-#define ADCTRL_QUERY_FORMAT 3 // test for availabilty of a format
-
-// fallback: use hw mixer in libao
-#define ADCTRL_SET_VOLUME 4 // not used at the moment
-
#endif /* MPLAYER_AD_H */
diff --git a/audio/decode/ad_internal.h b/audio/decode/ad_internal.h
index 1fed350b98..61bf306a5e 100644
--- a/audio/decode/ad_internal.h
+++ b/audio/decode/ad_internal.h
@@ -19,7 +19,7 @@
#ifndef MPLAYER_AD_INTERNAL_H
#define MPLAYER_AD_INTERNAL_H
-#include "core/codec-cfg.h"
+#include "core/codecs.h"
#include "audio/format.h"
#include "stream/stream.h"
@@ -28,14 +28,16 @@
#include "ad.h"
-static int init(sh_audio_t *sh);
+static void add_decoders(struct mp_decoder_list *list);
+static int init(sh_audio_t *sh, const char *decoder);
static int preinit(sh_audio_t *sh);
static void uninit(sh_audio_t *sh);
-static int control(sh_audio_t *sh,int cmd,void* arg, ...);
+static int control(sh_audio_t *sh, int cmd, void *arg);
static int decode_audio(sh_audio_t *sh,unsigned char *buffer,int minlen,int maxlen);
#define LIBAD_EXTERN(x) const ad_functions_t mpcodecs_ad_##x = {\
- &info,\
+ #x, \
+ add_decoders, \
preinit,\
init,\
uninit,\
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 9bcbde33cf..8abc0a6035 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -28,26 +28,20 @@
#include "talloc.h"
#include "config.h"
+#include "core/av_common.h"
+#include "core/codecs.h"
#include "core/mp_msg.h"
#include "core/options.h"
+#include "core/av_opts.h"
#include "ad_internal.h"
#include "audio/reorder_ch.h"
+#include "audio/fmt-conversion.h"
#include "compat/mpbswap.h"
#include "compat/libav.h"
-static const ad_info_t info =
-{
- "libavcodec audio decoders",
- "ffmpeg",
- "",
- "",
- "",
- .print_name = "libavcodec",
-};
-
-LIBAD_EXTERN(ffmpeg)
+LIBAD_EXTERN(lavc)
struct priv {
AVCodecContext *avctx;
@@ -57,6 +51,16 @@ struct priv {
int output_left;
int unitsize;
int previous_data_left; // input demuxer packet data
+ bool force_channel_map;
+};
+
+#define OPT_BASE_STRUCT struct MPOpts
+
+const m_option_t ad_lavc_decode_opts_conf[] = {
+ OPT_FLOATRANGE("ac3drc", ad_lavc_param.ac3drc, 0, 0, 2),
+ OPT_FLAG("downmix", ad_lavc_param.downmix, 0),
+ OPT_STRING("o", ad_lavc_param.avopt, 0),
+ {0}
};
struct pcm_map
@@ -152,32 +156,34 @@ static int preinit(sh_audio_t *sh)
static int setup_format(sh_audio_t *sh_audio,
const AVCodecContext *lavc_context)
{
- int sample_format = sh_audio->sample_format;
- switch (av_get_packed_sample_fmt(lavc_context->sample_fmt)) {
- case AV_SAMPLE_FMT_U8: sample_format = AF_FORMAT_U8; break;
- case AV_SAMPLE_FMT_S16: sample_format = AF_FORMAT_S16_NE; break;
- case AV_SAMPLE_FMT_S32: sample_format = AF_FORMAT_S32_NE; break;
- case AV_SAMPLE_FMT_FLT: sample_format = AF_FORMAT_FLOAT_NE; break;
- default:
- mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "Unsupported sample format\n");
- sample_format = AF_FORMAT_UNKNOWN;
- }
-
+ struct priv *priv = sh_audio->context;
+ int sample_format =
+ af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
bool broken_srate = false;
int samplerate = lavc_context->sample_rate;
int container_samplerate = sh_audio->container_out_samplerate;
if (!container_samplerate && sh_audio->wf)
container_samplerate = sh_audio->wf->nSamplesPerSec;
- if (lavc_context->codec_id == CODEC_ID_AAC
+ if (lavc_context->codec_id == AV_CODEC_ID_AAC
&& samplerate == 2 * container_samplerate)
broken_srate = true;
else if (container_samplerate)
samplerate = container_samplerate;
- if (lavc_context->channels != sh_audio->channels ||
+ struct mp_chmap lavc_chmap;
+ mp_chmap_from_lavc(&lavc_chmap, lavc_context->channel_layout);
+ // No channel layout or layout disagrees with channel count
+ if (lavc_chmap.num != lavc_context->channels)
+ mp_chmap_from_channels(&lavc_chmap, lavc_context->channels);
+ if (priv->force_channel_map) {
+ if (lavc_chmap.num == sh_audio->channels.num)
+ lavc_chmap = sh_audio->channels;
+ }
+
+ if (!mp_chmap_equals(&lavc_chmap, &sh_audio->channels) ||
samplerate != sh_audio->samplerate ||
sample_format != sh_audio->sample_format) {
- sh_audio->channels = lavc_context->channels;
+ sh_audio->channels = lavc_chmap;
sh_audio->samplerate = samplerate;
sh_audio->sample_format = sample_format;
sh_audio->samplesize = af_fmt2bits(sh_audio->sample_format) / 8;
@@ -189,82 +195,81 @@ static int setup_format(sh_audio_t *sh_audio,
return 0;
}
-static int init(sh_audio_t *sh_audio)
+static void set_from_wf(AVCodecContext *avctx, WAVEFORMATEX *wf)
+{
+ avctx->channels = wf->nChannels;
+ avctx->sample_rate = wf->nSamplesPerSec;
+ avctx->bit_rate = wf->nAvgBytesPerSec * 8;
+ avctx->block_align = wf->nBlockAlign;
+ avctx->bits_per_coded_sample = wf->wBitsPerSample;
+
+ if (wf->cbSize > 0) {
+ avctx->extradata = av_mallocz(wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE);
+ avctx->extradata_size = wf->cbSize;
+ memcpy(avctx->extradata, wf + 1, avctx->extradata_size);
+ }
+}
+
+static int init(sh_audio_t *sh_audio, const char *decoder)
{
- struct MPOpts *opts = sh_audio->opts;
+ struct MPOpts *mpopts = sh_audio->opts;
+ struct ad_lavc_param *opts = &mpopts->ad_lavc_param;
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
- const char *dll = sh_audio->codec->dll;
+ struct priv *ctx = talloc_zero(NULL, struct priv);
+ sh_audio->context = ctx;
- if (sh_audio->wf && dll && strcmp(dll, "pcm") == 0) {
- if (sh_audio->format == MKTAG('M', 'P', 'a', 'f')) {
- // demuxer_rawaudio convenience (abuses wFormatTag)
- dll = find_pcm_decoder(af_map, sh_audio->wf->wFormatTag, 0);
- } else {
- dll = find_pcm_decoder(tag_map, sh_audio->format,
+ if (sh_audio->wf && strcmp(decoder, "pcm") == 0) {
+ decoder = find_pcm_decoder(tag_map, sh_audio->format,
sh_audio->wf->wBitsPerSample);
- }
+ } else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) {
+ decoder = find_pcm_decoder(af_map, sh_audio->format, 0);
+ ctx->force_channel_map = true;
}
- if (dll) {
- lavc_codec = avcodec_find_decoder_by_name(dll);
- if (!lavc_codec) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
- "Cannot find codec '%s' in libavcodec...\n", dll);
- return 0;
- }
- } else if (!sh_audio->libav_codec_id) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "No Libav codec ID known. "
- "Generic lavc decoder is not applicable.\n");
+ lavc_codec = avcodec_find_decoder_by_name(decoder);
+ if (!lavc_codec) {
+ mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
+ "Cannot find codec '%s' in libavcodec...\n", decoder);
+ uninit(sh_audio);
return 0;
- } else {
- lavc_codec = avcodec_find_decoder(sh_audio->libav_codec_id);
- if (!lavc_codec) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Libavcodec has no decoder "
- "for this codec\n");
- return 0;
- }
}
- sh_audio->codecname = lavc_codec->long_name;
- if (!sh_audio->codecname)
- sh_audio->codecname = lavc_codec->name;
-
- struct priv *ctx = talloc_zero(NULL, struct priv);
- sh_audio->context = ctx;
lavc_context = avcodec_alloc_context3(lavc_codec);
ctx->avctx = lavc_context;
ctx->avframe = avcodec_alloc_frame();
+ lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
+ lavc_context->codec_id = lavc_codec->id;
+
+ if (opts->downmix) {
+ lavc_context->request_channels = mpopts->audio_output_channels.num;
+ lavc_context->request_channel_layout =
+ mp_chmap_to_lavc(&mpopts->audio_output_channels);
+ }
// Always try to set - option only exists for AC3 at the moment
- av_opt_set_double(lavc_context, "drc_scale", opts->drc_level,
+ av_opt_set_double(lavc_context, "drc_scale", opts->ac3drc,
AV_OPT_SEARCH_CHILDREN);
+
+ if (opts->avopt) {
+ if (parse_avopts(lavc_context, opts->avopt) < 0) {
+ mp_msg(MSGT_DECVIDEO, MSGL_ERR,
+ "ad_lavc: setting AVOptions '%s' failed.\n", opts->avopt);
+ uninit(sh_audio);
+ return 0;
+ }
+ }
+
+ lavc_context->codec_tag = sh_audio->format;
lavc_context->sample_rate = sh_audio->samplerate;
lavc_context->bit_rate = sh_audio->i_bps * 8;
- if (sh_audio->wf) {
- lavc_context->channels = sh_audio->wf->nChannels;
- lavc_context->sample_rate = sh_audio->wf->nSamplesPerSec;
- lavc_context->bit_rate = sh_audio->wf->nAvgBytesPerSec * 8;
- lavc_context->block_align = sh_audio->wf->nBlockAlign;
- lavc_context->bits_per_coded_sample = sh_audio->wf->wBitsPerSample;
- }
- lavc_context->request_channels = opts->audio_output_channels;
- lavc_context->codec_tag = sh_audio->format; //FOURCC
- if (sh_audio->gsh->lavf_codec_tag)
- lavc_context->codec_tag = sh_audio->gsh->lavf_codec_tag;
- lavc_context->codec_type = AVMEDIA_TYPE_AUDIO;
- lavc_context->codec_id = lavc_codec->id; // not sure if required, imho not --A'rpi
+ lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
- /* alloc extra data */
- if (sh_audio->wf && sh_audio->wf->cbSize > 0) {
- lavc_context->extradata = av_mallocz(sh_audio->wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE);
- lavc_context->extradata_size = sh_audio->wf->cbSize;
- memcpy(lavc_context->extradata, sh_audio->wf + 1,
- lavc_context->extradata_size);
- }
+ if (sh_audio->wf)
+ set_from_wf(lavc_context, sh_audio->wf);
- // for QDM2
+ // demux_mkv, demux_mpg
if (sh_audio->codecdata_len && sh_audio->codecdata &&
!lavc_context->extradata) {
lavc_context->extradata = av_malloc(sh_audio->codecdata_len +
@@ -274,6 +279,9 @@ static int init(sh_audio_t *sh_audio)
lavc_context->extradata_size);
}
+ if (sh_audio->gsh->lav_headers)
+ mp_copy_lav_codec_headers(lavc_context, sh_audio->gsh->lav_headers);
+
/* open it */
if (avcodec_open2(lavc_context, lavc_codec, NULL) < 0) {
mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Could not open codec.\n");
@@ -283,16 +291,6 @@ static int init(sh_audio_t *sh_audio)
mp_msg(MSGT_DECAUDIO, MSGL_V, "INFO: libavcodec \"%s\" init OK!\n",
lavc_codec->name);
- if (sh_audio->wf && sh_audio->format == 0x3343414D) {
- // MACE 3:1
- sh_audio->ds->ss_div = 2 * 3; // 1 samples/packet
- sh_audio->ds->ss_mul = 2 * sh_audio->wf->nChannels; // 1 byte*ch/packet
- } else if (sh_audio->wf && sh_audio->format == 0x3643414D) {
- // MACE 6:1
- sh_audio->ds->ss_div = 2 * 6; // 1 samples/packet
- sh_audio->ds->ss_mul = 2 * sh_audio->wf->nChannels; // 1 byte*ch/packet
- }
-
// Decode at least 1 byte: (to get header filled)
for (int tries = 0;;) {
int x = decode_audio(sh_audio, sh_audio->a_buffer, 1,
@@ -303,7 +301,7 @@ static int init(sh_audio_t *sh_audio)
}
if (++tries >= 5) {
mp_msg(MSGT_DECAUDIO, MSGL_ERR,
- "ad_ffmpeg: initial decode failed\n");
+ "ad_lavc: initial decode failed\n");
uninit(sh_audio);
return 0;
}
@@ -313,13 +311,9 @@ static int init(sh_audio_t *sh_audio)
if (sh_audio->wf && sh_audio->wf->nAvgBytesPerSec)
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
- switch (av_get_packed_sample_fmt(lavc_context->sample_fmt)) {
- case AV_SAMPLE_FMT_U8:
- case AV_SAMPLE_FMT_S16:
- case AV_SAMPLE_FMT_S32:
- case AV_SAMPLE_FMT_FLT:
- break;
- default:
+ int af_sample_fmt =
+ af_from_avformat(av_get_packed_sample_fmt(lavc_context->sample_fmt));
+ if (af_sample_fmt == AF_FORMAT_UNKNOWN) {
uninit(sh_audio);
return 0;
}
@@ -328,7 +322,6 @@ static int init(sh_audio_t *sh_audio)
static void uninit(sh_audio_t *sh)
{
- sh->codecname = NULL;
struct priv *ctx = sh->context;
if (!ctx)
return;
@@ -345,7 +338,7 @@ static void uninit(sh_audio_t *sh)
sh->context = NULL;
}
-static int control(sh_audio_t *sh, int cmd, void *arg, ...)
+static int control(sh_audio_t *sh, int cmd, void *arg)
{
struct priv *ctx = sh->context;
switch (cmd) {
@@ -477,13 +470,6 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen,
memcpy(buf, priv->output, size);
priv->output += size;
priv->output_left -= size;
- if (avctx->channels >= 5) {
- int samplesize = av_get_bytes_per_sample(avctx->sample_fmt);
- reorder_channel_nch(buf, AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
- AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
- avctx->channels,
- size / samplesize, samplesize);
- }
if (len < 0)
len = size;
else
@@ -494,3 +480,10 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen,
}
return len;
}
+
+static void add_decoders(struct mp_decoder_list *list)
+{
+ mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO);
+ mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM");
+ mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM");
+}
diff --git a/audio/decode/ad_mpg123.c b/audio/decode/ad_mpg123.c
index a3ce2cdcf6..8699013acf 100644
--- a/audio/decode/ad_mpg123.c
+++ b/audio/decode/ad_mpg123.c
@@ -26,14 +26,6 @@
#include "ad_internal.h"
-static const ad_info_t info = {
- "MPEG 1.0/2.0/2.5 layers I, II, III",
- "mpg123",
- "Thomas Orgis",
- "mpg123.org",
- "High-performance decoder using libmpg123."
-};
-
LIBAD_EXTERN(mpg123)
/* Reducing the ifdeffery to two main variants:
@@ -327,7 +319,7 @@ static int reopen_stream(sh_audio_t *sh)
* Paranoia note: The mpg123_close() on errors is not really necessary,
* But it ensures that we don't accidentally continue decoding with a
* bad state (possibly interpreting the format badly or whatnot). */
-static int init(sh_audio_t *sh)
+static int init(sh_audio_t *sh, const char *decoder)
{
long rate = 0;
int channels = 0;
@@ -366,7 +358,7 @@ static int init(sh_audio_t *sh)
con->mean_count = 0;
#endif
con->vbr = (finfo.vbr != MPG123_CBR);
- sh->channels = channels;
+ mp_chmap_from_channels(&sh->channels, channels);
sh->samplerate = rate;
/* Without external force, mpg123 will always choose signed encoding,
* and non-16-bit only on builds that don't support it.
@@ -463,7 +455,7 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf, int minlen,
return bytes;
}
-static int control(sh_audio_t *sh, int cmd, void *arg, ...)
+static int control(sh_audio_t *sh, int cmd, void *arg)
{
switch (cmd) {
case ADCTRL_RESYNC_STREAM:
@@ -487,3 +479,9 @@ static int control(sh_audio_t *sh, int cmd, void *arg, ...)
}
return CONTROL_UNKNOWN;
}
+
+static void add_decoders(struct mp_decoder_list *list)
+{
+ mp_add_decoder(list, "mpg123", "mp3", "mp3",
+ "High-performance decoder using libmpg123");
+}
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index d8cf731d38..1314110062 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -1,6 +1,8 @@
/*
* This file is part of MPlayer.
*
+ * Copyright (C) 2012 Naoya OYAMA
+ *
* 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
@@ -24,16 +26,10 @@
#include "config.h"
#include "core/mp_msg.h"
+#include "core/av_common.h"
+#include "core/options.h"
#include "ad_internal.h"
-static const ad_info_t info = {
- "libavformat/spdifenc audio pass-through decoder.",
- "spdif",
- "Naoya OYAMA",
- "Naoya OYAMA",
- "For ALL hardware decoders"
-};
-
LIBAD_EXTERN(spdif)
#define FILENAME_SPDIFENC "spdif"
@@ -76,22 +72,21 @@ static int preinit(sh_audio_t *sh)
return 1;
}
-static int init(sh_audio_t *sh)
+static int codecs[] = {
+ AV_CODEC_ID_AAC,
+ AV_CODEC_ID_AC3,
+ AV_CODEC_ID_DTS,
+ AV_CODEC_ID_EAC3,
+ AV_CODEC_ID_MP3,
+ AV_CODEC_ID_TRUEHD,
+ AV_CODEC_ID_NONE
+};
+
+static int init(sh_audio_t *sh, const char *decoder)
{
- int i, x, in_size, srate, bps, *dtshd_rate;
+ int x, in_size, srate, bps, *dtshd_rate;
unsigned char *start;
double pts;
- static const struct {
- const char *name; enum CodecID id;
- } fmt_id_type[] = {
- { "aac" , CODEC_ID_AAC },
- { "ac3" , CODEC_ID_AC3 },
- { "dca" , CODEC_ID_DTS },
- { "eac3", CODEC_ID_EAC3 },
- { "mpa" , CODEC_ID_MP3 },
- { "thd" , CODEC_ID_TRUEHD },
- { NULL , 0 }
- };
AVFormatContext *lavf_ctx = NULL;
AVStream *stream = NULL;
const AVOption *opt = NULL;
@@ -122,12 +117,7 @@ static int init(sh_audio_t *sh)
goto fail;
lavf_ctx->duration = AV_NOPTS_VALUE;
lavf_ctx->start_time = AV_NOPTS_VALUE;
- for (i = 0; fmt_id_type[i].name; i++) {
- if (!strcmp(sh->codec->dll, fmt_id_type[i].name)) {
- lavf_ctx->streams[0]->codec->codec_id = fmt_id_type[i].id;
- break;
- }
- }
+ lavf_ctx->streams[0]->codec->codec_id = mp_codec_to_av_codec_id(decoder);
lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) {
mp_msg(MSGT_DECAUDIO,MSGL_INFO,
@@ -158,59 +148,70 @@ static int init(sh_audio_t *sh)
}
sh->ds->buffer_pos -= in_size;
+ int num_channels = 0;
switch (lavf_ctx->streams[0]->codec->codec_id) {
- case CODEC_ID_AAC:
+ case AV_CODEC_ID_AAC:
spdif_ctx->iec61937_packet_size = 16384;
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = srate;
- sh->channels = 2;
+ num_channels = 2;
sh->i_bps = bps;
break;
- case CODEC_ID_AC3:
+ case AV_CODEC_ID_AC3:
spdif_ctx->iec61937_packet_size = 6144;
sh->sample_format = AF_FORMAT_AC3_LE;
sh->samplerate = srate;
- sh->channels = 2;
+ num_channels = 2;
sh->i_bps = bps;
break;
- case CODEC_ID_DTS: // FORCE USE DTS-HD
- opt = av_opt_find(&lavf_ctx->oformat->priv_class,
- "dtshd_rate", NULL, 0, 0);
- if (!opt)
- goto fail;
- dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) +
- opt->offset);
- *dtshd_rate = 192000*4;
- spdif_ctx->iec61937_packet_size = 32768;
- sh->sample_format = AF_FORMAT_IEC61937_LE;
- sh->samplerate = 192000; // DTS core require 48000
- sh->channels = 2*4;
- sh->i_bps = bps;
+ case AV_CODEC_ID_DTS:
+ if(sh->opts->dtshd) {
+ opt = av_opt_find(&lavf_ctx->oformat->priv_class,
+ "dtshd_rate", NULL, 0, 0);
+ if (!opt)
+ goto fail;
+ dtshd_rate = (int*)(((uint8_t*)lavf_ctx->priv_data) +
+ opt->offset);
+ *dtshd_rate = 192000*4;
+ spdif_ctx->iec61937_packet_size = 32768;
+ sh->sample_format = AF_FORMAT_IEC61937_LE;
+ sh->samplerate = 192000; // DTS core require 48000
+ num_channels = 2*4;
+ sh->i_bps = bps;
+ } else {
+ spdif_ctx->iec61937_packet_size = 32768;
+ sh->sample_format = AF_FORMAT_AC3_LE;
+ sh->samplerate = srate;
+ num_channels = 2;
+ sh->i_bps = bps;
+ }
break;
- case CODEC_ID_EAC3:
+ case AV_CODEC_ID_EAC3:
spdif_ctx->iec61937_packet_size = 24576;
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = 192000;
- sh->channels = 2;
+ num_channels = 2;
sh->i_bps = bps;
break;
- case CODEC_ID_MP3:
+ case AV_CODEC_ID_MP3:
spdif_ctx->iec61937_packet_size = 4608;
sh->sample_format = AF_FORMAT_MPEG2;
sh->samplerate = srate;
- sh->channels = 2;
+ num_channels = 2;
sh->i_bps = bps;
break;
- case CODEC_ID_TRUEHD:
+ case AV_CODEC_ID_TRUEHD:
spdif_ctx->iec61937_packet_size = 61440;
sh->sample_format = AF_FORMAT_IEC61937_LE;
sh->samplerate = 192000;
- sh->channels = 8;
+ num_channels = 8;
sh->i_bps = bps;
break;
default:
break;
}
+ if (num_channels)
+ mp_chmap_from_channels(&sh->channels, num_channels);
return 1;
@@ -272,7 +273,7 @@ static int decode_audio(sh_audio_t *sh, unsigned char *buf,
return spdif_ctx->out_buffer_len;
}
-static int control(sh_audio_t *sh, int cmd, void* arg, ...)
+static int control(sh_audio_t *sh, int cmd, void *arg)
{
unsigned char *start;
double pts;
@@ -306,3 +307,14 @@ static void uninit(sh_audio_t *sh)
av_freep(&lavf_ctx);
av_freep(&spdif_ctx);
}
+
+static void add_decoders(struct mp_decoder_list *list)
+{
+ for (int n = 0; codecs[n] != AV_CODEC_ID_NONE; n++) {
+ const char *format = mp_codec_from_av_codec_id(codecs[n]);
+ if (format) {
+ mp_add_decoder(list, "spdif", format, format,
+ "libavformat/spdifenc audio pass-through decoder");
+ }
+ }
+}
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 90967fdea0..dc461b81e3 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -21,14 +21,16 @@
#include <unistd.h>
#include <assert.h>
+#include "demux/codec_tags.h"
+
#include "config.h"
+#include "core/codecs.h"
#include "core/mp_msg.h"
#include "core/bstr.h"
#include "stream/stream.h"
#include "demux/demux.h"
-#include "core/codec-cfg.h"
#include "demux/stheader.h"
#include "dec_audio.h"
@@ -39,276 +41,199 @@
int fakemono = 0;
-struct af_cfg af_cfg = { 1, NULL }; // Configuration for audio filters
-
-void afm_help(void)
-{
- int i;
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Available (compiled-in) audio codec families/drivers:\n");
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_DRIVERS\n");
- mp_msg(MSGT_DECAUDIO, MSGL_INFO, " afm: info: (comment)\n");
- for (i = 0; mpcodecs_ad_drivers[i] != NULL; i++)
- if (mpcodecs_ad_drivers[i]->info->comment
- && mpcodecs_ad_drivers[i]->info->comment[0])
- mp_msg(MSGT_DECAUDIO, MSGL_INFO, "%9s %s (%s)\n",
- mpcodecs_ad_drivers[i]->info->short_name,
- mpcodecs_ad_drivers[i]->info->name,
- mpcodecs_ad_drivers[i]->info->comment);
- else
- mp_msg(MSGT_DECAUDIO, MSGL_INFO, "%9s %s\n",
- mpcodecs_ad_drivers[i]->info->short_name,
- mpcodecs_ad_drivers[i]->info->name);
-}
+struct af_cfg af_cfg = {0}; // Configuration for audio filters
-static int init_audio_codec(sh_audio_t *sh_audio)
+static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder)
{
assert(!sh_audio->initialized);
resync_audio_stream(sh_audio);
- sh_audio->samplesize = 2;
- sh_audio->sample_format = AF_FORMAT_S16_NE;
- if ((af_cfg.force & AF_INIT_FORMAT_MASK) == AF_INIT_FLOAT) {
- int fmt = AF_FORMAT_FLOAT_NE;
- if (sh_audio->ad_driver->control(sh_audio, ADCTRL_QUERY_FORMAT,
- &fmt) == CONTROL_TRUE) {
- sh_audio->sample_format = fmt;
- sh_audio->samplesize = 4;
- }
- }
+ sh_audio->samplesize = 4;
+ sh_audio->sample_format = AF_FORMAT_FLOAT_NE;
sh_audio->audio_out_minsize = 8192; // default, preinit() may change it
if (!sh_audio->ad_driver->preinit(sh_audio)) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "ADecoder preinit failed :(\n");
- return 0;
+ mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder preinit failed.\n");
+ return 0;
}
/* allocate audio in buffer: */
if (sh_audio->audio_in_minsize > 0) {
- sh_audio->a_in_buffer_size = sh_audio->audio_in_minsize;
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "dec_audio: Allocating %d bytes for input buffer.\n",
- sh_audio->a_in_buffer_size);
- sh_audio->a_in_buffer = av_mallocz(sh_audio->a_in_buffer_size);
+ sh_audio->a_in_buffer_size = sh_audio->audio_in_minsize;
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V,
+ "dec_audio: Allocating %d bytes for input buffer.\n",
+ sh_audio->a_in_buffer_size);
+ sh_audio->a_in_buffer = av_mallocz(sh_audio->a_in_buffer_size);
}
const int base_size = 65536;
// At least 64 KiB plus rounding up to next decodable unit size
sh_audio->a_buffer_size = base_size + sh_audio->audio_out_minsize;
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "dec_audio: Allocating %d + %d = %d bytes for output buffer.\n",
- sh_audio->audio_out_minsize, base_size, sh_audio->a_buffer_size);
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V,
+ "dec_audio: Allocating %d + %d = %d bytes for output buffer.\n",
+ sh_audio->audio_out_minsize, base_size,
+ sh_audio->a_buffer_size);
sh_audio->a_buffer = av_mallocz(sh_audio->a_buffer_size);
if (!sh_audio->a_buffer)
abort();
sh_audio->a_buffer_len = 0;
- if (!sh_audio->ad_driver->init(sh_audio)) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "ADecoder init failed :(\n");
- uninit_audio(sh_audio); // free buffers
- return 0;
+ if (!sh_audio->ad_driver->init(sh_audio, decoder)) {
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n");
+ uninit_audio(sh_audio); // free buffers
+ return 0;
}
sh_audio->initialized = 1;
- if (!sh_audio->channels || !sh_audio->samplerate) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify "
+ if (mp_chmap_is_empty(&sh_audio->channels) || !sh_audio->samplerate) {
+ mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify "
"audio format!\n");
- uninit_audio(sh_audio); // free buffers
- return 0;
+ uninit_audio(sh_audio); // free buffers
+ return 0;
}
if (!sh_audio->o_bps)
- sh_audio->o_bps = sh_audio->channels * sh_audio->samplerate
- * sh_audio->samplesize;
+ sh_audio->o_bps = sh_audio->channels.num * sh_audio->samplerate
+ * sh_audio->samplesize;
return 1;
}
-static int init_audio(sh_audio_t *sh_audio, char *codecname, char *afm,
- int status, stringset_t *selected)
+struct mp_decoder_list *mp_audio_decoder_list(void)
{
- int force = 0;
- if (codecname && codecname[0] == '+') {
- codecname = &codecname[1];
- force = 1;
- }
- sh_audio->codec = NULL;
- while (1) {
- const ad_functions_t *mpadec;
- sh_audio->ad_driver = 0;
- if (!(sh_audio->codec = find_audio_codec(sh_audio->format,
- NULL,
- sh_audio->codec, force)))
- break;
- // ok we found one codec
- if (stringset_test(selected, sh_audio->codec->name))
- continue; // already tried & failed
- if (codecname && strcmp(sh_audio->codec->name, codecname))
- continue; // -ac
- if (afm && strcmp(sh_audio->codec->drv, afm))
- continue; // afm doesn't match
- if (!force && sh_audio->codec->status < status)
- continue; // too unstable
- stringset_add(selected, sh_audio->codec->name); // tagging it
- // ok, it matches all rules, let's find the driver!
- int i;
- for (i = 0; mpcodecs_ad_drivers[i] != NULL; i++)
- if (!strcmp(mpcodecs_ad_drivers[i]->info->short_name,
- sh_audio->codec->drv))
- break;
- mpadec = mpcodecs_ad_drivers[i];
- if (!mpadec) { // driver not available (==compiled in)
- mp_tmsg(MSGT_DECAUDIO, MSGL_ERR,
- "Requested audio codec family [%s] (afm=%s) not available.\nEnable it at compilation.\n",
- sh_audio->codec->name, sh_audio->codec->drv);
- continue;
- }
- // it's available, let's try to init!
- // init()
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder: [%s] %s\n",
- mpadec->info->short_name, mpadec->info->name);
- sh_audio->ad_driver = mpadec;
- if (!init_audio_codec(sh_audio)) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for "
- "codecs.conf entry \"%s\".\n", sh_audio->codec->name);
- continue; // try next...
- }
- // Yeah! We got it!
- return 1;
+ struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
+ for (int i = 0; mpcodecs_ad_drivers[i] != NULL; i++)
+ mpcodecs_ad_drivers[i]->add_decoders(list);
+ return list;
+}
+
+static struct mp_decoder_list *mp_select_audio_decoders(const char *codec,
+ char *selection)
+{
+ struct mp_decoder_list *list = mp_audio_decoder_list();
+ struct mp_decoder_list *new = mp_select_decoders(list, codec, selection);
+ talloc_free(list);
+ return new;
+}
+
+static const struct ad_functions *find_driver(const char *name)
+{
+ for (int i = 0; mpcodecs_ad_drivers[i] != NULL; i++) {
+ if (strcmp(mpcodecs_ad_drivers[i]->name, name) == 0)
+ return mpcodecs_ad_drivers[i];
}
- return 0;
+ return NULL;
}
-int init_best_audio_codec(sh_audio_t *sh_audio, char **audio_codec_list,
- char **audio_fm_list)
+int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders)
{
- stringset_t selected;
- char *ac_l_default[2] = { "", (char *) NULL };
- // hack:
- if (!audio_codec_list)
- audio_codec_list = ac_l_default;
- // Go through the codec.conf and find the best codec...
- sh_audio->initialized = 0;
- stringset_init(&selected);
- while (!sh_audio->initialized && *audio_codec_list) {
- char *audio_codec = *(audio_codec_list++);
- if (audio_codec[0]) {
- if (audio_codec[0] == '-') {
- // disable this codec:
- stringset_add(&selected, audio_codec + 1);
- } else {
- // forced codec by name:
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Forced audio codec: %s\n",
- audio_codec);
- init_audio(sh_audio, audio_codec, NULL, -1, &selected);
- }
- } else {
- int status;
- // try in stability order: UNTESTED, WORKING, BUGGY.
- // never try CRASHING.
- if (audio_fm_list) {
- char **fmlist = audio_fm_list;
- // try first the preferred codec families:
- while (!sh_audio->initialized && *fmlist) {
- char *audio_fm = *(fmlist++);
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Trying to force audio codec driver family %s...\n",
- audio_fm);
- for (status = CODECS_STATUS__MAX;
- status >= CODECS_STATUS__MIN; --status)
- if (init_audio(sh_audio, NULL, audio_fm, status, &selected))
- break;
- }
- }
- if (!sh_audio->initialized)
- for (status = CODECS_STATUS__MAX; status >= CODECS_STATUS__MIN;
- --status)
- if (init_audio(sh_audio, NULL, NULL, status, &selected))
- break;
- }
+ assert(!sh_audio->initialized);
+
+ struct mp_decoder_entry *decoder = NULL;
+ struct mp_decoder_list *list =
+ mp_select_audio_decoders(sh_audio->gsh->codec, audio_decoders);
+
+ mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list);
+
+ for (int n = 0; n < list->num_entries; n++) {
+ struct mp_decoder_entry *sel = &list->entries[n];
+ const struct ad_functions *driver = find_driver(sel->family);
+ if (!driver)
+ continue;
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n",
+ sel->family, sel->decoder);
+ sh_audio->ad_driver = driver;
+ if (init_audio_codec(sh_audio, sel->decoder)) {
+ decoder = sel;
+ break;
+ }
+ sh_audio->ad_driver = NULL;
+ mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for "
+ "%s:%s\n", sel->family, sel->decoder);
}
- stringset_free(&selected);
- if (!sh_audio->initialized) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Cannot find codec for audio format 0x%X.\n",
- sh_audio->format);
- return 0; // failed
+ if (sh_audio->initialized) {
+ sh_audio->gsh->decoder_desc =
+ talloc_asprintf(NULL, "%s [%s:%s]", decoder->desc, decoder->family,
+ decoder->decoder);
+ mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n",
+ sh_audio->gsh->decoder_desc);
+ mp_msg(MSGT_DECAUDIO, MSGL_V,
+ "AUDIO: %d Hz, %d ch, %s, %3.1f kbit/%3.2f%% (ratio: %d->%d)\n",
+ sh_audio->samplerate, sh_audio->channels.num,
+ af_fmt2str_short(sh_audio->sample_format),
+ sh_audio->i_bps * 8 * 0.001,
+ ((float) sh_audio->i_bps / sh_audio->o_bps) * 100.0,
+ sh_audio->i_bps, sh_audio->o_bps);
+ mp_msg(MSGT_IDENTIFY, MSGL_INFO,
+ "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
+ sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels.num);
+ } else {
+ mp_msg(MSGT_DECAUDIO, MSGL_ERR,
+ "Failed to initialize an audio decoder for codec '%s'.\n",
+ sh_audio->gsh->codec ? sh_audio->gsh->codec : "<unknown>");
}
- mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s [%s]\n",
- sh_audio->codecname ? sh_audio->codecname : sh_audio->codec->info,
- sh_audio->ad_driver->info->print_name ?
- sh_audio->ad_driver->info->print_name :
- sh_audio->ad_driver->info->short_name);
- mp_tmsg(MSGT_DECAUDIO, MSGL_V,
- "Audio codecs.conf entry: %s (%s) afm: %s\n",
- sh_audio->codec->name, sh_audio->codec->info, sh_audio->codec->drv);
- mp_msg(MSGT_DECAUDIO, MSGL_V,
- "AUDIO: %d Hz, %d ch, %s, %3.1f kbit/%3.2f%% (ratio: %d->%d)\n",
- sh_audio->samplerate, sh_audio->channels,
- af_fmt2str_short(sh_audio->sample_format),
- sh_audio->i_bps * 8 * 0.001,
- ((float) sh_audio->i_bps / sh_audio->o_bps) * 100.0,
- sh_audio->i_bps, sh_audio->o_bps);
- mp_msg(MSGT_IDENTIFY, MSGL_INFO,
- "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
- sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels);
-
- return 1; // success
+ talloc_free(list);
+ return sh_audio->initialized;
}
void uninit_audio(sh_audio_t *sh_audio)
{
if (sh_audio->afilter) {
- mp_msg(MSGT_DECAUDIO, MSGL_V, "Uninit audio filters...\n");
- af_uninit(sh_audio->afilter);
- free(sh_audio->afilter);
- sh_audio->afilter = NULL;
+ mp_msg(MSGT_DECAUDIO, MSGL_V, "Uninit audio filters...\n");
+ af_uninit(sh_audio->afilter);
+ af_destroy(sh_audio->afilter);
+ sh_audio->afilter = NULL;
}
if (sh_audio->initialized) {
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Uninit audio: %s\n",
- sh_audio->codec->drv);
- sh_audio->ad_driver->uninit(sh_audio);
- sh_audio->initialized = 0;
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Uninit audio.\n");
+ sh_audio->ad_driver->uninit(sh_audio);
+ sh_audio->initialized = 0;
}
+ talloc_free(sh_audio->gsh->decoder_desc);
+ sh_audio->gsh->decoder_desc = NULL;
av_freep(&sh_audio->a_buffer);
av_freep(&sh_audio->a_in_buffer);
}
int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
- int *out_samplerate, int *out_channels, int *out_format)
+ int *out_samplerate, struct mp_chmap *out_channels,
+ int *out_format)
{
struct af_stream *afs = sh_audio->afilter;
- if (!afs) {
- afs = calloc(1, sizeof(struct af_stream));
- afs->opts = sh_audio->opts;
- }
+ if (!afs)
+ afs = af_new(sh_audio->opts);
// input format: same as codec's output format:
- afs->input.rate = in_samplerate;
- afs->input.nch = sh_audio->channels;
- afs->input.format = sh_audio->sample_format;
- af_fix_parameters(&(afs->input));
+ afs->input.rate = in_samplerate;
+ mp_audio_set_channels(&afs->input, &sh_audio->channels);
+ mp_audio_set_format(&afs->input, sh_audio->sample_format);
// output format: same as ao driver's input format (if missing, fallback to input)
- afs->output.rate = *out_samplerate;
- afs->output.nch = *out_channels;
- afs->output.format = *out_format;
- af_fix_parameters(&(afs->output));
+ afs->output.rate = *out_samplerate;
+ mp_audio_set_channels(&afs->output, out_channels);
+ mp_audio_set_format(&afs->output, *out_format);
// filter config:
memcpy(&afs->cfg, &af_cfg, sizeof(struct af_cfg));
- mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Building audio filter chain for %dHz/%dch/%s -> %dHz/%dch/%s...\n",
- afs->input.rate, afs->input.nch,
- af_fmt2str_short(afs->input.format), afs->output.rate,
- afs->output.nch, af_fmt2str_short(afs->output.format));
+ char *s_from = mp_audio_config_to_str(&afs->input);
+ char *s_to = mp_audio_config_to_str(&afs->output);
+ mp_tmsg(MSGT_DECAUDIO, MSGL_V,
+ "Building audio filter chain for %s -> %s...\n", s_from, s_to);
+ talloc_free(s_from);
+ talloc_free(s_to);
// let's autoprobe it!
if (0 != af_init(afs)) {
- sh_audio->afilter = NULL;
- free(afs);
- return 0; // failed :(
+ sh_audio->afilter = NULL;
+ af_destroy(afs);
+ return 0; // failed :(
}
*out_samplerate = afs->output.rate;
- *out_channels = afs->output.nch;
+ *out_channels = afs->output.channels;
*out_format = afs->output.format;
// ok!
@@ -321,51 +246,51 @@ static void set_min_out_buffer_size(struct bstr *outbuf, int len)
size_t oldlen = talloc_get_size(outbuf->start);
if (oldlen < len) {
assert(outbuf->start); // talloc context should be already set
- mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size "
- "from %zd to %d\n", oldlen, len);
+ mp_msg(MSGT_DECAUDIO, MSGL_V, "Increasing filtered audio buffer size "
+ "from %zd to %d\n", oldlen, len);
outbuf->start = talloc_realloc_size(NULL, outbuf->start, len);
}
}
static int filter_n_bytes(sh_audio_t *sh, struct bstr *outbuf, int len)
{
- assert(len-1 + sh->audio_out_minsize <= sh->a_buffer_size);
+ assert(len - 1 + sh->audio_out_minsize <= sh->a_buffer_size);
int error = 0;
// Decode more bytes if needed
int old_samplerate = sh->samplerate;
- int old_channels = sh->channels;
+ struct mp_chmap old_channels = sh->channels;
int old_sample_format = sh->sample_format;
while (sh->a_buffer_len < len) {
- unsigned char *buf = sh->a_buffer + sh->a_buffer_len;
- int minlen = len - sh->a_buffer_len;
- int maxlen = sh->a_buffer_size - sh->a_buffer_len;
- int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen);
- int format_change = sh->samplerate != old_samplerate
- || sh->channels != old_channels
+ unsigned char *buf = sh->a_buffer + sh->a_buffer_len;
+ int minlen = len - sh->a_buffer_len;
+ int maxlen = sh->a_buffer_size - sh->a_buffer_len;
+ int ret = sh->ad_driver->decode_audio(sh, buf, minlen, maxlen);
+ int format_change = sh->samplerate != old_samplerate
+ || !mp_chmap_equals(&sh->channels, &old_channels)
|| sh->sample_format != old_sample_format;
- if (ret <= 0 || format_change) {
- error = format_change ? -2 : -1;
+ if (ret <= 0 || format_change) {
+ error = format_change ? -2 : -1;
// samples from format-changing call get discarded too
- len = sh->a_buffer_len;
- break;
- }
- sh->a_buffer_len += ret;
+ len = sh->a_buffer_len;
+ break;
+ }
+ sh->a_buffer_len += ret;
}
// Filter
struct mp_audio filter_input = {
- .audio = sh->a_buffer,
- .len = len,
- .rate = sh->samplerate,
- .nch = sh->channels,
- .format = sh->sample_format
+ .audio = sh->a_buffer,
+ .len = len,
+ .rate = sh->samplerate,
};
- af_fix_parameters(&filter_input);
+ mp_audio_set_format(&filter_input, sh->sample_format);
+ mp_audio_set_channels(&filter_input, &sh->channels);
+
struct mp_audio *filter_output = af_play(sh->afilter, &filter_input);
if (!filter_output)
- return -1;
+ return -1;
set_min_out_buffer_size(outbuf, outbuf->len + filter_output->len);
memcpy(outbuf->start + outbuf->len, filter_output->audio,
filter_output->len);
@@ -390,7 +315,7 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen)
// Indicates that a filter seems to be buffering large amounts of data
int huge_filter_buffer = 0;
// Decoded audio must be cut at boundaries of this many bytes
- int unitsize = sh_audio->channels * sh_audio->samplesize * 16;
+ int unitsize = sh_audio->channels.num * sh_audio->samplesize * 16;
/* Filter output size will be about filter_multiplier times input size.
* If some filter buffers audio in big blocks this might only hold
@@ -407,29 +332,29 @@ int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen)
return -1;
max_decode_len -= max_decode_len % unitsize;
- while (minlen >=0 && outbuf->len < minlen) {
- int declen = (minlen - outbuf->len) / filter_multiplier
- + (unitsize << 5); // some extra for possible filter buffering
- if (huge_filter_buffer)
- /* Some filter must be doing significant buffering if the estimated
- * input length didn't produce enough output from filters.
- * Feed the filters 2k bytes at a time until we have enough output.
- * Very small amounts could make filtering inefficient while large
- * amounts can make MPlayer demux the file unnecessarily far ahead
- * to get audio data and buffer video frames in memory while doing
- * so. However the performance impact of either is probably not too
- * significant as long as the value is not completely insane. */
- declen = 2000;
- declen -= declen % unitsize;
- if (declen > max_decode_len)
- declen = max_decode_len;
- else
- /* if this iteration does not fill buffer, we must have lots
- * of buffering in filters */
- huge_filter_buffer = 1;
- int res = filter_n_bytes(sh_audio, outbuf, declen);
- if (res < 0)
- return res;
+ while (minlen >= 0 && outbuf->len < minlen) {
+ // + some extra for possible filter buffering
+ int declen = (minlen - outbuf->len) / filter_multiplier + (unitsize << 5);
+ if (huge_filter_buffer)
+ /* Some filter must be doing significant buffering if the estimated
+ * input length didn't produce enough output from filters.
+ * Feed the filters 2k bytes at a time until we have enough output.
+ * Very small amounts could make filtering inefficient while large
+ * amounts can make MPlayer demux the file unnecessarily far ahead
+ * to get audio data and buffer video frames in memory while doing
+ * so. However the performance impact of either is probably not too
+ * significant as long as the value is not completely insane. */
+ declen = 2000;
+ declen -= declen % unitsize;
+ if (declen > max_decode_len)
+ declen = max_decode_len;
+ else
+ /* if this iteration does not fill buffer, we must have lots
+ * of buffering in filters */
+ huge_filter_buffer = 1;
+ int res = filter_n_bytes(sh_audio, outbuf, declen);
+ if (res < 0)
+ return res;
}
return 0;
}
@@ -445,20 +370,20 @@ void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte)
void resync_audio_stream(sh_audio_t *sh_audio)
{
- sh_audio->a_in_buffer_len = 0; // clear audio input buffer
+ sh_audio->a_in_buffer_len = 0; // clear audio input buffer
sh_audio->pts = MP_NOPTS_VALUE;
if (!sh_audio->initialized)
- return;
+ return;
sh_audio->ad_driver->control(sh_audio, ADCTRL_RESYNC_STREAM, NULL);
}
void skip_audio_frame(sh_audio_t *sh_audio)
{
if (!sh_audio->initialized)
- return;
- if (sh_audio->ad_driver->control(sh_audio, ADCTRL_SKIP_FRAME, NULL) ==
- CONTROL_TRUE)
- return;
+ return;
+ if (sh_audio->ad_driver->control(sh_audio, ADCTRL_SKIP_FRAME, NULL)
+ == CONTROL_TRUE)
+ return;
// default skip code:
- ds_fill_buffer(sh_audio->ds); // skip block
+ ds_fill_buffer(sh_audio->ds); // skip block
}
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 986b85f22a..b46f4282fb 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -19,13 +19,14 @@
#ifndef MPLAYER_DEC_AUDIO_H
#define MPLAYER_DEC_AUDIO_H
+#include "audio/chmap.h"
#include "demux/stheader.h"
struct bstr;
+struct mp_decoder_list;
-// dec_audio.c:
-void afm_help(void);
-int init_best_audio_codec(sh_audio_t *sh_audio, char** audio_codec_list, char** audio_fm_list);
+struct mp_decoder_list *mp_audio_decoder_list(void);
+int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders);
int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen);
void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte);
void resync_audio_stream(sh_audio_t *sh_audio);
@@ -33,6 +34,7 @@ void skip_audio_frame(sh_audio_t *sh_audio);
void uninit_audio(sh_audio_t *sh_audio);
int init_audio_filters(sh_audio_t *sh_audio, int in_samplerate,
- int *out_samplerate, int *out_channels, int *out_format);
+ int *out_samplerate, struct mp_chmap *out_channels,
+ int *out_format);
#endif /* MPLAYER_DEC_AUDIO_H */
diff --git a/audio/filter/af.c b/audio/filter/af.c
index 8afedbcfe5..137e7cc407 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
#include "af.h"
@@ -28,17 +29,17 @@ extern struct af_info af_info_dummy;
extern struct af_info af_info_delay;
extern struct af_info af_info_channels;
extern struct af_info af_info_format;
-extern struct af_info af_info_resample;
+extern struct af_info af_info_force;
extern struct af_info af_info_volume;
extern struct af_info af_info_equalizer;
extern struct af_info af_info_pan;
extern struct af_info af_info_surround;
extern struct af_info af_info_sub;
extern struct af_info af_info_export;
-extern struct af_info af_info_volnorm;
+extern struct af_info af_info_drc;
extern struct af_info af_info_extrastereo;
extern struct af_info af_info_lavcac3enc;
-extern struct af_info af_info_lavcresample;
+extern struct af_info af_info_lavrresample;
extern struct af_info af_info_sweep;
extern struct af_info af_info_hrtf;
extern struct af_info af_info_ladspa;
@@ -48,233 +49,389 @@ extern struct af_info af_info_karaoke;
extern struct af_info af_info_scaletempo;
extern struct af_info af_info_bs2b;
-static struct af_info* filter_list[]={
- &af_info_dummy,
- &af_info_delay,
- &af_info_channels,
- &af_info_format,
- &af_info_resample,
- &af_info_volume,
- &af_info_equalizer,
- &af_info_pan,
- &af_info_surround,
- &af_info_sub,
+static struct af_info* filter_list[] = {
+ &af_info_dummy,
+ &af_info_delay,
+ &af_info_channels,
+ &af_info_force,
+ &af_info_volume,
+ &af_info_equalizer,
+ &af_info_pan,
+ &af_info_surround,
+ &af_info_sub,
#ifdef HAVE_SYS_MMAN_H
- &af_info_export,
+ &af_info_export,
#endif
- &af_info_volnorm,
- &af_info_extrastereo,
- &af_info_lavcac3enc,
- &af_info_lavcresample,
- &af_info_sweep,
- &af_info_hrtf,
+ &af_info_drc,
+ &af_info_extrastereo,
+ &af_info_lavcac3enc,
+ &af_info_lavrresample,
+ &af_info_sweep,
+ &af_info_hrtf,
#ifdef CONFIG_LADSPA
- &af_info_ladspa,
+ &af_info_ladspa,
#endif
- &af_info_center,
- &af_info_sinesuppress,
- &af_info_karaoke,
- &af_info_scaletempo,
+ &af_info_center,
+ &af_info_sinesuppress,
+ &af_info_karaoke,
+ &af_info_scaletempo,
#ifdef CONFIG_LIBBS2B
- &af_info_bs2b,
+ &af_info_bs2b,
#endif
- NULL
+ // Must come last, because it's the fallback format conversion filter
+ &af_info_format,
+ NULL
};
-// CPU speed
-int* af_cpu_speed = NULL;
+static bool af_config_equals(struct mp_audio *a, struct mp_audio *b)
+{
+ return a->format == b->format
+ && mp_chmap_equals(&a->channels, &b->channels)
+ && a->rate == b->rate;
+}
+
+static void af_copy_unset_fields(struct mp_audio *dst, struct mp_audio *src)
+{
+ if (dst->format == AF_FORMAT_UNKNOWN)
+ mp_audio_set_format(dst, src->format);
+ if (dst->nch == 0)
+ mp_audio_set_channels(dst, &src->channels);
+ if (dst->rate == 0)
+ dst->rate = src->rate;
+}
+
+static int input_control(struct af_instance* af, int cmd, void* arg)
+{
+ switch (cmd) {
+ case AF_CONTROL_REINIT:
+ assert(arg == &((struct af_stream *)af->setup)->input);
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+static int output_control(struct af_instance* af, int cmd, void* arg)
+{
+ struct af_stream *s = af->setup;
+ struct mp_audio *output = &s->output;
+ struct mp_audio *filter_output = &s->filter_output;
+
+ switch (cmd) {
+ case AF_CONTROL_REINIT: {
+ struct mp_audio *in = arg;
+ struct mp_audio orig_in = *in;
+
+ *filter_output = *output;
+ af_copy_unset_fields(filter_output, in);
+ *in = *filter_output;
+ return af_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+static struct mp_audio *dummy_play(struct af_instance* af, struct mp_audio* data)
+{
+ return data;
+}
/* Find a filter in the static list of filters using it's name. This
function is used internally */
-static struct af_info* af_find(char*name)
+static struct af_info *af_find(char *name)
{
- int i=0;
- while(filter_list[i]){
- if(!strcmp(filter_list[i]->name,name))
- return filter_list[i];
- i++;
- }
- mp_msg(MSGT_AFILTER, MSGL_ERR, "Couldn't find audio filter '%s'\n",name);
- return NULL;
+ int i = 0;
+ while (filter_list[i]) {
+ if (!strcmp(filter_list[i]->name, name))
+ return filter_list[i];
+ i++;
+ }
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "Couldn't find audio filter '%s'\n", name);
+ return NULL;
}
/* Find filter in the dynamic filter list using it's name This
function is used for finding already initialized filters */
-struct af_instance* af_get(struct af_stream* s, char* name)
-{
- struct af_instance* af=s->first;
- // Find the filter
- while(af != NULL){
- if(!strcmp(af->info->name,name))
- return af;
- af=af->next;
- }
- return NULL;
-}
-
-/*/ Function for creating a new filter of type name. The name may
- contain the commandline parameters for the filter */
-static struct af_instance* af_create(struct af_stream* s, const char* name_with_cmd)
-{
- char* name = strdup(name_with_cmd);
- char* cmdline = name;
-
- // Allocate space for the new filter and reset all pointers
- struct af_instance* new=malloc(sizeof(struct af_instance));
- if (!name || !new) {
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Could not allocate memory\n");
- goto err_out;
- }
- memset(new,0,sizeof(struct af_instance));
-
- // Check for commandline parameters
- char *skip = strstr(cmdline, "=");
- if (skip) {
- *skip = '\0'; // for name
- cmdline = skip + 1;
- } else {
- cmdline = NULL;
- }
-
- // Find filter from name
- if(NULL == (new->info=af_find(name)))
- goto err_out;
-
- /* Make sure that the filter is not already in the list if it is
- non-reentrant */
- if(new->info->flags & AF_FLAGS_NOT_REENTRANT){
- if(af_get(s,name)){
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one instance of"
- " the filter '%s' in each stream\n",name);
- goto err_out;
+struct af_instance *af_get(struct af_stream *s, char *name)
+{
+ struct af_instance *af = s->first;
+ // Find the filter
+ while (af != NULL) {
+ if (!strcmp(af->info->name, name))
+ return af;
+ af = af->next;
}
- }
+ return NULL;
+}
- mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n",name);
+/* Function for creating a new filter of type name.The name may
+contain the commandline parameters for the filter */
+static struct af_instance *af_create(struct af_stream *s,
+ const char *name_with_cmd)
+{
+ char *name = strdup(name_with_cmd);
+ char *cmdline = name;
- // Initialize the new filter
- if(AF_OK == new->info->open(new) &&
- AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg)){
- if(cmdline){
- if(AF_ERROR>=new->control(new,AF_CONTROL_COMMAND_LINE,cmdline))
+ // Allocate space for the new filter and reset all pointers
+ struct af_instance *new = malloc(sizeof(struct af_instance));
+ if (!name || !new) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Could not allocate memory\n");
goto err_out;
}
- free(name);
- return new;
- }
+ memset(new, 0, sizeof(struct af_instance));
+
+ // Check for commandline parameters
+ char *skip = strstr(cmdline, "=");
+ if (skip) {
+ *skip = '\0'; // for name
+ cmdline = skip + 1;
+ } else {
+ cmdline = NULL;
+ }
+
+ // Find filter from name
+ if (NULL == (new->info = af_find(name)))
+ goto err_out;
+
+ /* Make sure that the filter is not already in the list if it is
+ non-reentrant */
+ if (new->info->flags & AF_FLAGS_NOT_REENTRANT) {
+ if (af_get(s, name)) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] There can only be one "
+ "instance of the filter '%s' in each stream\n", name);
+ goto err_out;
+ }
+ }
+
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Adding filter %s \n", name);
+
+ // Initialize the new filter
+ if (AF_OK == new->info->open(new)) {
+ if (cmdline) {
+ if (AF_ERROR >= new->control(new, AF_CONTROL_COMMAND_LINE, cmdline))
+ goto err_out;
+ }
+ free(name);
+ return new;
+ }
err_out:
- free(new);
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Couldn't create or open audio filter '%s'\n",
- name);
- free(name);
- return NULL;
+ free(new);
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[libaf] Couldn't create or open audio filter '%s'\n", name);
+ free(name);
+ return NULL;
}
/* Create and insert a new filter of type name before the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
-static struct af_instance* af_prepend(struct af_stream* s, struct af_instance* af, const char* name)
+static struct af_instance *af_prepend(struct af_stream *s,
+ struct af_instance *af,
+ const char *name)
{
- // Create the new filter and make sure it is OK
- struct af_instance* new=af_create(s,name);
- if(!new)
- return NULL;
- // Update pointers
- new->next=af;
- if(af){
- new->prev=af->prev;
- af->prev=new;
- }
- else
- s->last=new;
- if(new->prev)
- new->prev->next=new;
- else
- s->first=new;
- return new;
+ if (!af)
+ af = s->last;
+ if (af == s->first)
+ af = s->first->next;
+ // Create the new filter and make sure it is OK
+ struct af_instance *new = af_create(s, name);
+ if (!new)
+ return NULL;
+ // Update pointers
+ new->next = af;
+ new->prev = af->prev;
+ af->prev = new;
+ new->prev->next = new;
+ return new;
}
/* Create and insert a new filter of type name after the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
-static struct af_instance* af_append(struct af_stream* s, struct af_instance* af, const char* name)
+static struct af_instance *af_append(struct af_stream *s,
+ struct af_instance *af,
+ const char *name)
{
- // Create the new filter and make sure it is OK
- struct af_instance* new=af_create(s,name);
- if(!new)
- return NULL;
- // Update pointers
- new->prev=af;
- if(af){
- new->next=af->next;
- af->next=new;
- }
- else
- s->first=new;
- if(new->next)
- new->next->prev=new;
- else
- s->last=new;
- return new;
+ if (!af)
+ af = s->first;
+ if (af == s->last)
+ af = s->last->prev;
+ // Create the new filter and make sure it is OK
+ struct af_instance *new = af_create(s, name);
+ if (!new)
+ return NULL;
+ // Update pointers
+ new->prev = af;
+ new->next = af->next;
+ af->next = new;
+ new->next->prev = new;
+ return new;
}
// Uninit and remove the filter "af"
-void af_remove(struct af_stream* s, struct af_instance* af)
+void af_remove(struct af_stream *s, struct af_instance *af)
{
- if(!af) return;
+ if (!af)
+ return;
+
+ if (af == s->first || af == s->last)
+ return;
- // Print friendly message
- mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Removing filter %s \n",af->info->name);
+ // Print friendly message
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Removing filter %s \n",
+ af->info->name);
- // Notify filter before changing anything
- af->control(af,AF_CONTROL_PRE_DESTROY,0);
+ // Notify filter before changing anything
+ af->control(af, AF_CONTROL_PRE_DESTROY, 0);
- // Detach pointers
- if(af->prev)
- af->prev->next=af->next;
- else
- s->first=af->next;
- if(af->next)
- af->next->prev=af->prev;
- else
- s->last=af->prev;
+ // Detach pointers
+ af->prev->next = af->next;
+ af->next->prev = af->prev;
- // Uninitialize af and free memory
- af->uninit(af);
- free(af);
+ af->uninit(af);
+ free(af);
}
-static void print_fmt(struct mp_audio *d)
+static void remove_auto_inserted_filters(struct af_stream *s)
{
- if (d) {
- mp_msg(MSGT_AFILTER, MSGL_V, "%dHz/%dch/%s", d->rate, d->nch,
- af_fmt2str_short(d->format));
- } else {
- mp_msg(MSGT_AFILTER, MSGL_V, "(?)");
+repeat:
+ for (struct af_instance *af = s->first; af; af = af->next) {
+ if (af->auto_inserted) {
+ af_remove(s, af);
+ goto repeat;
+ }
}
}
-static void af_print_filter_chain(struct af_stream* s)
+static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
+ int msg_level)
{
- mp_msg(MSGT_AFILTER, MSGL_V, "Audio filter chain:\n");
-
- mp_msg(MSGT_AFILTER, MSGL_V, " [in] ");
- print_fmt(&s->input);
- mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+ mp_msg(MSGT_AFILTER, msg_level, "Audio filter chain:\n");
struct af_instance *af = s->first;
while (af) {
- mp_msg(MSGT_AFILTER, MSGL_V, " [%s] ", af->info->name);
- print_fmt(af->data);
- mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+ mp_msg(MSGT_AFILTER, msg_level, " [%s] ", af->info->name);
+ if (af->data) {
+ char *info = mp_audio_config_to_str(af->data);
+ mp_msg(MSGT_AFILTER, msg_level, "%s", info);
+ talloc_free(info);
+ }
+ if (af == at)
+ mp_msg(MSGT_AFILTER, msg_level, " <-");
+ mp_msg(MSGT_AFILTER, msg_level, "\n");
af = af->next;
}
- mp_msg(MSGT_AFILTER, MSGL_V, " [out] ");
- print_fmt(&s->output);
- mp_msg(MSGT_AFILTER, MSGL_V, "\n");
+ mp_msg(MSGT_AFILTER, msg_level, " [ao] ");
+ char *info = mp_audio_config_to_str(&s->output);
+ mp_msg(MSGT_AFILTER, msg_level, "%s\n", info);
+ talloc_free(info);
+}
+
+static int af_count_filters(struct af_stream *s)
+{
+ int count = 0;
+ for (struct af_instance *af = s->first; af; af = af->next)
+ count++;
+ return count;
+}
+
+static const char *af_find_conversion_filter(int srcfmt, int dstfmt)
+{
+ for (int n = 0; filter_list[n]; n++) {
+ struct af_info *af = filter_list[n];
+ if (af->test_conversion && af->test_conversion(srcfmt, dstfmt))
+ return af->name;
+ }
+ return NULL;
+}
+
+static bool af_is_conversion_filter(struct af_instance *af)
+{
+ return af && af->info->test_conversion != NULL;
+}
+
+// in is what af can take as input - insert a conversion filter if the actual
+// input format doesn't match what af expects.
+// Returns:
+// AF_OK: must call af_reinit() or equivalent, format matches
+// AF_FALSE: nothing was changed, format matches
+// else: error
+static int af_fix_format_conversion(struct af_stream *s,
+ struct af_instance **p_af,
+ struct mp_audio in)
+{
+ int rv;
+ struct af_instance *af = *p_af;
+ struct af_instance *prev = af->prev;
+ struct mp_audio actual = *prev->data;
+ if (actual.format == in.format)
+ return AF_FALSE;
+ if (prev->control(prev, AF_CONTROL_FORMAT_FMT, &in.format) == AF_OK) {
+ *p_af = prev;
+ return AF_OK;
+ }
+ const char *filter = af_find_conversion_filter(actual.format, in.format);
+ if (!filter)
+ return AF_ERROR;
+ struct af_instance *new = af_prepend(s, af, filter);
+ if (new == NULL)
+ return AF_ERROR;
+ new->auto_inserted = true;
+ if (AF_OK != (rv = new->control(new, AF_CONTROL_FORMAT_FMT, &in.format)))
+ return rv;
+ *p_af = new;
+ return AF_OK;
+}
+
+// same as af_fix_format_conversion - only wrt. channels
+static int af_fix_channels(struct af_stream *s, struct af_instance **p_af,
+ struct mp_audio in)
+{
+ int rv;
+ struct af_instance *af = *p_af;
+ struct af_instance *prev = af->prev;
+ struct mp_audio actual = *prev->data;
+ if (mp_chmap_equals(&actual.channels, &in.channels))
+ return AF_FALSE;
+ if (prev->control(prev, AF_CONTROL_CHANNELS, &in.channels) == AF_OK) {
+ *p_af = prev;
+ return AF_OK;
+ }
+ const char *filter = "lavrresample";
+ struct af_instance *new = af_prepend(s, af, filter);
+ if (new == NULL)
+ return AF_ERROR;
+ new->auto_inserted = true;
+ if (AF_OK != (rv = new->control(new, AF_CONTROL_CHANNELS, &in.channels)))
+ return rv;
+ *p_af = new;
+ return AF_OK;
+}
+
+static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
+ struct mp_audio in)
+{
+ int rv;
+ struct af_instance *af = *p_af;
+ struct af_instance *prev = af->prev;
+ struct mp_audio actual = *prev->data;
+ if (actual.rate == in.rate)
+ return AF_FALSE;
+ if (prev->control(prev, AF_CONTROL_RESAMPLE_RATE, &in.rate) == AF_OK) {
+ *p_af = prev;
+ return AF_OK;
+ }
+ const char *filter = "lavrresample";
+ struct af_instance *new = af_prepend(s, af, filter);
+ if (new == NULL)
+ return AF_ERROR;
+ new->auto_inserted = true;
+ if (AF_OK != (rv = new->control(new, AF_CONTROL_RESAMPLE_RATE, &in.rate)))
+ return rv;
+ *p_af = new;
+ return AF_OK;
}
// Warning:
@@ -282,186 +439,128 @@ static void af_print_filter_chain(struct af_stream* s)
// state (for example, format filters that were tentatively inserted stay
// inserted).
// In that case, you should always rebuild the filter chain, or abort.
-int af_reinit(struct af_stream* s, struct af_instance* af)
-{
- do{
- struct mp_audio in; // Format of the input to current filter
- int rv=0; // Return value
-
- // Check if there are any filters left in the list
- if(NULL == af){
- if(!(af=af_append(s,s->first,"dummy")))
- return AF_UNKNOWN;
- else
- return AF_ERROR;
+// Also, note that for complete reinit, fixup_output_format() may have to be
+// called after this function.
+int af_reinit(struct af_stream *s)
+{
+ // Start with the second filter, as the first filter is the special input
+ // filter which needs no initialization.
+ struct af_instance *af = s->first->next;
+ int max_retry = af_count_filters(s) * 4; // up to 4 retries per filter
+ int retry = 0;
+ while (af) {
+ if (retry >= max_retry)
+ goto negotiate_error;
+
+ // Check if this is the first filter
+ struct mp_audio in = *af->prev->data;
+ // Reset just in case...
+ in.audio = NULL;
+ in.len = 0;
+
+ int rv = af->control(af, AF_CONTROL_REINIT, &in);
+ switch (rv) {
+ case AF_OK:
+ af = af->next;
+ break;
+ case AF_FALSE: { // Configuration filter is needed
+ if (af_fix_channels(s, &af, in) == AF_OK) {
+ retry++;
+ continue;
+ }
+ if (af_fix_rate(s, &af, in) == AF_OK) {
+ retry++;
+ continue;
+ }
+ // Do this last, to prevent "format->lavrresample" being added to
+ // the filter chain when output formats not supported by
+ // af_lavrresample are in use.
+ if (af_fix_format_conversion(s, &af, in) == AF_OK) {
+ retry++;
+ continue;
+ }
+ goto negotiate_error;
+ }
+ case AF_DETACH: { // Filter is redundant and wants to be unloaded
+ struct af_instance *aft = af->prev; // never NULL
+ af_remove(s, af);
+ af = aft->next;
+ break;
+ }
+ default:
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Reinitialization did not "
+ "work, audio filter '%s' returned error code %i\n",
+ af->info->name, rv);
+ af_print_filter_chain(s, af, MSGL_ERR);
+ return AF_ERROR;
+ }
}
- // Check if this is the first filter
- if(!af->prev)
- memcpy(&in,&(s->input),sizeof(struct mp_audio));
- else
- memcpy(&in,af->prev->data,sizeof(struct mp_audio));
- // Reset just in case...
- in.audio=NULL;
- in.len=0;
-
- rv = af->control(af,AF_CONTROL_REINIT,&in);
- switch(rv){
- case AF_OK:
- af = af->next;
- break;
- case AF_FALSE:{ // Configuration filter is needed
- // Do auto insertion only if force is not specified
- if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
- struct af_instance* new = NULL;
- // Insert channels filter
- if((af->prev?af->prev->data->nch:s->input.nch) != in.nch){
- // Create channels filter
- if(NULL == (new = af_prepend(s,af,"channels")))
- return AF_ERROR;
- // Set number of output channels
- if(AF_OK != (rv = new->control(new,AF_CONTROL_CHANNELS,&in.nch)))
- return rv;
- // Initialize channels filter
- if(!new->prev)
- memcpy(&in,&(s->input),sizeof(struct mp_audio));
- else
- memcpy(&in,new->prev->data,sizeof(struct mp_audio));
- if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
- return rv;
- }
- // Insert format filter
- if((af->prev?af->prev->data->format:s->input.format) != in.format){
- // Create format filter
- if(NULL == (new = af_prepend(s,af,"format")))
- return AF_ERROR;
- // Set output bits per sample
- in.format |= af_bits2fmt(in.bps*8);
- if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_FMT,&in.format)))
- return rv;
- // Initialize format filter
- if(!new->prev)
- memcpy(&in,&(s->input),sizeof(struct mp_audio));
- else
- memcpy(&in,new->prev->data,sizeof(struct mp_audio));
- if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
- return rv;
- }
- if(!new){ // Should _never_ happen
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to correct audio format. "
- "This error should never occur, please send a bug report.\n");
- return AF_ERROR;
- }
- af=new->next;
- }
- else {
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Automatic filter insertion disabled "
- "but formats do not match. Giving up.\n");
- return AF_ERROR;
- }
- break;
- }
- case AF_DETACH:{ // Filter is redundant and wants to be unloaded
- // Do auto remove only if force is not specified
- if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
- struct af_instance* aft=af->prev;
- af_remove(s,af);
- if(aft)
- af=aft->next;
- else
- af=s->first; // Restart configuration
- }
- break;
- }
- default:
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Reinitialization did not work, audio"
- " filter '%s' returned error code %i\n",af->info->name,rv);
- return AF_ERROR;
- }
- }while(af);
+ af_print_filter_chain(s, NULL, MSGL_V);
- af_print_filter_chain(s);
+ return AF_OK;
- return AF_OK;
+negotiate_error:
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to correct audio format. "
+ "This error should never occur, please send a bug report.\n");
+ af_print_filter_chain(s, af, MSGL_ERR);
+ return AF_ERROR;
}
// Uninit and remove all filters
-void af_uninit(struct af_stream* s)
+void af_uninit(struct af_stream *s)
{
- while(s->first)
- af_remove(s,s->first);
+ while (s->first->next && s->first->next != s->last)
+ af_remove(s, s->first->next);
}
-/**
- * Extend the filter chain so we get the required output format at the end.
- * \return AF_ERROR on error, AF_OK if successful.
- */
-static int fixup_output_format(struct af_stream* s)
-{
- struct af_instance* af = NULL;
- // Check number of output channels fix if not OK
- // If needed always inserted last -> easy to screw up other filters
- if(s->output.nch && s->last->data->nch!=s->output.nch){
- if(!strcmp(s->last->info->name,"format"))
- af = af_prepend(s,s->last,"channels");
- else
- af = af_append(s,s->last,"channels");
- // Init the new filter
- if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&(s->output.nch))))
- return AF_ERROR;
- if(AF_OK != af_reinit(s,af))
- return AF_ERROR;
- }
-
- // Check output format fix if not OK
- if(s->output.format != AF_FORMAT_UNKNOWN &&
- s->last->data->format != s->output.format){
- if(strcmp(s->last->info->name,"format"))
- af = af_append(s,s->last,"format");
- else
- af = s->last;
- // Init the new filter
- s->output.format |= af_bits2fmt(s->output.bps*8);
- if(!af || (AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT,&(s->output.format))))
- return AF_ERROR;
- if(AF_OK != af_reinit(s,af))
- return AF_ERROR;
- }
+struct af_stream *af_new(struct MPOpts *opts)
+{
+ struct af_stream *s = talloc_zero(NULL, struct af_stream);
+ static struct af_info in = { .name = "in" };
+ s->first = talloc(s, struct af_instance);
+ *s->first = (struct af_instance) {
+ .info = &in,
+ .control = input_control,
+ .play = dummy_play,
+ .setup = s,
+ .data = &s->input,
+ .mul = 1.0,
+ };
+ static struct af_info out = { .name = "out" };
+ s->last = talloc(s, struct af_instance);
+ *s->last = (struct af_instance) {
+ .info = &out,
+ .control = output_control,
+ .play = dummy_play,
+ .setup = s,
+ .data = &s->filter_output,
+ .mul = 1.0,
+ };
+ s->first->next = s->last;
+ s->last->prev = s->first;
+ return s;
+}
- // Re init again just in case
- if(AF_OK != af_reinit(s,s->first))
- return AF_ERROR;
-
- if (s->output.format == AF_FORMAT_UNKNOWN)
- s->output.format = s->last->data->format;
- if (!s->output.nch) s->output.nch = s->last->data->nch;
- if (!s->output.rate) s->output.rate = s->last->data->rate;
- if((s->last->data->format != s->output.format) ||
- (s->last->data->nch != s->output.nch) ||
- (s->last->data->rate != s->output.rate)) {
- return AF_ERROR;
- }
- return AF_OK;
+void af_destroy(struct af_stream *s)
+{
+ af_uninit(s);
+ talloc_free(s);
}
-/**
- * Automatic downmix to stereo in case the codec does not implement it.
+/*
+ * Set previously unset fields in s->output to those of the filter chain
+ * output. This is used to make the output format fixed, and even if you insert
+ * new filters or change the input format, the output format won't change.
+ * \return AF_ERROR on error, AF_OK if successful.
*/
-static void af_downmix(struct af_stream* s)
-{
- static const char * const downmix_strs[AF_NCH + 1] = {
- /* FL FR RL RR FC LF AL AR */
- [3] = "pan=2:" "0.6:0:" "0:0.6:" "0.4:0.4",
- [4] = "pan=2:" "0.6:0:" "0:0.6:" "0.4:0:" "0:0.4",
- [5] = "pan=2:" "0.5:0:" "0:0.5:" "0.2:0:" "0:0.2:" "0.3:0.3",
- [6] = "pan=2:" "0.4:0:" "0:0.4:" "0.2:0:" "0:0.2:" "0.3:0.3:" "0.1:0.1",
- [7] = "pan=2:" "0.4:0:" "0:0.4:" "0.2:0:" "0:0.2:" "0.3:0.3:" "0.1:0:" "0:0.1",
- [8] = "pan=2:" "0.4:0:" "0:0.4:" "0.15:0:" "0:0.15:" "0.25:0.25:" "0.1:0.1:" "0.1:0:" "0:0.1",
- };
- const char *af_pan_str = downmix_strs[s->input.nch];
+static int fixup_output_format(struct af_stream *s)
+{
+ if (AF_OK != af_reinit(s))
+ return AF_ERROR;
- if (af_pan_str)
- af_append(s, s->first, af_pan_str);
+ af_copy_unset_fields(&s->output, &s->filter_output);
+ return af_config_equals(&s->output, &s->filter_output) ? AF_OK : AF_ERROR;
}
/* Initialize the stream "s". This function creates a new filter list
@@ -473,233 +572,176 @@ static void af_downmix(struct af_stream* s)
If one of the prefered output parameters is 0 the one that needs
no conversion is used (i.e. the output format in the last filter).
The return value is 0 if success and -1 if failure */
-int af_init(struct af_stream* s)
-{
- struct MPOpts *opts = s->opts;
- int i=0;
-
- // Sanity check
- if(!s) return -1;
-
- // Precaution in case caller is misbehaving
- s->input.audio = s->output.audio = NULL;
- s->input.len = s->output.len = 0;
-
- // Figure out how fast the machine is
- if(AF_INIT_AUTO == (AF_INIT_TYPE_MASK & s->cfg.force))
- s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_TYPE;
-
- // Check if this is the first call
- if(!s->first){
- // Append a downmix pan filter at the beginning of the chain if needed
- if (s->input.nch != opts->audio_output_channels
- && opts->audio_output_channels == 2)
- af_downmix(s);
- // Add all filters in the list (if there are any)
- if (s->cfg.list) {
- while(s->cfg.list[i]){
- if(!af_append(s,s->last,s->cfg.list[i++]))
- return -1;
- }
- }
- }
-
- // If we do not have any filters otherwise
- // add dummy to make automatic format conversion work
- if (!s->first && !af_append(s, s->first, "dummy"))
- return -1;
-
- // Init filters
- if(AF_OK != af_reinit(s,s->first))
- return -1;
-
- // make sure the chain is not empty and valid (e.g. because of AF_DETACH)
- if (!s->first)
- if (!af_append(s,s->first,"dummy") || AF_OK != af_reinit(s,s->first))
- return -1;
-
- // Check output format
- if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
- struct af_instance* af = NULL; // New filter
- // Check output frequency if not OK fix with resample
- if(s->output.rate && s->last->data->rate!=s->output.rate){
- // try to find a filter that can change samplrate
- af = af_control_any_rev(s, AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET,
- &(s->output.rate));
- if (!af) {
- char *resampler = "resample";
- if ((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW)
- resampler = "lavcresample";
- if((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW){
- if(!strcmp(s->first->info->name,"format"))
- af = af_append(s,s->first,resampler);
- else
- af = af_prepend(s,s->first,resampler);
- }
- else{
- if(!strcmp(s->last->info->name,"format"))
- af = af_prepend(s,s->last,resampler);
- else
- af = af_append(s,s->last,resampler);
- }
- // Init the new filter
- if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET,
- &(s->output.rate))))
- return -1;
- // Use lin int if the user wants fast
- if ((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_FAST) {
- char args[32];
- sprintf(args, "%d", s->output.rate);
- if (strcmp(resampler, "lavcresample") == 0)
- strcat(args, ":1");
- else
- strcat(args, ":0:0");
- af->control(af, AF_CONTROL_COMMAND_LINE, args);
- }
- }
- if(AF_OK != af_reinit(s,af))
- return -1;
+int af_init(struct af_stream *s)
+{
+ int i = 0;
+
+ // Sanity check
+ if (!s)
+ return -1;
+
+ // Precaution in case caller is misbehaving
+ s->input.audio = s->output.audio = NULL;
+ s->input.len = s->output.len = 0;
+
+ // Check if this is the first call
+ if (s->first->next == s->last) {
+ // Add all filters in the list (if there are any)
+ if (s->cfg.list) {
+ while (s->cfg.list[i]) {
+ if (!af_prepend(s, s->last, s->cfg.list[i++]))
+ return -1;
+ }
+ }
}
+
+ remove_auto_inserted_filters(s);
+
+ // Init filters
+ if (AF_OK != af_reinit(s))
+ return -1;
+
if (AF_OK != fixup_output_format(s)) {
- // Something is stuffed audio out will not work
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[libaf] Unable to setup filter system can not"
- " meet sound-card demands, please send a bug report. \n");
- af_uninit(s);
- return -1;
+ // Something is stuffed audio out will not work
+ mp_msg(
+ MSGT_AFILTER, MSGL_ERR,
+ "[libaf] Unable to setup filter system can not"
+ " meet sound-card demands, please send a bug report. \n");
+ af_uninit(s);
+ return -1;
}
- }
- return 0;
+ return 0;
}
/* Add filter during execution. This function adds the filter "name"
to the stream s. The filter will be inserted somewhere nice in the
list of filters. The return value is a pointer to the new filter,
If the filter couldn't be added the return value is NULL. */
-struct af_instance* af_add(struct af_stream* s, char* name){
- struct af_instance* new;
- // Sanity check
- if(!s || !s->first || !name)
- return NULL;
- // Insert the filter somewhere nice
- if(!strcmp(s->first->info->name,"format"))
- new = af_append(s, s->first, name);
- else
- new = af_prepend(s, s->first, name);
- if(!new)
- return NULL;
-
- // Reinitalize the filter list
- if(AF_OK != af_reinit(s, s->first) ||
- AF_OK != fixup_output_format(s)){
- while (s->first)
- af_remove(s, s->first);
- af_init(s);
- return NULL;
- }
- return new;
+struct af_instance *af_add(struct af_stream *s, char *name)
+{
+ struct af_instance *new;
+ // Sanity check
+ if (!s || !s->first || !name)
+ return NULL;
+ // Insert the filter somewhere nice
+ if (af_is_conversion_filter(s->first->next))
+ new = af_append(s, s->first->next, name);
+ else
+ new = af_prepend(s, s->first->next, name);
+ if (!new)
+ return NULL;
+
+ // Reinitalize the filter list
+ if (AF_OK != af_reinit(s) ||
+ AF_OK != fixup_output_format(s)) {
+ while (s->first)
+ af_remove(s, s->first);
+ af_init(s);
+ return NULL;
+ }
+ return new;
}
// Filter data chunk through the filters in the list
-struct mp_audio* af_play(struct af_stream* s, struct mp_audio* data)
+struct mp_audio *af_play(struct af_stream *s, struct mp_audio *data)
{
- struct af_instance* af=s->first;
- // Iterate through all filters
- do{
- if (data->len <= 0) break;
- data=af->play(af,data);
- af=af->next;
- }while(af && data);
- return data;
+ struct af_instance *af = s->first;
+ // Iterate through all filters
+ do {
+ if (data->len <= 0)
+ break;
+ data = af->play(af, data);
+ af = af->next;
+ } while (af && data);
+ return data;
}
/* Calculate the minimum output buffer size for given input data d
* when using the RESIZE_LOCAL_BUFFER macro. The +t+1 part ensures the
* value is >= len*mul rounded upwards to whole samples even if the
* double 'mul' is inexact. */
-int af_lencalc(double mul, struct mp_audio* d)
+int af_lencalc(double mul, struct mp_audio *d)
{
- int t = d->bps * d->nch;
- return d->len * mul + t + 1;
+ int t = d->bps * d->nch;
+ return d->len * mul + t + 1;
}
// Calculate average ratio of filter output size to input size
-double af_calc_filter_multiplier(struct af_stream* s)
+double af_calc_filter_multiplier(struct af_stream *s)
{
- struct af_instance* af=s->first;
- double mul = 1;
- // Iterate through all filters and calculate total multiplication factor
- do{
- mul *= af->mul;
- af=af->next;
- }while(af);
+ struct af_instance *af = s->first;
+ double mul = 1;
+ // Iterate through all filters and calculate total multiplication factor
+ do {
+ mul *= af->mul;
+ af = af->next;
+ } while (af);
- return mul;
+ return mul;
}
/* Calculate the total delay [bytes output] caused by the filters */
-double af_calc_delay(struct af_stream* s)
+double af_calc_delay(struct af_stream *s)
{
- struct af_instance* af=s->first;
- register double delay = 0.0;
- // Iterate through all filters
- while(af){
- delay += af->delay;
- delay *= af->mul;
- af=af->next;
- }
- return delay;
+ struct af_instance *af = s->first;
+ register double delay = 0.0;
+ // Iterate through all filters
+ while (af) {
+ delay += af->delay;
+ delay *= af->mul;
+ af = af->next;
+ }
+ return delay;
}
/* Helper function called by the macro with the same name this
function should not be called directly */
-int af_resize_local_buffer(struct af_instance* af, struct mp_audio* data)
-{
- // Calculate new length
- register int len = af_lencalc(af->mul,data);
- mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
- "old len = %i, new len = %i\n",af->info->name,af->data->len,len);
- // If there is a buffer free it
- free(af->data->audio);
- // Create new buffer and check that it is OK
- af->data->audio = malloc(len);
- if(!af->data->audio){
- mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
- return AF_ERROR;
- }
- af->data->len=len;
- return AF_OK;
+int af_resize_local_buffer(struct af_instance *af, struct mp_audio *data)
+{
+ // Calculate new length
+ register int len = af_lencalc(af->mul, data);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[libaf] Reallocating memory in module %s, "
+ "old len = %i, new len = %i\n", af->info->name, af->data->len, len);
+ // If there is a buffer free it
+ free(af->data->audio);
+ // Create new buffer and check that it is OK
+ af->data->audio = malloc(len);
+ if (!af->data->audio) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
+ return AF_ERROR;
+ }
+ af->data->len = len;
+ return AF_OK;
}
// documentation in af.h
-struct af_instance *af_control_any_rev (struct af_stream* s, int cmd, void* arg) {
- int res = AF_UNKNOWN;
- struct af_instance* filt = s->last;
- while (filt) {
- res = filt->control(filt, cmd, arg);
- if (res == AF_OK)
- return filt;
- filt = filt->prev;
- }
- return NULL;
-}
-
-void af_help (void) {
- int i = 0;
- mp_msg(MSGT_AFILTER, MSGL_INFO, "Available audio filters:\n");
- while (filter_list[i]) {
- if (filter_list[i]->comment && filter_list[i]->comment[0])
- mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s (%s)\n", filter_list[i]->name, filter_list[i]->info, filter_list[i]->comment);
- else
- mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s\n", filter_list[i]->name, filter_list[i]->info);
- i++;
- }
+struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg)
+{
+ int res = AF_UNKNOWN;
+ struct af_instance *filt = s->last;
+ while (filt) {
+ res = filt->control(filt, cmd, arg);
+ if (res == AF_OK)
+ return filt;
+ filt = filt->prev;
+ }
+ return NULL;
}
-void af_fix_parameters(struct mp_audio *data)
+void af_help(void)
{
- if (data->nch < 0 || data->nch > AF_NCH) {
- mp_msg(MSGT_AFILTER, MSGL_ERR, "Invalid number of channels %i, assuming 2.\n", data->nch);
- data->nch = 2;
+ int i = 0;
+ mp_msg(MSGT_AFILTER, MSGL_INFO, "Available audio filters:\n");
+ while (filter_list[i]) {
+ if (filter_list[i]->comment && filter_list[i]->comment[0]) {
+ mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s (%s)\n",
+ filter_list[i]->name, filter_list[i]->info,
+ filter_list[i]->comment);
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_INFO, " %-15s: %s\n",
+ filter_list[i]->name,
+ filter_list[i]->info);
+ }
+ i++;
}
- data->bps = af_fmt2bits(data->format)/8;
}
diff --git a/audio/filter/af.h b/audio/filter/af.h
index 31abe1edee..4ccc70792f 100644
--- a/audio/filter/af.h
+++ b/audio/filter/af.h
@@ -20,31 +20,21 @@
#define MPLAYER_AF_H
#include <stdio.h>
+#include <stdbool.h>
#include "config.h"
#include "core/options.h"
#include "audio/format.h"
+#include "audio/chmap.h"
+#include "audio/audio.h"
#include "control.h"
#include "core/mp_msg.h"
struct af_instance;
// Number of channels
-#ifndef AF_NCH
-#define AF_NCH 8
-#endif
-
-// Audio data chunk
-struct mp_audio {
- void *audio; // data buffer
- int len; // buffer length
- int rate; // sample rate
- int nch; // number of channels
- int format; // format
- int bps; // bytes per sample
-};
-
+#define AF_NCH MP_NUM_CHANNELS
// Flags used for defining the behavior of an audio filter
#define AF_FLAGS_REENTRANT 0x00000000
@@ -59,6 +49,7 @@ struct af_info {
const char *comment;
const int flags;
int (*open)(struct af_instance *vf);
+ bool (*test_conversion)(int src_format, int dst_format);
};
// Linked list of audio filters
@@ -75,29 +66,11 @@ struct af_instance {
* corresponding output */
double mul; /* length multiplier: how much does this instance change
the length of the buffer. */
+ bool auto_inserted; // inserted by af.c, such as conversion filters
};
-// Initialization flags
-extern int *af_cpu_speed;
-
-#define AF_INIT_AUTO 0x00000000
-#define AF_INIT_SLOW 0x00000001
-#define AF_INIT_FAST 0x00000002
-#define AF_INIT_FORCE 0x00000003
-#define AF_INIT_TYPE_MASK 0x00000003
-
-#define AF_INIT_INT 0x00000000
-#define AF_INIT_FLOAT 0x00000004
-#define AF_INIT_FORMAT_MASK 0x00000004
-
-// Default init type
-#ifndef AF_INIT_TYPE
-#define AF_INIT_TYPE (af_cpu_speed ? *af_cpu_speed : AF_INIT_SLOW)
-#endif
-
// Configuration switches
struct af_cfg {
- int force; // Initialization type
char **list; /* list of names of filters that are added to filter
list during first initialization of stream */
};
@@ -107,9 +80,12 @@ struct af_stream {
// The first and last filter in the list
struct af_instance *first;
struct af_instance *last;
- // Storage for input and output data formats
+ // The user sets the input format (what the decoder outputs), and sets some
+ // or all fields in output to the output format the AO accepts.
+ // See fixup_output_format().
struct mp_audio input;
struct mp_audio output;
+ struct mp_audio filter_output;
// Configuration for this stream
struct af_cfg cfg;
struct MPOpts *opts;
@@ -139,6 +115,9 @@ struct af_stream {
* \param s filter chain
*/
+struct af_stream *af_new(struct MPOpts *opts);
+void af_destroy(struct af_stream *s);
+
/**
* \brief Initialize the stream "s".
* \return 0 on success, -1 on failure
@@ -161,10 +140,10 @@ void af_uninit(struct af_stream *s);
/**
* \brief Reinit the filter list from the given filter on downwards
- * \param Filter instance to begin the reinit from
+ * See af.c.
* \return AF_OK on success or AF_ERROR on failure
*/
-int af_reinit(struct af_stream *s, struct af_instance *af);
+int af_reinit(struct af_stream *s);
/**
* \brief This function adds the filter "name" to the stream s.
@@ -306,23 +285,13 @@ float af_softclip(float a);
/** Print a list of all available audio filters */
void af_help(void);
-/**
- * \brief fill the missing parameters in the struct mp_audio structure
- * \param data structure to fill
- * \ingroup af_filter
- *
- * Currently only sets bps based on format
- */
-void af_fix_parameters(struct mp_audio *data);
-
/** Memory reallocation macro: if a local buffer is used (i.e. if the
filter doesn't operate on the incoming buffer this macro must be
called to ensure the buffer is big enough.
* \ingroup af_filter
*/
#define RESIZE_LOCAL_BUFFER(a, d) \
- ((a->data->len < \
- af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
+ ((a->data->len < af_lencalc(a->mul, d)) ? af_resize_local_buffer(a, d) : AF_OK)
/* Some other useful macro definitions*/
#ifndef min
diff --git a/audio/filter/af_bs2b.c b/audio/filter/af_bs2b.c
index aebcc3b201..f8003a70a3 100644
--- a/audio/filter/af_bs2b.c
+++ b/audio/filter/af_bs2b.c
@@ -105,9 +105,8 @@ static int control(struct af_instance *af, int cmd, void *arg)
format = ((struct mp_audio*)arg)->format;
af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = 2; // bs2b is useful only for 2ch audio
- af->data->bps = ((struct mp_audio*)arg)->bps;
- af->data->format = format;
+ mp_audio_set_num_channels(af->data, 2); // bs2b is useful only for 2ch audio
+ mp_audio_set_format(af->data, format);
/* check for formats supported by libbs2b
and assign corresponding handlers */
@@ -162,8 +161,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
break;
default:
af->play = play_f;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
break;
}
diff --git a/audio/filter/af_center.c b/audio/filter/af_center.c
index aa9aae8514..42571eea35 100644
--- a/audio/filter/af_center.c
+++ b/audio/filter/af_center.c
@@ -48,9 +48,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_set_channels_old(af->data, max(s->ch+1,((struct mp_audio*)arg)->nch));
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
return af_test_output(af,(struct mp_audio*)arg);
}
diff --git a/audio/filter/af_channels.c b/audio/filter/af_channels.c
index 8f676d8cfd..7955018ec0 100644
--- a/audio/filter/af_channels.c
+++ b/audio/filter/af_channels.c
@@ -164,8 +164,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->format = ((struct mp_audio*)arg)->format;
- af->data->bps = ((struct mp_audio*)arg)->bps;
+ mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
return check_routes(s,((struct mp_audio*)arg)->nch,af->data->nch);
case AF_CONTROL_COMMAND_LINE:{
@@ -194,54 +193,20 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
}
- if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch))
+ struct mp_chmap chmap;
+ mp_chmap_from_channels(&chmap, nch);
+ if (AF_OK != af->control(af, AF_CONTROL_CHANNELS | AF_CONTROL_SET, &chmap))
return AF_ERROR;
return AF_OK;
}
case AF_CONTROL_CHANNELS | AF_CONTROL_SET:
// Reinit must be called after this function has been called
- // Sanity check
- if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[channels] The number of output channels must be"
- " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
- return AF_ERROR;
- }
-
- af->data->nch=((int*)arg)[0];
+ mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
if(!s->router)
mp_msg(MSGT_AFILTER, MSGL_V, "[channels] Changing number of channels"
" to %i\n",af->data->nch);
return AF_OK;
- case AF_CONTROL_CHANNELS | AF_CONTROL_GET:
- *(int*)arg = af->data->nch;
- return AF_OK;
- case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{
- int ch = ((af_control_ext_t*)arg)->ch;
- int* route = ((af_control_ext_t*)arg)->arg;
- s->route[ch][FR] = route[FR];
- s->route[ch][TO] = route[TO];
- return AF_OK;
- }
- case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{
- int ch = ((af_control_ext_t*)arg)->ch;
- int* route = ((af_control_ext_t*)arg)->arg;
- route[FR] = s->route[ch][FR];
- route[TO] = s->route[ch][TO];
- return AF_OK;
- }
- case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET:
- s->nr = *(int*)arg;
- return AF_OK;
- case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET:
- *(int*)arg = s->nr;
- return AF_OK;
- case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET:
- s->router = *(int*)arg;
- return AF_OK;
- case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET:
- *(int*)arg = s->router;
- return AF_OK;
}
return AF_UNKNOWN;
}
@@ -277,7 +242,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
c->len = c->len / c->nch * l->nch;
- c->nch = l->nch;
+ mp_audio_set_channels(c, &l->channels);
return c;
}
diff --git a/audio/filter/af_delay.c b/audio/filter/af_delay.c
index ce8d71980b..eb3e9e19cb 100644
--- a/audio/filter/af_delay.c
+++ b/audio/filter/af_delay.c
@@ -52,10 +52,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
for(i=0;i<af->data->nch;i++)
free(s->q[i]);
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
- af->data->format = ((struct mp_audio*)arg)->format;
- af->data->bps = ((struct mp_audio*)arg)->bps;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
// Allocate new delay queues
for(i=0;i<af->data->nch;i++){
diff --git a/audio/filter/af_volnorm.c b/audio/filter/af_drc.c
index f49bbc185a..e293f7f616 100644
--- a/audio/filter/af_volnorm.c
+++ b/audio/filter/af_drc.c
@@ -75,27 +75,22 @@ typedef struct af_volume_s
// "Ideal" level
float mid_s16;
float mid_float;
-}af_volnorm_t;
+}af_drc_t;
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
- af_volnorm_t* s = (af_volnorm_t*)af->setup;
+ af_drc_t* s = (af_drc_t*)af->setup;
switch(cmd){
case AF_CONTROL_REINIT:
// Sanity check
if(!arg) return AF_ERROR;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
- if(((struct mp_audio*)arg)->format == (AF_FORMAT_S16_NE)){
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
- }else{
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16_NE)){
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
return af_test_output(af,(struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE:{
@@ -120,7 +115,7 @@ static void uninit(struct af_instance* af)
free(af->setup);
}
-static void method1_int16(af_volnorm_t *s, struct mp_audio *c)
+static void method1_int16(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
int16_t *data = (int16_t*)c->audio; // Audio data
@@ -162,7 +157,7 @@ static void method1_int16(af_volnorm_t *s, struct mp_audio *c)
s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
}
-static void method1_float(af_volnorm_t *s, struct mp_audio *c)
+static void method1_float(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
float *data = (float*)c->audio; // Audio data
@@ -199,7 +194,7 @@ static void method1_float(af_volnorm_t *s, struct mp_audio *c)
s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
}
-static void method2_int16(af_volnorm_t *s, struct mp_audio *c)
+static void method2_int16(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
int16_t *data = (int16_t*)c->audio; // Audio data
@@ -249,7 +244,7 @@ static void method2_int16(af_volnorm_t *s, struct mp_audio *c)
s->idx = (s->idx + 1) % NSAMPLES;
}
-static void method2_float(af_volnorm_t *s, struct mp_audio *c)
+static void method2_float(af_drc_t *s, struct mp_audio *c)
{
register int i = 0;
float *data = (float*)c->audio; // Audio data
@@ -298,7 +293,7 @@ static void method2_float(af_volnorm_t *s, struct mp_audio *c)
// Filter data through filter
static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
{
- af_volnorm_t *s = af->setup;
+ af_drc_t *s = af->setup;
if(af->data->format == (AF_FORMAT_S16_NE))
{
@@ -325,27 +320,27 @@ static int af_open(struct af_instance* af){
af->play=play;
af->mul=1;
af->data=calloc(1,sizeof(struct mp_audio));
- af->setup=calloc(1,sizeof(af_volnorm_t));
+ af->setup=calloc(1,sizeof(af_drc_t));
if(af->data == NULL || af->setup == NULL)
return AF_ERROR;
- ((af_volnorm_t*)af->setup)->mul = MUL_INIT;
- ((af_volnorm_t*)af->setup)->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
- ((af_volnorm_t*)af->setup)->idx = 0;
- ((af_volnorm_t*)af->setup)->mid_s16 = ((float)SHRT_MAX) * DEFAULT_TARGET;
- ((af_volnorm_t*)af->setup)->mid_float = DEFAULT_TARGET;
+ ((af_drc_t*)af->setup)->mul = MUL_INIT;
+ ((af_drc_t*)af->setup)->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
+ ((af_drc_t*)af->setup)->idx = 0;
+ ((af_drc_t*)af->setup)->mid_s16 = ((float)SHRT_MAX) * DEFAULT_TARGET;
+ ((af_drc_t*)af->setup)->mid_float = DEFAULT_TARGET;
for (i = 0; i < NSAMPLES; i++)
{
- ((af_volnorm_t*)af->setup)->mem[i].len = 0;
- ((af_volnorm_t*)af->setup)->mem[i].avg = 0;
+ ((af_drc_t*)af->setup)->mem[i].len = 0;
+ ((af_drc_t*)af->setup)->mem[i].avg = 0;
}
return AF_OK;
}
// Description of this filter
-struct af_info af_info_volnorm = {
- "Volume normalizer filter",
- "volnorm",
+struct af_info af_info_drc = {
+ "Dynamic range compression filter",
+ "drc",
"Alex Beregszaszi & Pierre Lombard",
"",
AF_FLAGS_NOT_REENTRANT,
diff --git a/audio/filter/af_dummy.c b/audio/filter/af_dummy.c
index 29a5b3d4b8..5a54cdd80c 100644
--- a/audio/filter/af_dummy.c
+++ b/audio/filter/af_dummy.c
@@ -29,8 +29,8 @@
static int control(struct af_instance* af, int cmd, void* arg)
{
switch(cmd){
- case AF_CONTROL_REINIT:
- memcpy(af->data,(struct mp_audio*)arg,sizeof(struct mp_audio));
+ case AF_CONTROL_REINIT: ;
+ *af->data = *(struct mp_audio*)arg;
mp_msg(MSGT_AFILTER, MSGL_V, "[dummy] Was reinitialized: %iHz/%ich/%s\n",
af->data->rate,af->data->nch,af_fmt2str_short(af->data->format));
return AF_OK;
diff --git a/audio/filter/af_equalizer.c b/audio/filter/af_equalizer.c
index c488ffaeaf..6441b9b116 100644
--- a/audio/filter/af_equalizer.c
+++ b/audio/filter/af_equalizer.c
@@ -96,10 +96,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
// Calculate number of active filters
s->K=KM;
@@ -150,30 +148,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
}
return AF_OK;
}
- case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{
- float* gain = ((af_control_ext_t*)arg)->arg;
- int ch = ((af_control_ext_t*)arg)->ch;
- int k;
- if(ch >= AF_NCH || ch < 0)
- return AF_ERROR;
-
- for(k = 0 ; k<KM ; k++)
- s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0;
-
- return AF_OK;
- }
- case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{
- float* gain = ((af_control_ext_t*)arg)->arg;
- int ch = ((af_control_ext_t*)arg)->ch;
- int k;
- if(ch >= AF_NCH || ch < 0)
- return AF_ERROR;
-
- for(k = 0 ; k<KM ; k++)
- gain[k] = log10(s->g[ch][k]+1.0) * 20.0;
-
- return AF_OK;
- }
}
return AF_UNKNOWN;
}
diff --git a/audio/filter/af_export.c b/audio/filter/af_export.c
index 5e3a1869ee..ea0aa938ca 100644
--- a/audio/filter/af_export.c
+++ b/audio/filter/af_export.c
@@ -85,10 +85,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
close(s->fd);
// Accept only int16_t as input format (which sucks)
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
// If buffer length isn't set, set it to the default value
if(s->sz == 0)
diff --git a/audio/filter/af_extrastereo.c b/audio/filter/af_extrastereo.c
index 0f7fe36861..ed1fd27898 100644
--- a/audio/filter/af_extrastereo.c
+++ b/audio/filter/af_extrastereo.c
@@ -47,17 +47,14 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = 2;
- if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_num_channels(af->data, 2);
+ if (af->data->format == AF_FORMAT_FLOAT_NE)
{
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
af->play = play_float;
}// else
{
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
af->play = play_s16;
}
@@ -69,12 +66,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
s->mul = f;
return AF_OK;
}
- case AF_CONTROL_ES_MUL | AF_CONTROL_SET:
- s->mul = *(float*)arg;
- return AF_OK;
- case AF_CONTROL_ES_MUL | AF_CONTROL_GET:
- *(float*)arg = s->mul;
- return AF_OK;
}
return AF_UNKNOWN;
}
diff --git a/audio/filter/af_force.c b/audio/filter/af_force.c
new file mode 100644
index 0000000000..51fe83d0f0
--- /dev/null
+++ b/audio/filter/af_force.c
@@ -0,0 +1,146 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include <libavutil/common.h>
+
+#include "core/m_config.h"
+#include "core/m_option.h"
+
+#include "audio/format.h"
+#include "af.h"
+
+struct priv {
+ struct m_config *config;
+
+ int in_format;
+ int in_srate;
+ struct mp_chmap in_channels;
+ int out_format;
+ int out_srate;
+ struct mp_chmap out_channels;
+
+ struct mp_audio data;
+ struct mp_audio temp;
+};
+
+static const struct priv defaults = {
+ .in_format = AF_FORMAT_UNKNOWN,
+ .out_format = AF_FORMAT_UNKNOWN,
+};
+
+#define OPT_BASE_STRUCT struct priv
+
+static const struct m_option options[] = {
+ OPT_AUDIOFORMAT("format", in_format, 0),
+ OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000),
+ OPT_CHMAP("channels", in_channels, CONF_MIN, .min = 0),
+ OPT_AUDIOFORMAT("out-format", out_format, 0),
+ OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000),
+ OPT_CHMAP("out-channels", out_channels, CONF_MIN, .min = 0),
+ {0}
+};
+
+static int control(struct af_instance *af, int cmd, void *arg)
+{
+ struct priv *priv = af->setup;
+
+ switch (cmd) {
+ case AF_CONTROL_REINIT: {
+ struct mp_audio *in = arg;
+ struct mp_audio orig_in = *in;
+ struct mp_audio *out = af->data;
+
+ if (priv->in_format != AF_FORMAT_UNKNOWN)
+ mp_audio_set_format(in, priv->in_format);
+
+ if (priv->in_channels.num)
+ mp_audio_set_channels(in, &priv->in_channels);
+
+ if (priv->in_srate)
+ in->rate = priv->in_srate;
+
+ mp_audio_copy_config(out, in);
+
+ if (priv->out_format != AF_FORMAT_UNKNOWN)
+ mp_audio_set_format(out, priv->out_format);
+
+ if (priv->out_channels.num)
+ mp_audio_set_channels(out, &priv->out_channels);
+
+ if (priv->out_srate)
+ out->rate = priv->out_srate;
+
+ if (in->nch != out->nch || in->bps != out->bps) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR,
+ "[af_force] Forced input/output format are incompatible.\n");
+ return AF_ERROR;
+ }
+
+ return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
+ }
+ case AF_CONTROL_COMMAND_LINE: {
+ if (m_config_parse_suboptions(priv->config, "af_force", (char *)arg) < 0)
+ return AF_ERROR;
+ return AF_OK;
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
+{
+ struct priv *priv = af->setup;
+ struct mp_audio *r = &priv->temp;
+
+ *r = *af->data;
+ r->audio = data->audio;
+ r->len = data->len;
+
+ return r;
+}
+
+static void uninit(struct af_instance *af)
+{
+ talloc_free(af->setup);
+}
+
+static int af_open(struct af_instance *af)
+{
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul = 1;
+ struct priv *priv = talloc(NULL, struct priv);
+ af->setup = priv;
+ *priv = defaults;
+ priv->config = m_config_simple(priv);
+ talloc_steal(priv, priv->config);
+ m_config_register_options(priv->config, options);
+ af->data = &priv->data;
+ return AF_OK;
+}
+
+struct af_info af_info_force = {
+ "Force audio format",
+ "force",
+ "",
+ "",
+ 0,
+ af_open
+};
diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c
index 37d29c1f80..616bc9e494 100644
--- a/audio/filter/af_format.c
+++ b/audio/filter/af_format.c
@@ -75,6 +75,14 @@ static int check_format(int format)
return AF_ERROR;
}
+static bool test_conversion(int src_format, int dst_format)
+{
+ // This is the fallback conversion filter, so this filter is always
+ // inserted on format mismatches if no other filter can handle it.
+ // Initializing the filter might still fail.
+ return true;
+}
+
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
@@ -86,8 +94,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
int supported_ac3 = 0;
// Make sure this filter isn't redundant
- if(af->data->format == data->format &&
- af->data->bps == data->bps)
+ if(af->data->format == data->format)
return AF_DETACH;
// A bit complex because we can convert AC3
@@ -113,7 +120,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
buf1, buf2);
af->data->rate = data->rate;
- af->data->nch = data->nch;
+ mp_audio_set_channels(af->data, &data->channels);
af->mul = (double)af->data->bps / data->bps;
af->play = play; // set default
@@ -147,7 +154,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] %s is not a valid format\n", (char *)arg);
return AF_ERROR;
}
- if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
+ if(AF_OK != af->control(af, AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
return AF_ERROR;
return AF_OK;
}
@@ -156,8 +163,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
return AF_ERROR;
- af->data->format = *(int*)arg;
- af->data->bps = af_fmt2bits(af->data->format)/8;
+ mp_audio_set_format(af->data, *(int*)arg);
return AF_OK;
}
@@ -186,7 +192,7 @@ static struct mp_audio* play_swapendian(struct af_instance* af, struct mp_audio*
endian(c->audio,l->audio,len,c->bps);
c->audio = l->audio;
- c->format = l->format;
+ mp_audio_set_format(c, l->format);
return c;
}
@@ -203,9 +209,8 @@ static struct mp_audio* play_float_s16(struct af_instance* af, struct mp_audio*
float2int(c->audio, l->audio, len, 2);
c->audio = l->audio;
+ mp_audio_set_format(c, l->format);
c->len = len*2;
- c->bps = 2;
- c->format = l->format;
return c;
}
@@ -222,9 +227,8 @@ static struct mp_audio* play_s16_float(struct af_instance* af, struct mp_audio*
int2float(c->audio, l->audio, len, 2);
c->audio = l->audio;
+ mp_audio_set_format(c, l->format);
c->len = len*4;
- c->bps = 4;
- c->format = l->format;
return c;
}
@@ -276,9 +280,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
+ mp_audio_set_format(c, l->format);
c->len = len*l->bps;
- c->bps = l->bps;
- c->format = l->format;
return c;
}
@@ -301,7 +304,8 @@ struct af_info af_info_format = {
"Anders",
"",
AF_FLAGS_REENTRANT,
- af_open
+ af_open,
+ .test_conversion = test_conversion,
};
static inline uint32_t load24bit(void* data, int pos) {
diff --git a/audio/filter/af_hrtf.c b/audio/filter/af_hrtf.c
index 4f5eedb29d..85e6477b31 100644
--- a/audio/filter/af_hrtf.c
+++ b/audio/filter/af_hrtf.c
@@ -299,7 +299,7 @@ static int control(struct af_instance *af, int cmd, void* arg)
af->data->rate);
return AF_ERROR;
}
- af->data->nch = ((struct mp_audio*)arg)->nch;
+ mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch);
if(af->data->nch == 2) {
/* 2 channel input */
if(s->decode_mode != HRTF_MIX_MATRIX2CH) {
@@ -308,13 +308,12 @@ static int control(struct af_instance *af, int cmd, void* arg)
}
}
else if (af->data->nch < 5)
- af->data->nch = 5;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
+ mp_audio_set_channels_old(af->data, 5);
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
test_output_res = af_test_output(af, (struct mp_audio*)arg);
af->mul = 2.0 / af->data->nch;
// after testing input set the real output format
- af->data->nch = 2;
+ mp_audio_set_num_channels(af->data, 2);
s->print_flag = 1;
return test_output_res;
case AF_CONTROL_COMMAND_LINE:
@@ -566,7 +565,7 @@ static struct mp_audio* play(struct af_instance *af, struct mp_audio *data)
/* Set output data */
data->audio = af->data->audio;
data->len = data->len / data->nch * 2;
- data->nch = 2;
+ mp_audio_set_num_channels(data, 2);
return data;
}
diff --git a/audio/filter/af_karaoke.c b/audio/filter/af_karaoke.c
index 965eb8f40d..faed389625 100644
--- a/audio/filter/af_karaoke.c
+++ b/audio/filter/af_karaoke.c
@@ -34,10 +34,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
{
switch(cmd){
case AF_CONTROL_REINIT:
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
- af->data->format= AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
return af_test_output(af,(struct mp_audio*)arg);
}
return AF_UNKNOWN;
diff --git a/audio/filter/af_ladspa.c b/audio/filter/af_ladspa.c
index c1b3f24360..5e516f060e 100644
--- a/audio/filter/af_ladspa.c
+++ b/audio/filter/af_ladspa.c
@@ -291,7 +291,7 @@ static int af_ladspa_parse_plugin(af_ladspa_t *setup) {
static void* mydlopen(const char *filename, int flag) {
char *buf;
const char *end, *start, *ladspapath;
- int endsinso, needslash;
+ int endsinso;
size_t filenamelen;
void *result = NULL;
@@ -324,9 +324,9 @@ static void* mydlopen(const char *filename, int flag) {
ladspapath=getenv("LADSPA_PATH");
if (ladspapath) {
-
start=ladspapath;
while (*start != '\0') {
+ int needslash;
end=start;
while ( (*end != ':') && (*end != '\0') )
end++;
@@ -487,7 +487,6 @@ static int af_ladspa_malloc_failed(char *myname) {
static int control(struct af_instance *af, int cmd, void *arg) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
- int i, r;
float val;
switch(cmd) {
@@ -498,10 +497,8 @@ static int control(struct af_instance *af, int cmd, void *arg) {
/* accept FLOAT, let af_format do conversion */
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
/* arg->len is not set here yet, so init of buffers and connecting the
* filter, has to be done in play() :-/
@@ -538,7 +535,10 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
line += strlen(buf);
setup->file = strdup(buf);
- if (!setup->file) return af_ladspa_malloc_failed(setup->myname);
+ if (!setup->file) {
+ free(buf);
+ return af_ladspa_malloc_failed(setup->myname);
+ }
mp_msg(MSGT_AFILTER, MSGL_V, "%s: file --> %s\n", setup->myname,
setup->file);
if (*line != '\0') line++; /* read ':' */
@@ -554,7 +554,10 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
line += strlen(buf);
setup->label = strdup(buf);
- if (!setup->label) return af_ladspa_malloc_failed(setup->myname);
+ if (!setup->label) {
+ free(buf);
+ return af_ladspa_malloc_failed(setup->myname);
+ }
mp_msg(MSGT_AFILTER, MSGL_V, "%s: label --> %s\n", setup->myname,
setup->label);
/* if (*line != '0') line++; */ /* read ':' */
@@ -581,15 +584,14 @@ static int control(struct af_instance *af, int cmd, void *arg) {
/* ninputcontrols is set by now, read control values from arg */
- for(i=0; i<setup->ninputcontrols; i++) {
+ for (int i = 0; i < setup->ninputcontrols; i++) {
if (!line || *line != ':') {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
}
line++;
- r = sscanf(line, "%f", &val);
- if (r!=1) {
+ if (sscanf(line, "%f", &val) != 1) {
mp_msg(MSGT_AFILTER, MSGL_ERR, "%s: %s\n", setup->myname,
_("Not enough controls specified on the command line."));
return AF_ERROR;
@@ -599,7 +601,7 @@ static int control(struct af_instance *af, int cmd, void *arg) {
}
mp_msg(MSGT_AFILTER, MSGL_V, "%s: input controls: ", setup->myname);
- for(i=0; i<setup->ninputcontrols; i++) {
+ for (int i = 0; i < setup->ninputcontrols; i++) {
mp_msg(MSGT_AFILTER, MSGL_V, "%0.4f ",
setup->inputcontrols[setup->inputcontrolsmap[i]]);
}
@@ -609,7 +611,7 @@ static int control(struct af_instance *af, int cmd, void *arg) {
mp_msg(MSGT_AFILTER, MSGL_V, "%s: checking boundaries of input controls\n",
setup->myname);
- for(i=0; i<setup->ninputcontrols; i++) {
+ for (int i = 0; i < setup->ninputcontrols; i++) {
int p = setup->inputcontrolsmap[i];
LADSPA_PortRangeHint hint =
setup->plugin_descriptor->PortRangeHints[p];
@@ -651,8 +653,6 @@ static int control(struct af_instance *af, int cmd, void *arg) {
*/
static void uninit(struct af_instance *af) {
- int i;
-
free(af->data);
if (af->setup) {
af_ladspa_t *setup = (af_ladspa_t*) af->setup;
@@ -664,7 +664,7 @@ static void uninit(struct af_instance *af) {
}
if (setup->chhandles) {
- for(i=0; i<setup->nch; i+=setup->ninputs) {
+ for (int i = 0; i < setup->nch; i+=setup->ninputs) {
if (pdes->deactivate) pdes->deactivate(setup->chhandles[i]);
if (pdes->cleanup) pdes->cleanup(setup->chhandles[i]);
}
@@ -681,13 +681,13 @@ static void uninit(struct af_instance *af) {
free(setup->outputs);
if (setup->inbufs) {
- for(i=0; i<setup->nch; i++)
+ for(int i = 0; i < setup->nch; i++)
free(setup->inbufs[i]);
free(setup->inbufs);
}
if (setup->outbufs) {
- for(i=0; i<setup->nch; i++)
+ for (int i = 0; i < setup->nch; i++)
free(setup->outbufs[i]);
free(setup->outbufs);
}
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index 2b7a4ffb4c..7eacc01d81 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -27,7 +27,9 @@
#include <assert.h>
#include <libavcodec/avcodec.h>
+#include <libavutil/audioconvert.h>
#include <libavutil/intreadwrite.h>
+#include <libavutil/common.h>
#include <libavutil/mem.h>
#include "config.h"
@@ -47,6 +49,7 @@ const uint16_t ac3_bitrate_tab[19] = {
typedef struct af_ac3enc_s {
struct AVCodec *lavc_acodec;
struct AVCodecContext *lavc_actx;
+ AVPacket pkt;
bool planarize;
int add_iec61937_header;
int bit_rate;
@@ -72,16 +75,16 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (AF_FORMAT_IS_AC3(data->format) || data->nch < s->min_channel_num)
return AF_DETACH;
- af->data->format = s->in_sampleformat;
- af->data->bps = af_fmt2bits(s->in_sampleformat) / 8;
+ mp_audio_set_format(af->data, s->in_sampleformat);
if (data->rate == 48000 || data->rate == 44100 || data->rate == 32000)
af->data->rate = data->rate;
else
af->data->rate = 48000;
if (data->nch > AC3_MAX_CHANNELS)
- af->data->nch = AC3_MAX_CHANNELS;
+ mp_audio_set_num_channels(af->data, AC3_MAX_CHANNELS);
else
- af->data->nch = data->nch;
+ mp_audio_set_channels(af->data, &data->channels);
+ mp_chmap_reorder_to_lavc(&af->data->channels);
test_output_res = af_test_output(af, data);
s->pending_len = 0;
@@ -105,6 +108,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
// Put sample parameters
s->lavc_actx->channels = af->data->nch;
+ s->lavc_actx->channel_layout = mp_chmap_to_lavc(&af->data->channels);
s->lavc_actx->sample_rate = af->data->rate;
s->lavc_actx->bit_rate = bit_rate;
@@ -118,9 +122,8 @@ static int control(struct af_instance *af, int cmd, void *arg)
"encoder frame size %d\n", s->lavc_actx->frame_size);
return AF_ERROR;
}
- af->data->format = AF_FORMAT_AC3_BE;
- af->data->bps = 2;
- af->data->nch = 2;
+ mp_audio_set_format(af->data, AF_FORMAT_AC3_BE);
+ mp_audio_set_num_channels(af->data, 2);
return test_output_res;
case AF_CONTROL_COMMAND_LINE:
mp_msg(MSGT_AFILTER, MSGL_DBG2, "af_lavcac3enc cmdline: %s.\n", (char*)arg);
@@ -155,12 +158,13 @@ static int control(struct af_instance *af, int cmd, void *arg)
// Deallocate memory
static void uninit(struct af_instance* af)
{
+ af_ac3enc_t *s = af->setup;
+
if (af->data)
free(af->data->audio);
free(af->data);
- if (af->setup) {
- af_ac3enc_t *s = af->setup;
- af->setup = NULL;
+ if (s) {
+ av_free_packet(&s->pkt);
if(s->lavc_actx) {
avcodec_close(s->lavc_actx);
av_free(s->lavc_actx);
@@ -176,8 +180,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
af_ac3enc_t *s = af->setup;
struct mp_audio *c = data; // Current working data
struct mp_audio *l;
- int len, left, outsize = 0, destsize;
- char *buf, *src, *dest;
+ int left, outsize = 0;
+ char *buf, *src;
int max_output_len;
int frame_num = (data->len + s->pending_len) / s->expect_len;
int samplesize = af_fmt2bits(s->in_sampleformat) / 8;
@@ -207,6 +211,8 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
while (left > 0) {
+ int ret;
+
if (left + s->pending_len < s->expect_len) {
memcpy(s->pending_data + s->pending_len, src, left);
src += left;
@@ -215,8 +221,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
break;
}
- dest = s->add_iec61937_header ? buf + 8 : buf;
- destsize = (char *)l->audio + l->len - buf;
+ char *src2 = src;
if (s->pending_len) {
int needs = s->expect_len - s->pending_len;
@@ -225,58 +230,60 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
src += needs;
left -= needs;
}
+ src2= s->pending_data;
+ }
- if (c->nch >= 5)
- reorder_channel_nch(s->pending_data,
- AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
- AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
- c->nch,
- s->expect_len / samplesize, samplesize);
-
- void *data = (void *) s->pending_data;
- if (s->planarize) {
- void *data2 = malloc(s->expect_len);
- reorder_to_planar(data2, data, samplesize,
- c->nch, s->expect_len / samplesize / c->nch);
- data = data2;
- }
-
- len = avcodec_encode_audio(s->lavc_actx, dest, destsize, data);
+ void *data = (void *) src2;
+ if (s->planarize) {
+ void *data2 = malloc(s->expect_len);
+ reorder_to_planar(data2, data, samplesize,
+ c->nch, s->expect_len / samplesize / c->nch);
+ data = data2;
+ }
- if (s->planarize)
- free(data);
+ AVFrame *frame = avcodec_alloc_frame();
+ if (!frame) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[libaf] Could not allocate memory \n");
+ return NULL;
+ }
+ frame->nb_samples = AC3_FRAME_SIZE;
+ frame->format = s->lavc_actx->sample_fmt;
+ frame->channel_layout = s->lavc_actx->channel_layout;
+
+ ret = avcodec_fill_audio_frame(frame, c->nch, s->lavc_actx->sample_fmt,
+ (const uint8_t*)data, s->expect_len, 0);
+ if (ret < 0) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[lavac3enc] Frame setup failed.\n");
+ return NULL;
+ }
- s->pending_len = 0;
+ int ok;
+ ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok);
+ if (ret < 0 || !ok) {
+ mp_msg(MSGT_AFILTER, MSGL_FATAL, "[lavac3enc] Encode failed.\n");
+ return NULL;
}
- else {
- if (c->nch >= 5)
- reorder_channel_nch(src,
- AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
- AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
- c->nch,
- s->expect_len / samplesize, samplesize);
-
- void *data = (void *) src;
- if (s->planarize) {
- void *data2 = malloc(s->expect_len);
- reorder_to_planar(data2, data, samplesize,
- c->nch, s->expect_len / samplesize / c->nch);
- data = data2;
- }
- len = avcodec_encode_audio(s->lavc_actx, dest, destsize, data);
+ if (s->planarize)
+ free(data);
- if (s->planarize)
- free(data);
+ avcodec_free_frame(&frame);
+ if (s->pending_len) {
+ s->pending_len = 0;
+ } else {
src += s->expect_len;
left -= s->expect_len;
}
+
mp_msg(MSGT_AFILTER, MSGL_DBG2, "avcodec_encode_audio got %d, pending %d.\n",
- len, s->pending_len);
+ s->pkt.size, s->pending_len);
+ int len = s->pkt.size;
+ int header_len = 0;
if (s->add_iec61937_header) {
- int bsmod = dest[5] & 0x7;
+ assert(s->pkt.size > 5);
+ int bsmod = s->pkt.data[5] & 0x7;
AV_WB16(buf, 0xF872); // iec 61937 syncword 1
AV_WB16(buf + 2, 0x4E1F); // iec 61937 syncword 2
@@ -285,15 +292,21 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
AV_WB16(buf + 6, len << 3); // number of bits in payload
memset(buf + 8 + len, 0, AC3_FRAME_SIZE * 2 * 2 - 8 - len);
+ header_len = 8;
len = AC3_FRAME_SIZE * 2 * 2;
}
+ assert(buf + len <= (char *)af->data->audio + af->data->len);
+ assert(s->pkt.size <= len - header_len);
+
+ memcpy(buf + header_len, s->pkt.data, s->pkt.size);
+
outsize += len;
buf += len;
}
c->audio = l->audio;
- c->nch = 2;
- c->bps = 2;
+ mp_audio_set_num_channels(c, 2);
+ mp_audio_set_format(c, af->data->format);
c->len = outsize;
mp_msg(MSGT_AFILTER, MSGL_DBG2, "play return size %d, pending %d\n",
outsize, s->pending_len);
@@ -360,6 +373,8 @@ static int af_open(struct af_instance* af){
mp_msg(MSGT_AFILTER, MSGL_WARN,
"[af_lavcac3enc]: need to planarize audio data\n");
+ av_init_packet(&s->pkt);
+
return AF_OK;
}
diff --git a/audio/filter/af_lavcresample.c b/audio/filter/af_lavcresample.c
deleted file mode 100644
index ce777fed31..0000000000
--- a/audio/filter/af_lavcresample.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.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 <string.h>
-#include <inttypes.h>
-
-#include "config.h"
-#include "af.h"
-#include "libavcodec/avcodec.h"
-#include "libavutil/rational.h"
-
-// Data for specific instances of this filter
-typedef struct af_resample_s{
- struct AVResampleContext *avrctx;
- int16_t *in[AF_NCH];
- int in_alloc;
- int index;
-
- int filter_length;
- int linear;
- int phase_shift;
- double cutoff;
-
- int ctx_out_rate;
- int ctx_in_rate;
- int ctx_filter_size;
- int ctx_phase_shift;
- int ctx_linear;
- double ctx_cutoff;
-}af_resample_t;
-
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- af_resample_t* s = (af_resample_t*)af->setup;
- struct mp_audio *data= (struct mp_audio*)arg;
- int out_rate, test_output_res; // helpers for checking input format
-
- switch(cmd){
- case AF_CONTROL_REINIT:
- if((af->data->rate == data->rate) || (af->data->rate == 0))
- return AF_DETACH;
-
- af->data->nch = data->nch;
- if (af->data->nch > AF_NCH) af->data->nch = AF_NCH;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
- af->mul = (double)af->data->rate / data->rate;
- af->delay = af->data->nch * s->filter_length / min(af->mul, 1); // *bps*.5
-
- if (s->ctx_out_rate != af->data->rate || s->ctx_in_rate != data->rate || s->ctx_filter_size != s->filter_length ||
- s->ctx_phase_shift != s->phase_shift || s->ctx_linear != s->linear || s->ctx_cutoff != s->cutoff) {
- if(s->avrctx) av_resample_close(s->avrctx);
- s->avrctx= av_resample_init(af->data->rate, /*in_rate*/data->rate, s->filter_length, s->phase_shift, s->linear, s->cutoff);
- s->ctx_out_rate = af->data->rate;
- s->ctx_in_rate = data->rate;
- s->ctx_filter_size = s->filter_length;
- s->ctx_phase_shift = s->phase_shift;
- s->ctx_linear = s->linear;
- s->ctx_cutoff = s->cutoff;
- }
-
- // hack to make af_test_output ignore the samplerate change
- out_rate = af->data->rate;
- af->data->rate = data->rate;
- test_output_res = af_test_output(af, (struct mp_audio*)arg);
- af->data->rate = out_rate;
- return test_output_res;
- case AF_CONTROL_COMMAND_LINE:{
- s->cutoff= 0.0;
- sscanf((char*)arg,"%d:%d:%d:%d:%lf", &af->data->rate, &s->filter_length, &s->linear, &s->phase_shift, &s->cutoff);
- if(s->cutoff <= 0.0) s->cutoff= max(1.0 - 6.5/(s->filter_length+8), 0.80);
- return AF_OK;
- }
- case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
- af->data->rate = *(int*)arg;
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-// Deallocate memory
-static void uninit(struct af_instance* af)
-{
- if(af->data)
- free(af->data->audio);
- free(af->data);
- if(af->setup){
- int i;
- af_resample_t *s = af->setup;
- if(s->avrctx) av_resample_close(s->avrctx);
- for (i=0; i < AF_NCH; i++)
- free(s->in[i]);
- free(s);
- }
-}
-
-// Filter data through filter
-static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
-{
- af_resample_t *s = af->setup;
- int i, j, consumed, ret = 0;
- int16_t *in = (int16_t*)data->audio;
- int16_t *out;
- int chans = data->nch;
- int in_len = data->len/(2*chans);
- int out_len = in_len * af->mul + 10;
- int16_t tmp[AF_NCH][out_len];
-
- if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
- return NULL;
-
- out= (int16_t*)af->data->audio;
-
- out_len= min(out_len, af->data->len/(2*chans));
-
- if(s->in_alloc < in_len + s->index){
- s->in_alloc= in_len + s->index;
- for(i=0; i<chans; i++){
- s->in[i]= realloc(s->in[i], s->in_alloc*sizeof(int16_t));
- }
- }
-
- if(chans==1){
- memcpy(&s->in[0][s->index], in, in_len * sizeof(int16_t));
- }else if(chans==2){
- for(j=0; j<in_len; j++){
- s->in[0][j + s->index]= *(in++);
- s->in[1][j + s->index]= *(in++);
- }
- }else{
- for(j=0; j<in_len; j++){
- for(i=0; i<chans; i++){
- s->in[i][j + s->index]= *(in++);
- }
- }
- }
- in_len += s->index;
-
- for(i=0; i<chans; i++){
- ret= av_resample(s->avrctx, tmp[i], s->in[i], &consumed, in_len, out_len, i+1 == chans);
- }
- out_len= ret;
-
- s->index= in_len - consumed;
- for(i=0; i<chans; i++){
- memmove(s->in[i], s->in[i] + consumed, s->index*sizeof(int16_t));
- }
-
- if(chans==1){
- memcpy(out, tmp[0], out_len*sizeof(int16_t));
- }else if(chans==2){
- for(j=0; j<out_len; j++){
- *(out++)= tmp[0][j];
- *(out++)= tmp[1][j];
- }
- }else{
- for(j=0; j<out_len; j++){
- for(i=0; i<chans; i++){
- *(out++)= tmp[i][j];
- }
- }
- }
-
- data->audio = af->data->audio;
- data->len = out_len*chans*2;
- data->rate = af->data->rate;
- return data;
-}
-
-static int af_open(struct af_instance* af){
- af_resample_t *s = calloc(1,sizeof(af_resample_t));
- af->control=control;
- af->uninit=uninit;
- af->play=play;
- af->mul=1;
- af->data=calloc(1,sizeof(struct mp_audio));
- s->filter_length= 16;
- s->cutoff= max(1.0 - 6.5/(s->filter_length+8), 0.80);
- s->phase_shift= 10;
-// s->setup = RSMP_INT | FREQ_SLOPPY;
- af->setup=s;
- return AF_OK;
-}
-
-struct af_info af_info_lavcresample = {
- "Sample frequency conversion using libavcodec",
- "lavcresample",
- "Michael Niedermayer",
- "",
- AF_FLAGS_REENTRANT,
- af_open
-};
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
new file mode 100644
index 0000000000..cf248dc001
--- /dev/null
+++ b/audio/filter/af_lavrresample.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
+ *
+ * This file is part of mpv.
+ *
+ * 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 <string.h>
+#include <inttypes.h>
+#include <libavutil/opt.h>
+#include <libavutil/audioconvert.h>
+#include <libavutil/common.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/mathematics.h>
+
+#include "talloc.h"
+#include "config.h"
+
+#if defined(CONFIG_LIBAVRESAMPLE)
+#include <libavresample/avresample.h>
+#define USE_SET_CHANNEL_MAPPING HAVE_AVRESAMPLE_SET_CHANNEL_MAPPING
+#elif defined(CONFIG_LIBSWRESAMPLE)
+#include <libswresample/swresample.h>
+#define AVAudioResampleContext SwrContext
+#define avresample_alloc_context swr_alloc
+#define avresample_open swr_init
+#define avresample_close(x) do { } while(0)
+#define avresample_available(x) 0
+#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
+ swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
+#define avresample_set_channel_mapping swr_set_channel_mapping
+#define USE_SET_CHANNEL_MAPPING 1
+#else
+#error "config.h broken"
+#endif
+
+#include "core/mp_msg.h"
+#include "core/subopt-helper.h"
+#include "audio/filter/af.h"
+#include "audio/fmt-conversion.h"
+#include "audio/reorder_ch.h"
+
+struct af_resample_opts {
+ int filter_size;
+ int phase_shift;
+ int linear;
+ double cutoff;
+
+ int in_rate;
+ int in_format;
+ struct mp_chmap in_channels;
+ int out_rate;
+ int out_format;
+ struct mp_chmap out_channels;
+};
+
+struct af_resample {
+ int allow_detach;
+ struct AVAudioResampleContext *avrctx;
+ struct AVAudioResampleContext *avrctx_out; // for output channel reordering
+ struct af_resample_opts ctx; // opts in the context
+ struct af_resample_opts opts; // opts requested by the user
+ // At least libswresample keeps a pointer around for this:
+ int reorder_in[MP_NUM_CHANNELS];
+ int reorder_out[MP_NUM_CHANNELS];
+ uint8_t *reorder_buffer;
+};
+
+#ifdef CONFIG_LIBAVRESAMPLE
+static int get_delay(struct af_resample *s)
+{
+ return avresample_get_delay(s->avrctx);
+}
+#else
+static int get_delay(struct af_resample *s)
+{
+ return swr_get_delay(s->avrctx, s->ctx.in_rate);
+}
+#endif
+
+static double af_resample_default_cutoff(int filter_size)
+{
+ return FFMAX(1.0 - 6.5 / (filter_size + 8), 0.80);
+}
+
+static bool needs_lavrctx_reconfigure(struct af_resample *s,
+ struct mp_audio *in,
+ struct mp_audio *out)
+{
+ return s->ctx.in_rate != in->rate ||
+ s->ctx.in_format != in->format ||
+ !mp_chmap_equals(&s->ctx.in_channels, &in->channels) ||
+ s->ctx.out_rate != out->rate ||
+ s->ctx.out_format != out->format ||
+ !mp_chmap_equals(&s->ctx.out_channels, &out->channels) ||
+ s->ctx.filter_size != s->opts.filter_size ||
+ s->ctx.phase_shift != s->opts.phase_shift ||
+ s->ctx.linear != s->opts.linear ||
+ s->ctx.cutoff != s->opts.cutoff;
+
+}
+
+static bool test_conversion(int src_format, int dst_format)
+{
+ return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
+ af_to_avformat(dst_format) != AV_SAMPLE_FMT_NONE;
+}
+
+#define ctx_opt_set_int(a,b) av_opt_set_int(s->avrctx, (a), (b), 0)
+#define ctx_opt_set_dbl(a,b) av_opt_set_double(s->avrctx, (a), (b), 0)
+
+static int control(struct af_instance *af, int cmd, void *arg)
+{
+ struct af_resample *s = (struct af_resample *) af->setup;
+ struct mp_audio *in = (struct mp_audio *) arg;
+ struct mp_audio *out = (struct mp_audio *) af->data;
+
+ switch (cmd) {
+ case AF_CONTROL_REINIT: {
+ struct mp_audio orig_in = *in;
+
+ if (((out->rate == in->rate) || (out->rate == 0)) &&
+ (out->format == in->format) &&
+ (mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) &&
+ s->allow_detach)
+ return AF_DETACH;
+
+ if (out->rate == 0)
+ out->rate = in->rate;
+
+ if (mp_chmap_is_empty(&out->channels))
+ mp_audio_set_channels(out, &in->channels);
+
+ enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
+ if (in_samplefmt == AV_SAMPLE_FMT_NONE) {
+ mp_audio_set_format(in, AF_FORMAT_FLOAT_NE);
+ in_samplefmt = af_to_avformat(in->format);
+ }
+ enum AVSampleFormat out_samplefmt = af_to_avformat(out->format);
+ if (out_samplefmt == AV_SAMPLE_FMT_NONE) {
+ mp_audio_set_format(out, in->format);
+ out_samplefmt = in_samplefmt;
+ }
+
+ af->mul = (double) (out->rate * out->nch) / (in->rate * in->nch);
+ af->delay = out->nch * s->opts.filter_size / FFMIN(af->mul, 1);
+
+ if (needs_lavrctx_reconfigure(s, in, out)) {
+ avresample_close(s->avrctx);
+ avresample_close(s->avrctx_out);
+
+ s->ctx.out_rate = out->rate;
+ s->ctx.in_rate = in->rate;
+ s->ctx.out_format = out->format;
+ s->ctx.in_format = in->format;
+ s->ctx.out_channels= out->channels;
+ s->ctx.in_channels = in->channels;
+ s->ctx.filter_size = s->opts.filter_size;
+ s->ctx.phase_shift = s->opts.phase_shift;
+ s->ctx.linear = s->opts.linear;
+ s->ctx.cutoff = s->opts.cutoff;
+
+ struct mp_chmap map_in = in->channels;
+ struct mp_chmap map_out = out->channels;
+
+ // Try not to do any remixing if at least one is "unknown".
+ if (mp_chmap_is_unknown(&map_in) || mp_chmap_is_unknown(&map_out)) {
+ mp_chmap_set_unknown(&map_in, map_in.num);
+ mp_chmap_set_unknown(&map_out, map_out.num);
+ }
+
+ // unchecked: don't take any channel reordering into account
+ uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&map_in);
+ uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&map_out);
+
+ ctx_opt_set_int("in_channel_layout", in_ch_layout);
+ ctx_opt_set_int("out_channel_layout", out_ch_layout);
+
+ ctx_opt_set_int("in_sample_rate", s->ctx.in_rate);
+ ctx_opt_set_int("out_sample_rate", s->ctx.out_rate);
+
+ ctx_opt_set_int("in_sample_fmt", in_samplefmt);
+ ctx_opt_set_int("out_sample_fmt", out_samplefmt);
+
+ ctx_opt_set_int("filter_size", s->ctx.filter_size);
+ ctx_opt_set_int("phase_shift", s->ctx.phase_shift);
+ ctx_opt_set_int("linear_interp", s->ctx.linear);
+
+ ctx_opt_set_dbl("cutoff", s->ctx.cutoff);
+
+ struct mp_chmap in_lavc;
+ mp_chmap_from_lavc(&in_lavc, in_ch_layout);
+ mp_chmap_get_reorder(s->reorder_in, &map_in, &in_lavc);
+
+ struct mp_chmap out_lavc;
+ mp_chmap_from_lavc(&out_lavc, out_ch_layout);
+ mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
+
+ // Same configuration; we just reorder.
+ av_opt_set_int(s->avrctx_out, "in_channel_layout", out_ch_layout, 0);
+ av_opt_set_int(s->avrctx_out, "out_channel_layout", out_ch_layout, 0);
+ av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmt, 0);
+ av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
+ av_opt_set_int(s->avrctx_out, "in_sample_rate", s->ctx.out_rate, 0);
+ av_opt_set_int(s->avrctx_out, "out_sample_rate", s->ctx.out_rate, 0);
+
+#if USE_SET_CHANNEL_MAPPING
+ // API has weird requirements, quoting avresample.h:
+ // * This function can only be called when the allocated context is not open.
+ // * Also, the input channel layout must have already been set.
+ avresample_set_channel_mapping(s->avrctx, s->reorder_in);
+ avresample_set_channel_mapping(s->avrctx_out, s->reorder_out);
+#endif
+
+ if (avresample_open(s->avrctx) < 0 ||
+ avresample_open(s->avrctx_out) < 0)
+ {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot open "
+ "Libavresample Context. \n");
+ return AF_ERROR;
+ }
+ }
+
+ return ((in->format == orig_in.format) &&
+ mp_chmap_equals(&in->channels, &orig_in.channels))
+ ? AF_OK : AF_FALSE;
+ }
+ case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET: {
+ if (af_to_avformat(*(int*)arg) == AV_SAMPLE_FMT_NONE)
+ return AF_FALSE;
+
+ mp_audio_set_format(af->data, *(int*)arg);
+ return AF_OK;
+ }
+ case AF_CONTROL_CHANNELS | AF_CONTROL_SET: {
+ mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
+ return AF_OK;
+ }
+ case AF_CONTROL_COMMAND_LINE: {
+ s->opts.cutoff = 0.0;
+
+ const opt_t subopts[] = {
+ {"srate", OPT_ARG_INT, &out->rate, NULL},
+ {"filter_size", OPT_ARG_INT, &s->opts.filter_size, NULL},
+ {"phase_shift", OPT_ARG_INT, &s->opts.phase_shift, NULL},
+ {"linear", OPT_ARG_BOOL, &s->opts.linear, NULL},
+ {"cutoff", OPT_ARG_FLOAT, &s->opts.cutoff, NULL},
+ {"detach", OPT_ARG_BOOL, &s->allow_detach, NULL},
+ {0}
+ };
+
+ if (subopt_parse(arg, subopts) != 0) {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Invalid option "
+ "specified.\n");
+ return AF_ERROR;
+ }
+
+ if (s->opts.cutoff <= 0.0)
+ s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size);
+ return AF_OK;
+ }
+ case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
+ out->rate = *(int *)arg;
+ return AF_OK;
+ }
+ return AF_UNKNOWN;
+}
+
+#undef ctx_opt_set_int
+#undef ctx_opt_set_dbl
+
+static void uninit(struct af_instance *af)
+{
+ if (af->setup) {
+ struct af_resample *s = af->setup;
+ if (s->avrctx)
+ avresample_close(s->avrctx);
+ if (s->avrctx_out)
+ avresample_close(s->avrctx_out);
+ talloc_free(af->setup);
+ }
+}
+
+static bool needs_reorder(int *reorder, int num_ch)
+{
+ for (int n = 0; n < num_ch; n++) {
+ if (reorder[n] != n)
+ return true;
+ }
+ return false;
+}
+
+static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
+{
+ struct af_resample *s = af->setup;
+ struct mp_audio *in = data;
+ struct mp_audio *out = af->data;
+
+
+ int in_size = data->len;
+ int in_samples = in_size / (data->bps * data->nch);
+ int out_samples = avresample_available(s->avrctx) +
+ av_rescale_rnd(get_delay(s) + in_samples,
+ s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP);
+ int out_size = out->bps * out_samples * out->nch;
+
+ if (talloc_get_size(out->audio) < out_size)
+ out->audio = talloc_realloc_size(out, out->audio, out_size);
+
+ af->delay = out->bps * av_rescale_rnd(get_delay(s),
+ s->ctx.out_rate, s->ctx.in_rate,
+ AV_ROUND_UP);
+
+#if !USE_SET_CHANNEL_MAPPING
+ reorder_channels(data->audio, s->reorder_in, data->bps, data->nch, in_samples);
+#endif
+
+ out_samples = avresample_convert(s->avrctx,
+ (uint8_t **) &out->audio, out_size, out_samples,
+ (uint8_t **) &in->audio, in_size, in_samples);
+
+ *data = *out;
+
+#if USE_SET_CHANNEL_MAPPING
+ if (needs_reorder(s->reorder_out, out->nch)) {
+ if (talloc_get_size(s->reorder_buffer) < out_size)
+ s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
+ data->audio = s->reorder_buffer;
+ out_samples = avresample_convert(s->avrctx_out,
+ (uint8_t **) &data->audio, out_size, out_samples,
+ (uint8_t **) &out->audio, out_size, out_samples);
+ }
+#else
+ reorder_channels(data->audio, s->reorder_out, out->bps, out->nch, out_samples);
+#endif
+
+ data->len = out->bps * out_samples * out->nch;
+ return data;
+}
+
+static int af_open(struct af_instance *af)
+{
+ struct af_resample *s = talloc_zero(NULL, struct af_resample);
+
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul = 1;
+ af->data = talloc_zero(s, struct mp_audio);
+
+ af->data->rate = 0;
+
+ int default_filter_size = 16;
+ s->opts = (struct af_resample_opts) {
+ .linear = 0,
+ .filter_size = default_filter_size,
+ .cutoff = af_resample_default_cutoff(default_filter_size),
+ .phase_shift = 10,
+ };
+
+ s->allow_detach = 1;
+
+ s->avrctx = avresample_alloc_context();
+ s->avrctx_out = avresample_alloc_context();
+ af->setup = s;
+
+ if (s->avrctx && s->avrctx_out) {
+ return AF_OK;
+ } else {
+ mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot initialize "
+ "Libavresample Context. \n");
+ uninit(af);
+ return AF_ERROR;
+ }
+}
+
+struct af_info af_info_lavrresample = {
+ "Sample frequency conversion using libavresample",
+ "lavrresample",
+ "Stefano Pigozzi (based on Michael Niedermayer's lavcresample)",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open,
+ .test_conversion = test_conversion,
+};
diff --git a/audio/filter/af_pan.c b/audio/filter/af_pan.c
index 8b1783ee84..d6f7538868 100644
--- a/audio/filter/af_pan.c
+++ b/audio/filter/af_pan.c
@@ -34,6 +34,15 @@ typedef struct af_pan_s
float level[AF_NCH][AF_NCH]; // Gain level for each channel
}af_pan_t;
+static void set_channels(struct mp_audio *mpa, int num)
+{
+ struct mp_chmap map;
+ // "unknown" channel layouts make it easier to pass through audio data,
+ // without triggering remixing.
+ mp_chmap_set_unknown(&map, num);
+ mp_audio_set_channels(mpa, &map);
+}
+
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
@@ -45,15 +54,13 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
- af->data->nch = s->nch ? s->nch: ((struct mp_audio*)arg)->nch;
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
+ set_channels(af->data, s->nch ? s->nch: ((struct mp_audio*)arg)->nch);
af->mul = (double)af->data->nch / ((struct mp_audio*)arg)->nch;
if((af->data->format != ((struct mp_audio*)arg)->format) ||
(af->data->bps != ((struct mp_audio*)arg)->bps)){
- ((struct mp_audio*)arg)->format = af->data->format;
- ((struct mp_audio*)arg)->bps = af->data->bps;
+ mp_audio_set_format((struct mp_audio*)arg, af->data->format);
return AF_FALSE;
}
return AF_OK;
@@ -109,14 +116,11 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){
mp_msg(MSGT_AFILTER, MSGL_ERR, "[pan] The number of output channels must be"
- " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
+ " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]);
return AF_ERROR;
}
s->nch=((int*)arg)[0];
return AF_OK;
- case AF_CONTROL_PAN_NOUT | AF_CONTROL_GET:
- *(int*)arg = af->data->nch;
- return AF_OK;
case AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET:{
float val = *(float*)arg;
if (s->nch)
@@ -181,7 +185,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
// Set output data
c->audio = l->audio;
c->len = c->len / c->nch * l->nch;
- c->nch = l->nch;
+ set_channels(c, l->nch);
return c;
}
diff --git a/audio/filter/af_resample.c b/audio/filter/af_resample.c
deleted file mode 100644
index 1f0b7cc942..0000000000
--- a/audio/filter/af_resample.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * This audio filter changes the sample rate.
- *
- * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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 <inttypes.h>
-
-#include "libavutil/common.h"
-#include "libavutil/mathematics.h"
-#include "af.h"
-#include "dsp.h"
-
-/* Below definition selects the length of each poly phase component.
- Valid definitions are L8 and L16, where the number denotes the
- length of the filter. This definition affects the computational
- complexity (see play()), the performance (see filter.h) and the
- memory usage. The filter length is chosen to 8 if the machine is
- slow and to 16 if the machine is fast and has MMX.
-*/
-
-#if !HAVE_MMX // This machine is slow
-#define L8
-#else
-#define L16
-#endif
-
-#include "af_resample_template.c"
-
-// Filtering types
-#define RSMP_LIN (0<<0) // Linear interpolation
-#define RSMP_INT (1<<0) // 16 bit integer
-#define RSMP_FLOAT (2<<0) // 32 bit floating point
-#define RSMP_MASK (3<<0)
-
-// Defines for sloppy or exact resampling
-#define FREQ_SLOPPY (0<<2)
-#define FREQ_EXACT (1<<2)
-#define FREQ_MASK (1<<2)
-
-// Accuracy for linear interpolation
-#define STEPACCURACY 32
-
-// local data
-typedef struct af_resample_s
-{
- void* w; // Current filter weights
- void** xq; // Circular buffers
- uint32_t xi; // Index for circular buffers
- uint32_t wi; // Index for w
- uint32_t i; // Number of new samples to put in x queue
- uint32_t dn; // Down sampling factor
- uint32_t up; // Up sampling factor
- uint64_t step; // Step size for linear interpolation
- uint64_t pt; // Pointer remainder for linear interpolation
- int setup; // Setup parameters cmdline or through postcreate
-} af_resample_t;
-
-// Fast linear interpolation resample with modest audio quality
-static int linint(struct mp_audio* c,struct mp_audio* l, af_resample_t* s)
-{
- uint32_t len = 0; // Number of input samples
- uint32_t nch = l->nch; // Words pre transfer
- uint64_t step = s->step;
- int16_t* in16 = ((int16_t*)c->audio);
- int16_t* out16 = ((int16_t*)l->audio);
- int32_t* in32 = ((int32_t*)c->audio);
- int32_t* out32 = ((int32_t*)l->audio);
- uint64_t end = ((((uint64_t)c->len)/2LL)<<STEPACCURACY);
- uint64_t pt = s->pt;
- uint16_t tmp;
-
- switch (nch){
- case 1:
- while(pt < end){
- out16[len++]=in16[pt>>STEPACCURACY];
- pt+=step;
- }
- s->pt=pt & ((1LL<<STEPACCURACY)-1);
- break;
- case 2:
- end/=2;
- while(pt < end){
- out32[len++]=in32[pt>>STEPACCURACY];
- pt+=step;
- }
- len=(len<<1);
- s->pt=pt & ((1LL<<STEPACCURACY)-1);
- break;
- default:
- end /=nch;
- while(pt < end){
- tmp=nch;
- do {
- tmp--;
- out16[len+tmp]=in16[tmp+(pt>>STEPACCURACY)*nch];
- } while (tmp);
- len+=nch;
- pt+=step;
- }
- s->pt=pt & ((1LL<<STEPACCURACY)-1);
- }
- return len;
-}
-
-/* Determine resampling type and format */
-static int set_types(struct af_instance* af, struct mp_audio* data)
-{
- af_resample_t* s = af->setup;
- int rv = AF_OK;
- float rd = 0;
-
- // Make sure this filter isn't redundant
- if((af->data->rate == data->rate) || (af->data->rate == 0))
- return AF_DETACH;
- /* If sloppy and small resampling difference (2%) */
- rd = abs((float)af->data->rate - (float)data->rate)/(float)data->rate;
- if((((s->setup & FREQ_MASK) == FREQ_SLOPPY) && (rd < 0.02) &&
- (data->format != (AF_FORMAT_FLOAT_NE))) ||
- ((s->setup & RSMP_MASK) == RSMP_LIN)){
- s->setup = (s->setup & ~RSMP_MASK) | RSMP_LIN;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
- mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Using linear interpolation. \n");
- }
- else{
- /* If the input format is float or if float is explicitly selected
- use float, otherwise use int */
- if((data->format == (AF_FORMAT_FLOAT_NE)) ||
- ((s->setup & RSMP_MASK) == RSMP_FLOAT)){
- s->setup = (s->setup & ~RSMP_MASK) | RSMP_FLOAT;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
- }
- else{
- s->setup = (s->setup & ~RSMP_MASK) | RSMP_INT;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
- }
- mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Using %s processing and %s frequecy"
- " conversion.\n",
- ((s->setup & RSMP_MASK) == RSMP_FLOAT)?"floating point":"integer",
- ((s->setup & FREQ_MASK) == FREQ_SLOPPY)?"inexact":"exact");
- }
-
- if(af->data->format != data->format || af->data->bps != data->bps)
- rv = AF_FALSE;
- data->format = af->data->format;
- data->bps = af->data->bps;
- af->data->nch = data->nch;
- return rv;
-}
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- switch(cmd){
- case AF_CONTROL_REINIT:{
- af_resample_t* s = af->setup;
- struct mp_audio* n = arg; // New configuration
- int i,d = 0;
- int rv = AF_OK;
-
- // Free space for circular buffers
- if(s->xq){
- free(s->xq[0]);
- free(s->xq);
- s->xq = NULL;
- }
-
- if(AF_DETACH == (rv = set_types(af,n)))
- return AF_DETACH;
-
- // If linear interpolation
- if((s->setup & RSMP_MASK) == RSMP_LIN){
- s->pt=0LL;
- s->step=((uint64_t)n->rate<<STEPACCURACY)/(uint64_t)af->data->rate+1LL;
- mp_msg(MSGT_AFILTER, MSGL_DBG2, "[resample] Linear interpolation step: 0x%016"PRIX64".\n",
- s->step);
- af->mul = (double)af->data->rate / n->rate;
- return rv;
- }
-
- // Calculate up and down sampling factors
- d=av_gcd(af->data->rate,n->rate);
-
- // If sloppy resampling is enabled limit the upsampling factor
- if(((s->setup & FREQ_MASK) == FREQ_SLOPPY) && (af->data->rate/d > 5000)){
- int up=af->data->rate/2;
- int dn=n->rate/2;
- int m=2;
- while(af->data->rate/(d*m) > 5000){
- d=av_gcd(up,dn);
- up/=2; dn/=2; m*=2;
- }
- d*=m;
- }
-
- // Create space for circular buffers
- s->xq = malloc(n->nch*sizeof(void*));
- s->xq[0] = calloc(n->nch, 2*L*af->data->bps);
- for(i=1;i<n->nch;i++)
- s->xq[i] = (uint8_t *)s->xq[i-1] + 2*L*af->data->bps;
- s->xi = 0;
-
- // Check if the design needs to be redone
- if(s->up != af->data->rate/d || s->dn != n->rate/d){
- float* w;
- float* wt;
- float fc;
- int j;
- s->up = af->data->rate/d;
- s->dn = n->rate/d;
- s->wi = 0;
- s->i = 0;
-
- // Calculate cutoff frequency for filter
- fc = 1/(float)(max(s->up,s->dn));
- // Allocate space for polyphase filter bank and prototype filter
- w = malloc(sizeof(float) * s->up *L);
- free(s->w);
- s->w = malloc(L*s->up*af->data->bps);
-
- // Design prototype filter type using Kaiser window with beta = 10
- if(NULL == w || NULL == s->w ||
- -1 == af_filter_design_fir(s->up*L, w, &fc, LP|KAISER , 10.0)){
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[resample] Unable to design prototype filter.\n");
- return AF_ERROR;
- }
- // Copy data from prototype to polyphase filter
- wt=w;
- for(j=0;j<L;j++){//Columns
- for(i=0;i<s->up;i++){//Rows
- if((s->setup & RSMP_MASK) == RSMP_INT){
- float t=(float)s->up*32767.0*(*wt);
- ((int16_t*)s->w)[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5));
- }
- else
- ((float*)s->w)[i*L+j] = (float)s->up*(*wt);
- wt++;
- }
- }
- free(w);
- mp_msg(MSGT_AFILTER, MSGL_V, "[resample] New filter designed up: %i "
- "down: %i\n", s->up, s->dn);
- }
-
- // Set multiplier and delay
- af->delay = 0; // not set correctly, but shouldn't be too large anyway
- af->mul = (double)s->up / s->dn;
- return rv;
- }
- case AF_CONTROL_COMMAND_LINE:{
- af_resample_t* s = af->setup;
- int rate=0;
- int type=RSMP_INT;
- int sloppy=1;
- sscanf((char*)arg,"%i:%i:%i", &rate, &sloppy, &type);
- s->setup = (sloppy?FREQ_SLOPPY:FREQ_EXACT) |
- (clamp(type,RSMP_LIN,RSMP_FLOAT));
- return af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET, &rate);
- }
- case AF_CONTROL_POST_CREATE:
- if((((struct af_cfg*)arg)->force & AF_INIT_FORMAT_MASK) == AF_INIT_FLOAT)
- ((af_resample_t*)af->setup)->setup = RSMP_FLOAT;
- return AF_OK;
- case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
- // Reinit must be called after this function has been called
-
- // Sanity check
- if(((int*)arg)[0] < 8000 || ((int*)arg)[0] > 192000){
- mp_msg(MSGT_AFILTER, MSGL_ERR, "[resample] The output sample frequency "
- "must be between 8kHz and 192kHz. Current value is %i \n",
- ((int*)arg)[0]);
- return AF_ERROR;
- }
-
- af->data->rate=((int*)arg)[0];
- mp_msg(MSGT_AFILTER, MSGL_V, "[resample] Changing sample rate "
- "to %iHz\n",af->data->rate);
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-// Deallocate memory
-static void uninit(struct af_instance* af)
-{
- af_resample_t *s = af->setup;
- if (s) {
- if (s->xq) free(s->xq[0]);
- free(s->xq);
- free(s->w);
- free(s);
- }
- if(af->data)
- free(af->data->audio);
- free(af->data);
-}
-
-// Filter data through filter
-static struct mp_audio* play(struct af_instance* af, struct mp_audio* data)
-{
- int len = 0; // Length of output data
- struct mp_audio* c = data; // Current working data
- struct mp_audio* l = af->data; // Local data
- af_resample_t* s = af->setup;
-
- if(AF_OK != RESIZE_LOCAL_BUFFER(af,data))
- return NULL;
-
- // Run resampling
- switch(s->setup & RSMP_MASK){
- case(RSMP_INT):
-# define FORMAT_I 1
- if(s->up>s->dn){
-# define UP
-# include "af_resample_template.c"
-# undef UP
- }
- else{
-# define DN
-# include "af_resample_template.c"
-# undef DN
- }
- break;
- case(RSMP_FLOAT):
-# undef FORMAT_I
-# define FORMAT_F 1
- if(s->up>s->dn){
-# define UP
-# include "af_resample_template.c"
-# undef UP
- }
- else{
-# define DN
-# include "af_resample_template.c"
-# undef DN
- }
- break;
- case(RSMP_LIN):
- len = linint(c, l, s);
- break;
- }
-
- // Set output data
- c->audio = l->audio;
- c->len = len*l->bps;
- c->rate = l->rate;
-
- return c;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance* af){
- af->control=control;
- af->uninit=uninit;
- af->play=play;
- af->mul=1;
- af->data=calloc(1,sizeof(struct mp_audio));
- af->setup=calloc(1,sizeof(af_resample_t));
- if(af->data == NULL || af->setup == NULL)
- return AF_ERROR;
- ((af_resample_t*)af->setup)->setup = RSMP_INT | FREQ_SLOPPY;
- return AF_OK;
-}
-
-// Description of this plugin
-struct af_info af_info_resample = {
- "Sample frequency conversion",
- "resample",
- "Anders",
- "",
- AF_FLAGS_REENTRANT,
- af_open
-};
diff --git a/audio/filter/af_resample_template.c b/audio/filter/af_resample_template.c
deleted file mode 100644
index 4d4c5922ca..0000000000
--- a/audio/filter/af_resample_template.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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.
- */
-
-/* This file contains the resampling engine, the sample format is
- controlled by the FORMAT parameter, the filter length by the L
- parameter and the resampling type by UP and DN. This file should
- only be included by af_resample.c
-*/
-
-#undef L
-#undef SHIFT
-#undef FORMAT
-#undef FIR
-#undef ADDQUE
-
-/* The length Lxx definition selects the length of each poly phase
- component. Valid definitions are L8 and L16 where the number
- defines the nuber of taps. This definition affects the
- computational complexity, the performance and the memory usage.
-*/
-
-/* The FORMAT_x parameter selects the sample format type currently
- float and int16 are supported. Thes two formats are selected by
- defining eiter FORMAT_F or FORMAT_I. The advantage of using float
- is that the amplitude and therefore the SNR isn't affected by the
- filtering, the disadvantage is that it is a lot slower.
-*/
-
-#if defined(FORMAT_I)
-#define SHIFT >>16
-#define FORMAT int16_t
-#else
-#define SHIFT
-#define FORMAT float
-#endif
-
-// Short filter
-#if defined(L8)
-
-#define L 8 // Filter length
-// Unrolled loop to speed up execution
-#define FIR(x,w,y) \
- (y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \
- + w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) SHIFT
-
-
-
-#else /* L8/L16 */
-
-#define L 16
-// Unrolled loop to speed up execution
-#define FIR(x,w,y) \
- y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \
- + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \
- + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \
- + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) SHIFT
-
-#endif /* L8/L16 */
-
-// Macro to add data to circular que
-#define ADDQUE(xi,xq,in)\
- xq[xi]=xq[(xi)+L]=*(in);\
- xi=((xi)-1)&(L-1);
-
-#if defined(UP)
-
- uint32_t ci = l->nch; // Index for channels
- uint32_t nch = l->nch; // Number of channels
- uint32_t inc = s->up/s->dn;
- uint32_t level = s->up%s->dn;
- uint32_t up = s->up;
- uint32_t dn = s->dn;
- uint32_t ns = c->len/l->bps;
- register FORMAT* w = s->w;
-
- register uint32_t wi = 0;
- register uint32_t xi = 0;
-
- // Index current channel
- while(ci--){
- // Temporary pointers
- register FORMAT* x = s->xq[ci];
- register FORMAT* in = ((FORMAT*)c->audio)+ci;
- register FORMAT* out = ((FORMAT*)l->audio)+ci;
- FORMAT* end = in+ns; // Block loop end
- wi = s->wi; xi = s->xi;
-
- while(in < end){
- register uint32_t i = inc;
- if(wi<level) i++;
-
- ADDQUE(xi,x,in);
- in+=nch;
- while(i--){
- // Run the FIR filter
- FIR((&x[xi]),(&w[wi*L]),out);
- len++; out+=nch;
- // Update wi to point at the correct polyphase component
- wi=(wi+dn)%up;
- }
- }
-
- }
- // Save values that needs to be kept for next time
- s->wi = wi;
- s->xi = xi;
-#endif /* UP */
-
-#if defined(DN) /* DN */
- uint32_t ci = l->nch; // Index for channels
- uint32_t nch = l->nch; // Number of channels
- uint32_t inc = s->dn/s->up;
- uint32_t level = s->dn%s->up;
- uint32_t up = s->up;
- uint32_t dn = s->dn;
- uint32_t ns = c->len/l->bps;
- FORMAT* w = s->w;
-
- register int32_t i = 0;
- register uint32_t wi = 0;
- register uint32_t xi = 0;
-
- // Index current channel
- while(ci--){
- // Temporary pointers
- register FORMAT* x = s->xq[ci];
- register FORMAT* in = ((FORMAT*)c->audio)+ci;
- register FORMAT* out = ((FORMAT*)l->audio)+ci;
- register FORMAT* end = in+ns; // Block loop end
- i = s->i; wi = s->wi; xi = s->xi;
-
- while(in < end){
-
- ADDQUE(xi,x,in);
- in+=nch;
- if((--i)<=0){
- // Run the FIR filter
- FIR((&x[xi]),(&w[wi*L]),out);
- len++; out+=nch;
-
- // Update wi to point at the correct polyphase component
- wi=(wi+dn)%up;
-
- // Insert i number of new samples in queue
- i = inc;
- if(wi<level) i++;
- }
- }
- }
- // Save values that needs to be kept for next time
- s->wi = wi;
- s->xi = xi;
- s->i = i;
-#endif /* DN */
diff --git a/audio/filter/af_scaletempo.c b/audio/filter/af_scaletempo.c
index cf326fedfb..5cf0f3b082 100644
--- a/audio/filter/af_scaletempo.c
+++ b/audio/filter/af_scaletempo.c
@@ -302,26 +302,22 @@ static int control(struct af_instance* af, int cmd, void* arg)
"[scaletempo] %.3f speed * %.3f scale_nominal = %.3f\n",
s->speed, s->scale_nominal, s->scale);
+ mp_audio_copy_config(af->data, data);
+
if (s->scale == 1.0) {
if (s->speed_tempo && s->speed_pitch)
return AF_DETACH;
- memcpy(af->data, data, sizeof(struct mp_audio));
af->delay = 0;
af->mul = 1;
return af_test_output(af, data);
}
- af->data->rate = data->rate;
- af->data->nch = data->nch;
- if ( data->format == AF_FORMAT_S16_LE
- || data->format == AF_FORMAT_S16_BE ) {
+ if (data->format == AF_FORMAT_S16_NE) {
use_int = 1;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = bps = 2;
} else {
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = bps = 4;
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
+ bps = af->data->bps;
frames_stride = srate * s->ms_stride;
s->bytes_stride = frames_stride * bps * nch;
diff --git a/audio/filter/af_sinesuppress.c b/audio/filter/af_sinesuppress.c
index 36f7189f00..10f0b650ec 100644
--- a/audio/filter/af_sinesuppress.c
+++ b/audio/filter/af_sinesuppress.c
@@ -54,8 +54,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = 1;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_num_channels(af->data, 1);
#if 0
if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT_NE)
{
@@ -65,8 +65,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
}// else
#endif
{
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
af->play = play_s16;
}
@@ -79,18 +78,6 @@ static int control(struct af_instance* af, int cmd, void* arg)
s->decay = f2;
return AF_OK;
}
- case AF_CONTROL_SS_FREQ | AF_CONTROL_SET:
- s->freq = *(float*)arg;
- return AF_OK;
- case AF_CONTROL_SS_FREQ | AF_CONTROL_GET:
- *(float*)arg = s->freq;
- return AF_OK;
- case AF_CONTROL_SS_DECAY | AF_CONTROL_SET:
- s->decay = *(float*)arg;
- return AF_OK;
- case AF_CONTROL_SS_DECAY | AF_CONTROL_GET:
- *(float*)arg = s->decay;
- return AF_OK;
}
return AF_UNKNOWN;
}
diff --git a/audio/filter/af_sub.c b/audio/filter/af_sub.c
index 4af28d9141..a985ac2a05 100644
--- a/audio/filter/af_sub.c
+++ b/audio/filter/af_sub.c
@@ -70,9 +70,8 @@ static int control(struct af_instance* af, int cmd, void* arg)
if(!arg) return AF_ERROR;
af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = max(s->ch+1,((struct mp_audio*)arg)->nch);
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_set_channels_old(af->data, max(s->ch+1,((struct mp_audio*)arg)->nch));
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
// Design low-pass filter
s->k = 1.0;
diff --git a/audio/filter/af_surround.c b/audio/filter/af_surround.c
index 57288d6ba2..c04a039d65 100644
--- a/audio/filter/af_surround.c
+++ b/audio/filter/af_surround.c
@@ -92,10 +92,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
switch(cmd){
case AF_CONTROL_REINIT:{
float fc;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch*2;
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
+ mp_audio_set_channels_old(af->data, ((struct mp_audio*)arg)->nch*2);
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
if (af->data->nch != 4){
mp_msg(MSGT_AFILTER, MSGL_ERR, "[surround] Only stereo input is supported.\n");
@@ -125,8 +124,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
if((af->data->format != ((struct mp_audio*)arg)->format) ||
(af->data->bps != ((struct mp_audio*)arg)->bps)){
- ((struct mp_audio*)arg)->format = af->data->format;
- ((struct mp_audio*)arg)->bps = af->data->bps;
+ mp_audio_set_format((struct mp_audio*)arg, af->data->format);
return AF_FALSE;
}
return AF_OK;
@@ -244,7 +242,7 @@ static struct mp_audio* play(struct af_instance* af, struct mp_audio* data){
// Set output data
data->audio = af->data->audio;
data->len *= 2;
- data->nch = af->data->nch;
+ mp_audio_set_channels_old(data, af->data->nch);
return data;
}
diff --git a/audio/filter/af_sweep.c b/audio/filter/af_sweep.c
index 6d1106fefc..6cc099f2d8 100644
--- a/audio/filter/af_sweep.c
+++ b/audio/filter/af_sweep.c
@@ -41,12 +41,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
switch(cmd){
case AF_CONTROL_REINIT:
- af->data->nch = data->nch;
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
- af->data->rate = data->rate;
+ mp_audio_copy_config(af->data, data);
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
- return AF_OK;
+ return af_test_output(af, data);
case AF_CONTROL_COMMAND_LINE:
sscanf((char*)arg,"%lf", &s->delta);
return AF_OK;
diff --git a/audio/filter/af_tools.c b/audio/filter/af_tools.c
index 0d5dc6c573..77fdad55f2 100644
--- a/audio/filter/af_tools.c
+++ b/audio/filter/af_tools.c
@@ -90,8 +90,8 @@ int af_test_output(struct af_instance* af, struct mp_audio* out)
if((af->data->format != out->format) ||
(af->data->bps != out->bps) ||
(af->data->rate != out->rate) ||
- (af->data->nch != out->nch)){
- memcpy(out,af->data,sizeof(struct mp_audio));
+ !mp_chmap_equals(&af->data->channels, &out->channels)){
+ *out = *af->data;
return AF_FALSE;
}
return AF_OK;
diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c
index ecf181c8b8..82c31eaa12 100644
--- a/audio/filter/af_volume.c
+++ b/audio/filter/af_volume.c
@@ -66,12 +66,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
// Sanity check
if(!arg) return AF_ERROR;
- af->data->rate = ((struct mp_audio*)arg)->rate;
- af->data->nch = ((struct mp_audio*)arg)->nch;
+ mp_audio_copy_config(af->data, (struct mp_audio*)arg);
if(s->fast && (((struct mp_audio*)arg)->format != (AF_FORMAT_FLOAT_NE))){
- af->data->format = AF_FORMAT_S16_NE;
- af->data->bps = 2;
+ mp_audio_set_format(af->data, AF_FORMAT_S16_NE);
}
else{
// Cutoff set to 10Hz for forgetting factor
@@ -79,42 +77,21 @@ static int control(struct af_instance* af, int cmd, void* arg)
float t = 2.0-cos(x);
s->time = 1.0 - (t - sqrt(t*t - 1));
mp_msg(MSGT_AFILTER, MSGL_DBG2, "[volume] Forgetting factor = %0.5f\n",s->time);
- af->data->format = AF_FORMAT_FLOAT_NE;
- af->data->bps = 4;
+ mp_audio_set_format(af->data, AF_FORMAT_FLOAT_NE);
}
return af_test_output(af,(struct mp_audio*)arg);
case AF_CONTROL_COMMAND_LINE:{
float v=0.0;
float vol[AF_NCH];
int i;
- sscanf((char*)arg,"%f:%i", &v, &s->soft);
+ sscanf((char*)arg,"%f:%i:%i", &v, &s->soft, &s->fast);
for(i=0;i<AF_NCH;i++) vol[i]=v;
return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol);
}
- case AF_CONTROL_POST_CREATE:
- s->fast = ((((struct af_cfg*)arg)->force & AF_INIT_FORMAT_MASK) ==
- AF_INIT_FLOAT) ? 0 : 1;
- return AF_OK;
- case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET:
- memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int));
- return AF_OK;
- case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET:
- memcpy((int*)arg,s->enable,AF_NCH*sizeof(int));
- return AF_OK;
- case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET:
- s->soft = *(int*)arg;
- return AF_OK;
- case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET:
- *(int*)arg = s->soft;
- return AF_OK;
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET:
return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0);
case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET:
return af_to_dB(AF_NCH,s->level,(float*)arg,20.0);
- case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET:
- return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0);
- case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET:
- return af_to_dB(AF_NCH,s->max,(float*)arg,10.0);
case AF_CONTROL_PRE_DESTROY:{
float m = 0.0;
int i;
@@ -122,7 +99,7 @@ static int control(struct af_instance* af, int cmd, void* arg)
for(i=0;i<AF_NCH;i++)
m=max(m,s->max[i]);
af_to_dB(1, &m, &m, 10.0);
- mp_msg(MSGT_AFILTER, MSGL_INFO, "[volume] The maximum volume was %0.2fdB \n", m);
+ mp_msg(MSGT_AFILTER, MSGL_V, "[volume] The maximum volume was %0.2fdB \n", m);
}
return AF_OK;
}
diff --git a/audio/filter/control.h b/audio/filter/control.h
index 323b9a3924..aa1900d106 100644
--- a/audio/filter/control.h
+++ b/audio/filter/control.h
@@ -22,48 +22,6 @@
#include <sys/types.h>
/*********************************************
-// Control info struct.
-//
-// This struct is the argument in a info call to a filter.
-*/
-
-// Argument types
-#define AF_CONTROL_TYPE_BOOL (0x0<<0)
-#define AF_CONTROL_TYPE_CHAR (0x1<<0)
-#define AF_CONTROL_TYPE_INT (0x2<<0)
-#define AF_CONTROL_TYPE_FLOAT (0x3<<0)
-#define AF_CONTROL_TYPE_STRUCT (0x4<<0)
-#define AF_CONTROL_TYPE_SPECIAL (0x5<<0) // a pointer to a function for example
-#define AF_CONTROL_TYPE_MASK (0x7<<0)
-// Argument geometry
-#define AF_CONTROL_GEOM_SCALAR (0x0<<3)
-#define AF_CONTROL_GEOM_ARRAY (0x1<<3)
-#define AF_CONTROL_GEOM_MATRIX (0x2<<3)
-#define AF_CONTROL_GEOM_MASK (0x3<<3)
-// Argument properties
-#define AF_CONTROL_PROP_READ (0x0<<5) // The argument can be read
-#define AF_CONTROL_PROP_WRITE (0x1<<5) // The argument can be written
-#define AF_CONTROL_PROP_SAVE (0x2<<5) // Can be saved
-#define AF_CONTROL_PROP_RUNTIME (0x4<<5) // Acessable during execution
-#define AF_CONTROL_PROP_CHANNEL (0x8<<5) // Argument is set per channel
-#define AF_CONTROL_PROP_MASK (0xF<<5)
-
-typedef struct af_control_info_s{
- int def; // Control enumrification
- char* name; // Name of argument
- char* info; // Description of what it does
- int flags; // Flags as defined above
- float max; // Max and min value
- float min; // (only aplicable on float and int)
- int xdim; // 1st dimension
- int ydim; // 2nd dimension (=0 for everything except matrix)
- size_t sz; // Size of argument in bytes
- int ch; // Channel number (for future use)
- void* arg; // Data (for future use)
-}af_control_info_t;
-
-
-/*********************************************
// Extended control used with arguments that operates on only one
// channel at the time
*/
@@ -98,11 +56,6 @@ typedef struct af_control_ext_s{
// OPTIONAL CALLS
-/* Called just after creation with the af_cfg for the stream in which
- the filter resides as input parameter this call can be used by the
- filter to initialize itself */
-#define AF_CONTROL_POST_CREATE 0x00000100 | AF_CONTROL_OPTIONAL
-
// Called just before destruction of a filter
#define AF_CONTROL_PRE_DESTROY 0x00000200 | AF_CONTROL_OPTIONAL
@@ -119,20 +72,12 @@ typedef struct af_control_ext_s{
#define AF_CONTROL_SET 0x00000000
// Get argument
#define AF_CONTROL_GET 0x00000001
-// Get info about the control, i.e fill in everything except argument
-#define AF_CONTROL_INFO 0x00000002
// Resample
// Set output rate in resample
#define AF_CONTROL_RESAMPLE_RATE 0x00000100 | AF_CONTROL_FILTER_SPECIFIC
-// Enable sloppy resampling
-#define AF_CONTROL_RESAMPLE_SLOPPY 0x00000200 | AF_CONTROL_FILTER_SPECIFIC
-
-// Set resampling accuracy
-#define AF_CONTROL_RESAMPLE_ACCURACY 0x00000300 | AF_CONTROL_FILTER_SPECIFIC
-
// Format
#define AF_CONTROL_FORMAT_FMT 0x00000400 | AF_CONTROL_FILTER_SPECIFIC
@@ -142,69 +87,11 @@ typedef struct af_control_ext_s{
// Set number of output channels in channels
#define AF_CONTROL_CHANNELS 0x00000600 | AF_CONTROL_FILTER_SPECIFIC
-// Set number of channel routes
-#define AF_CONTROL_CHANNELS_ROUTES 0x00000700 | AF_CONTROL_FILTER_SPECIFIC
-
-// Set channel routing pair, arg is int[2] and ch is used
-#define AF_CONTROL_CHANNELS_ROUTING 0x00000800 | AF_CONTROL_FILTER_SPECIFIC
-
-// Set nuber of channel routing pairs, arg is int*
-#define AF_CONTROL_CHANNELS_NR 0x00000900 | AF_CONTROL_FILTER_SPECIFIC
-
-// Set make af_channels into a router
-#define AF_CONTROL_CHANNELS_ROUTER 0x00000A00 | AF_CONTROL_FILTER_SPECIFIC
-
// Volume
-// Turn volume control on and off, arg is int*
-#define AF_CONTROL_VOLUME_ON_OFF 0x00000B00 | AF_CONTROL_FILTER_SPECIFIC
-
-// Turn soft clipping of the volume on and off, arg is binary
-#define AF_CONTROL_VOLUME_SOFTCLIP 0x00000C00 | AF_CONTROL_FILTER_SPECIFIC
-
// Set volume level, arg is a float* with the volume for all the channels
#define AF_CONTROL_VOLUME_LEVEL 0x00000D00 | AF_CONTROL_FILTER_SPECIFIC
-// Probed power level for all channels, arg is a float*
-#define AF_CONTROL_VOLUME_PROBE 0x00000E00 | AF_CONTROL_FILTER_SPECIFIC
-
-// Maximum probed power level for all channels, arg is a float*
-#define AF_CONTROL_VOLUME_PROBE_MAX 0x00000F00 | AF_CONTROL_FILTER_SPECIFIC
-
-// Compressor/expander
-
-// Turn compressor/expander on and off
-#define AF_CONTROL_COMP_ON_OFF 0x00001000 | AF_CONTROL_FILTER_SPECIFIC
-
-// Compression/expansion threshold [dB]
-#define AF_CONTROL_COMP_THRESH 0x00001100 | AF_CONTROL_FILTER_SPECIFIC
-
-// Compression/expansion attack time [ms]
-#define AF_CONTROL_COMP_ATTACK 0x00001200 | AF_CONTROL_FILTER_SPECIFIC
-
-// Compression/expansion release time [ms]
-#define AF_CONTROL_COMP_RELEASE 0x00001300 | AF_CONTROL_FILTER_SPECIFIC
-
-// Compression/expansion gain level [dB]
-#define AF_CONTROL_COMP_RATIO 0x00001400 | AF_CONTROL_FILTER_SPECIFIC
-
-// Noise gate
-
-// Turn noise gate on an off
-#define AF_CONTROL_GATE_ON_OFF 0x00001500 | AF_CONTROL_FILTER_SPECIFIC
-
-// Noise gate threshold [dB]
-#define AF_CONTROL_GATE_THRESH 0x00001600 | AF_CONTROL_FILTER_SPECIFIC
-
-// Noise gate attack time [ms]
-#define AF_CONTROL_GATE_ATTACK 0x00001700 | AF_CONTROL_FILTER_SPECIFIC
-
-// Noise gate release time [ms]
-#define AF_CONTROL_GATE_RELEASE 0x00001800 | AF_CONTROL_FILTER_SPECIFIC
-
-// Noise gate release range level [dB]
-#define AF_CONTROL_GATE_RANGE 0x00001900 | AF_CONTROL_FILTER_SPECIFIC
-
// Pan
// Pan levels, arg is a control_ext with a float*
@@ -216,9 +103,6 @@ typedef struct af_control_ext_s{
// Balance, arg is float*; range -1 (left) to 1 (right), 0 center
#define AF_CONTROL_PAN_BALANCE 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC
-// Set equalizer gain, arg is a control_ext with a float*
-#define AF_CONTROL_EQUALIZER_GAIN 0x00001D00 | AF_CONTROL_FILTER_SPECIFIC
-
// Delay length in ms, arg is a control_ext with a float*
#define AF_CONTROL_DELAY_LEN 0x00001E00 | AF_CONTROL_FILTER_SPECIFIC
@@ -236,21 +120,10 @@ typedef struct af_control_ext_s{
// Export
#define AF_CONTROL_EXPORT_SZ 0x00003000 | AF_CONTROL_FILTER_SPECIFIC
-
-// ExtraStereo Multiplier
-#define AF_CONTROL_ES_MUL 0x00003100 | AF_CONTROL_FILTER_SPECIFIC
-
-
-// Center
-
// Channel number which to inster the filtered data, arg in int*
#define AF_CONTROL_CENTER_CH 0x00003200 | AF_CONTROL_FILTER_SPECIFIC
-// SineSuppress
-#define AF_CONTROL_SS_FREQ 0x00003300 | AF_CONTROL_FILTER_SPECIFIC
-#define AF_CONTROL_SS_DECAY 0x00003400 | AF_CONTROL_FILTER_SPECIFIC
-
#define AF_CONTROL_PLAYBACK_SPEED 0x00003500 | AF_CONTROL_FILTER_SPECIFIC
#define AF_CONTROL_SCALETEMPO_AMOUNT 0x00003600 | AF_CONTROL_FILTER_SPECIFIC
diff --git a/audio/fmt-conversion.c b/audio/fmt-conversion.c
new file mode 100644
index 0000000000..4c1055f118
--- /dev/null
+++ b/audio/fmt-conversion.c
@@ -0,0 +1,65 @@
+/*
+ * 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 "core/mp_msg.h"
+#include <libavutil/avutil.h>
+#include <libavutil/samplefmt.h>
+#include "format.h"
+#include "fmt-conversion.h"
+
+static const struct {
+ enum AVSampleFormat sample_fmt;
+ int fmt;
+} audio_conversion_map[] = {
+ {AV_SAMPLE_FMT_U8, AF_FORMAT_U8},
+ {AV_SAMPLE_FMT_S16, AF_FORMAT_S16_NE},
+ {AV_SAMPLE_FMT_S32, AF_FORMAT_S32_NE},
+ {AV_SAMPLE_FMT_FLT, AF_FORMAT_FLOAT_NE},
+ {AV_SAMPLE_FMT_DBL, AF_FORMAT_DOUBLE_NE},
+
+ {AV_SAMPLE_FMT_NONE, 0},
+};
+
+enum AVSampleFormat af_to_avformat(int fmt)
+{
+ int i;
+ enum AVSampleFormat sample_fmt;
+ for (i = 0; audio_conversion_map[i].fmt; i++)
+ if (audio_conversion_map[i].fmt == fmt)
+ break;
+ sample_fmt = audio_conversion_map[i].sample_fmt;
+ if (sample_fmt == AF_FORMAT_UNKNOWN)
+ mp_msg(MSGT_GLOBAL, MSGL_V, "Unsupported sample format: %s\n",
+ af_fmt2str_short(fmt));
+ return sample_fmt;
+}
+
+int af_from_avformat(enum AVSampleFormat sample_fmt)
+{
+ int i;
+ for (i = 0; audio_conversion_map[i].fmt; i++)
+ if (audio_conversion_map[i].sample_fmt == sample_fmt)
+ break;
+ int fmt = audio_conversion_map[i].fmt;
+ if (!fmt) {
+ const char *fmtname = av_get_sample_fmt_name(sample_fmt);
+ mp_msg(MSGT_GLOBAL, MSGL_ERR, "Unsupported AVSampleFormat %s (%d)\n",
+ fmtname ? fmtname : "INVALID", sample_fmt);
+ }
+ return fmt;
+}
diff --git a/demux/mp_taglists.h b/audio/fmt-conversion.h
index d23a982a93..7f2739f86f 100644
--- a/demux/mp_taglists.h
+++ b/audio/fmt-conversion.h
@@ -16,13 +16,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPLAYER_MP_TAGLISTS_H
-#define MPLAYER_MP_TAGLISTS_H
+#ifndef MPLAYER_SAMPLE_FMT_CONVERSION_H
+#define MPLAYER_SAMPLE_FMT_CONVERSION_H
-#include <libavcodec/avcodec.h>
+enum AVSampleFormat af_to_avformat(int fmt);
+int af_from_avformat(enum AVSampleFormat sample_fmt);
-unsigned int mp_taglist_override(enum CodecID id);
-unsigned int mp_taglist_video(enum CodecID id);
-unsigned int mp_taglist_audio(enum CodecID id);
-
-#endif /* MPLAYER_MP_TAGLISTS_H */
+#endif /* MPLAYER_SAMPLE_FMT_CONVERSION_H */
diff --git a/audio/format.c b/audio/format.c
index 9625857ada..5b1262956c 100644
--- a/audio/format.c
+++ b/audio/format.c
@@ -29,24 +29,17 @@
int af_fmt2bits(int format)
{
if (AF_FORMAT_IS_AC3(format)) return 16;
- return (format & AF_FORMAT_BITS_MASK)+8;
-// return (((format & AF_FORMAT_BITS_MASK)>>3)+1) * 8;
-#if 0
+ if (format == AF_FORMAT_UNKNOWN)
+ return 0;
switch(format & AF_FORMAT_BITS_MASK)
{
case AF_FORMAT_8BIT: return 8;
case AF_FORMAT_16BIT: return 16;
case AF_FORMAT_24BIT: return 24;
case AF_FORMAT_32BIT: return 32;
- case AF_FORMAT_48BIT: return 48;
+ case AF_FORMAT_64BIT: return 64;
}
-#endif
- return -1;
-}
-
-int af_bits2fmt(int bits)
-{
- return (bits/8 - 1) << 3;
+ return 0;
}
/* Convert format to str input str is a buffer for the
@@ -94,6 +87,9 @@ const struct af_fmt_entry af_fmtstr_table[] = {
{ "floatle", AF_FORMAT_FLOAT_LE },
{ "floatbe", AF_FORMAT_FLOAT_BE },
{ "floatne", AF_FORMAT_FLOAT_NE },
+ { "doublele", AF_FORMAT_DOUBLE_LE },
+ { "doublebe", AF_FORMAT_DOUBLE_BE },
+ { "doublene", AF_FORMAT_DOUBLE_NE },
{0}
};
diff --git a/audio/format.h b/audio/format.h
index a8249954f0..30a4aa1cea 100644
--- a/audio/format.h
+++ b/audio/format.h
@@ -53,8 +53,7 @@
#define AF_FORMAT_16BIT (1<<3)
#define AF_FORMAT_24BIT (2<<3)
#define AF_FORMAT_32BIT (3<<3)
-#define AF_FORMAT_40BIT (4<<3)
-#define AF_FORMAT_48BIT (5<<3)
+#define AF_FORMAT_64BIT (4<<3)
#define AF_FORMAT_BITS_MASK (7<<3)
// Special flags refering to non pcm data (note: 1<<6, 2<<6, 5<<6 unused)
@@ -85,6 +84,9 @@
#define AF_FORMAT_FLOAT_LE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE)
#define AF_FORMAT_FLOAT_BE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE)
+#define AF_FORMAT_DOUBLE_LE (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_LE)
+#define AF_FORMAT_DOUBLE_BE (AF_FORMAT_F|AF_FORMAT_64BIT|AF_FORMAT_BE)
+
#define AF_FORMAT_AC3_LE (AF_FORMAT_AC3|AF_FORMAT_16BIT|AF_FORMAT_LE)
#define AF_FORMAT_AC3_BE (AF_FORMAT_AC3|AF_FORMAT_16BIT|AF_FORMAT_BE)
@@ -99,6 +101,7 @@
#define AF_FORMAT_U32_NE AF_FORMAT_U32_BE
#define AF_FORMAT_S32_NE AF_FORMAT_S32_BE
#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_BE
+#define AF_FORMAT_DOUBLE_NE AF_FORMAT_DOUBLE_BE
#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_BE
#define AF_FORMAT_IEC61937_NE AF_FORMAT_IEC61937_BE
#else
@@ -109,6 +112,7 @@
#define AF_FORMAT_U32_NE AF_FORMAT_U32_LE
#define AF_FORMAT_S32_NE AF_FORMAT_S32_LE
#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_LE
+#define AF_FORMAT_DOUBLE_NE AF_FORMAT_DOUBLE_LE
#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_LE
#define AF_FORMAT_IEC61937_NE AF_FORMAT_IEC61937_LE
#endif
@@ -127,7 +131,6 @@ extern const struct af_fmt_entry af_fmtstr_table[];
int af_str2fmt_short(bstr str);
int af_fmt2bits(int format);
-int af_bits2fmt(int bits);
char* af_fmt2str(int format, char* str, int size);
const char* af_fmt2str_short(int format);
diff --git a/audio/mixer.c b/audio/mixer.c
index bdcb0cbc5c..0f1a7871d6 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -34,6 +34,7 @@ static void checkvolume(struct mixer *mixer)
if (mixer->softvol == SOFTVOL_AUTO) {
mixer->softvol = mixer->ao->per_application_mixer
+ || mixer->ao->no_persistent_volume
? SOFTVOL_NO : SOFTVOL_YES;
}
@@ -129,6 +130,7 @@ void mixer_setvolume(mixer_t *mixer, float l, float r)
if (!mixer->ao || mixer->muted_using_volume)
return;
setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
+ mixer->user_set_volume = true;
}
void mixer_getbothvolume(mixer_t *mixer, float *b)
@@ -151,6 +153,7 @@ void mixer_setmute(struct mixer *mixer, bool mute)
}
mixer->muted = mute;
mixer->muted_by_us = mute;
+ mixer->user_set_mute = true;
}
}
@@ -214,7 +217,7 @@ void mixer_setbalance(mixer_t *mixer, float val)
AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &val))
return;
- if (val == 0 || mixer->ao->channels < 2)
+ if (val == 0 || mixer->ao->channels.num < 2)
return;
if (!(af_pan_balance = af_add(mixer->afilter, "pan"))) {
@@ -263,6 +266,8 @@ void mixer_reinit(struct mixer *mixer, struct ao *ao)
mixer_setmute(mixer, true);
if (mixer->balance != 0)
mixer_setbalance(mixer, mixer->balance);
+ mixer->user_set_mute = false;
+ mixer->user_set_volume = false;
}
/* Called before uninitializing the audio output. The main purpose is to
diff --git a/audio/mixer.h b/audio/mixer.h
index 3de92e1e03..3160c20cfe 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -41,6 +41,8 @@ typedef struct mixer {
* and needs to be restored after the driver is reinitialized. */
const char *restore_volume;
float balance;
+ bool user_set_mute;
+ bool user_set_volume;
} mixer_t;
void mixer_reinit(struct mixer *mixer, struct ao *ao);
diff --git a/audio/out/ao.c b/audio/out/ao.c
index 85e9548454..10badcfa07 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -61,12 +61,12 @@ static const struct ao_driver * const audio_out_drivers[] = {
#ifdef CONFIG_OSS_AUDIO
&audio_out_oss,
#endif
-#ifdef CONFIG_PORTAUDIO
- &audio_out_portaudio,
-#endif
#ifdef CONFIG_DSOUND
&audio_out_dsound,
#endif
+#ifdef CONFIG_PORTAUDIO
+ &audio_out_portaudio,
+#endif
// wrappers:
#ifdef CONFIG_JACK
&audio_out_jack,
@@ -91,13 +91,14 @@ static const struct ao_driver * const audio_out_drivers[] = {
void list_audio_out(void)
{
- int i=0;
mp_tmsg(MSGT_AO, MSGL_INFO, "Available audio output drivers:\n");
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_OUTPUTS\n");
- while (audio_out_drivers[i]) {
- const ao_info_t *info = audio_out_drivers[i++]->info;
- mp_msg(MSGT_GLOBAL, MSGL_INFO, "\t%s\t%s\n", info->short_name,
- info->name);
+ for (int i = 0; audio_out_drivers[i]; i++) {
+ const ao_info_t *info = audio_out_drivers[i]->info;
+ if (!audio_out_drivers[i]->encode) {
+ mp_msg(MSGT_GLOBAL, MSGL_INFO, "\t%s\t%s\n",
+ info->short_name, info->name);
+ }
}
mp_msg(MSGT_GLOBAL, MSGL_INFO,"\n");
}
@@ -110,6 +111,13 @@ struct ao *ao_create(struct MPOpts *opts, struct input_ctx *input)
return r;
}
+static bool ao_try_init(struct ao *ao, char *params)
+{
+ if (ao->driver->encode != !!ao->encode_lavc_ctx)
+ return false;
+ return ao->driver->init(ao, params) >= 0;
+}
+
void ao_init(struct ao *ao, char **ao_list)
{
/* Caller adding child blocks is not supported as we may call
@@ -148,7 +156,7 @@ void ao_init(struct ao *ao, char **ao_list)
if (audio_out) {
// name matches, try it
ao->driver = audio_out;
- if (audio_out->init(ao, params) >= 0) {
+ if (ao_try_init(ao, params)) {
ao->driver = audio_out;
ao->initialized = true;
return;
@@ -167,13 +175,14 @@ void ao_init(struct ao *ao, char **ao_list)
try_defaults:
mp_tmsg(MSGT_AO, MSGL_V, "Trying every known audio driver...\n");
+ ao->probing = false;
+
// now try the rest...
for (int i = 0; audio_out_drivers[i]; i++) {
const struct ao_driver *audio_out = audio_out_drivers[i];
ao->driver = audio_out;
ao->probing = true;
- if (audio_out->init(ao, NULL) >= 0) {
- ao->probing = false;
+ if (ao_try_init(ao, NULL)) {
ao->initialized = true;
ao->driver = audio_out;
return;
@@ -241,14 +250,24 @@ void ao_resume(struct ao *ao)
ao->driver->resume(ao);
}
+bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map)
+{
+ return mp_chmap_sel_adjust(s, map);
+}
+bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map, int num)
+{
+ return mp_chmap_sel_get_def(s, map, num);
+}
int old_ao_init(struct ao *ao, char *params)
{
assert(!global_ao);
global_ao = ao;
ao_subdevice = params ? talloc_strdup(ao, params) : NULL;
- if (ao->driver->old_functions->init(ao->samplerate, ao->channels,
+ if (ao->driver->old_functions->init(ao->samplerate, &ao->channels,
ao->format, 0) == 0) {
global_ao = NULL;
return -1;
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 6ea1b22cd2..d908841457 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -22,13 +22,9 @@
#include <stdbool.h>
#include "core/bstr.h"
-
-#define CONTROL_OK 1
-#define CONTROL_TRUE 1
-#define CONTROL_FALSE 0
-#define CONTROL_UNKNOWN -1
-#define CONTROL_ERROR -2
-#define CONTROL_NA -3
+#include "core/mp_common.h"
+#include "audio/chmap.h"
+#include "audio/chmap_sel.h"
enum aocontrol {
// _VOLUME commands take struct ao_control_vol pointer for input/output.
@@ -61,7 +57,7 @@ typedef struct ao_info {
/* interface towards mplayer and */
typedef struct ao_old_functions {
int (*control)(int cmd, void *arg);
- int (*init)(int rate, int channels, int format, int flags);
+ int (*init)(int rate, const struct mp_chmap *channels, int format, int flags);
void (*uninit)(int immed);
void (*reset)(void);
int (*get_space)(void);
@@ -74,7 +70,7 @@ typedef struct ao_old_functions {
struct ao;
struct ao_driver {
- bool is_new;
+ bool encode;
const struct ao_info *info;
const struct ao_old_functions *old_functions;
int (*control)(struct ao *ao, enum aocontrol cmd, void *arg);
@@ -91,9 +87,9 @@ struct ao_driver {
/* global data used by mplayer and plugins */
struct ao {
int samplerate;
- int channels;
+ struct mp_chmap channels;
int format;
- int bps;
+ int bps; // bytes per second
int outburst;
int buffersize;
double pts;
@@ -102,8 +98,8 @@ struct ao {
bool probing;
bool initialized;
bool untimed;
- bool no_persistent_volume;
- bool per_application_mixer;
+ bool no_persistent_volume; // the AO does the equivalent of af_volume
+ bool per_application_mixer; // like above, but volume persists (per app)
const struct ao_driver *driver;
void *priv;
struct encode_lavc_context *encode_lavc_ctx;
@@ -126,6 +122,11 @@ void ao_reset(struct ao *ao);
void ao_pause(struct ao *ao);
void ao_resume(struct ao *ao);
+bool ao_chmap_sel_adjust(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map);
+bool ao_chmap_sel_get_def(struct ao *ao, const struct mp_chmap_sel *s,
+ struct mp_chmap *map, int num);
+
int old_ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
int old_ao_init(struct ao *ao, char *params);
void old_ao_uninit(struct ao *ao, bool cut_audio);
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 366b912b76..d2e8180608 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -36,6 +36,7 @@
#include <alloca.h>
#include "config.h"
+#include "core/options.h"
#include "core/subopt-helper.h"
#include "audio/mixer.h"
#include "core/mp_msg.h"
@@ -46,292 +47,372 @@
#include <alsa/asoundlib.h>
#include "ao.h"
-#include "audio_out_internal.h"
#include "audio/format.h"
-
-static const ao_info_t info =
-{
- "ALSA-0.9.x-1.x audio output",
- "alsa",
- "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
- "under development"
+#include "audio/reorder_ch.h"
+
+struct priv {
+ snd_pcm_t *alsa;
+ snd_pcm_format_t alsa_fmt;
+ size_t bytes_per_sample;
+ int can_pause;
+ snd_pcm_sframes_t prepause_frames;
+ float delay_before_pause;
};
-LIBAO_EXTERN(alsa)
-
-static snd_pcm_t *alsa_handler;
-static snd_pcm_format_t alsa_format;
-
#define BUFFER_TIME 500000 // 0.5 s
#define FRAGCOUNT 16
-static size_t bytes_per_sample;
+#define ALSA_DEVICE_SIZE 256
-static int alsa_can_pause;
-static snd_pcm_sframes_t prepause_frames;
-static float delay_before_pause;
+#define CHECK_ALSA_ERROR(message) \
+ do { \
+ if (err < 0) { \
+ mp_msg(MSGT_VO, MSGL_ERR, "[AO_ALSA] %s: %s\n", \
+ (message), snd_strerror(err)); \
+ goto alsa_error; \
+ } \
+ } while (0)
-#define ALSA_DEVICE_SIZE 256
+static float get_delay(struct ao *ao);
+static int play(struct ao *ao, void *data, int len, int flags);
static void alsa_error_handler(const char *file, int line, const char *function,
- int err, const char *format, ...)
+ int err, const char *format, ...)
{
- char tmp[0xc00];
- va_list va;
-
- va_start(va, format);
- vsnprintf(tmp, sizeof tmp, format, va);
- va_end(va);
-
- if (err)
- mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n",
- file, line, function, tmp, snd_strerror(err));
- else
- mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n",
- file, line, function, tmp);
+ char tmp[0xc00];
+ va_list va;
+
+ va_start(va, format);
+ vsnprintf(tmp, sizeof tmp, format, va);
+ va_end(va);
+
+ if (err) {
+ mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n",
+ file, line, function, tmp, snd_strerror(err));
+ } else {
+ mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n",
+ file, line, function, tmp);
+ }
}
/* to set/get/query special features/parameters */
-static int control(int cmd, void *arg)
+static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
- switch(cmd) {
- case AOCONTROL_GET_MUTE:
- case AOCONTROL_SET_MUTE:
- case AOCONTROL_GET_VOLUME:
- case AOCONTROL_SET_VOLUME:
+ snd_mixer_t *handle = NULL;
+ switch (cmd) {
+ case AOCONTROL_GET_MUTE:
+ case AOCONTROL_SET_MUTE:
+ case AOCONTROL_GET_VOLUME:
+ case AOCONTROL_SET_VOLUME:
{
- int err;
- snd_mixer_t *handle;
- snd_mixer_elem_t *elem;
- snd_mixer_selem_id_t *sid;
-
- char *mix_name = "Master";
- char *card = "default";
- int mix_index = 0;
-
- long pmin, pmax;
- long get_vol, set_vol;
- float f_multi;
-
- if(AF_FORMAT_IS_IEC61937(ao_data.format))
- return CONTROL_TRUE;
-
- if(mixer_channel) {
- char *test_mix_index;
-
- mix_name = strdup(mixer_channel);
- if ((test_mix_index = strchr(mix_name, ','))){
- *test_mix_index = 0;
- test_mix_index++;
- mix_index = strtol(test_mix_index, &test_mix_index, 0);
-
- if (*test_mix_index){
- mp_tmsg(MSGT_AO,MSGL_ERR,
- "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n");
- mix_index = 0 ;
- }
- }
- }
- if(mixer_device) card = mixer_device;
-
- //allocate simple id
- snd_mixer_selem_id_alloca(&sid);
-
- //sets simple-mixer index and name
- snd_mixer_selem_id_set_index(sid, mix_index);
- snd_mixer_selem_id_set_name(sid, mix_name);
-
- if (mixer_channel) {
- free(mix_name);
- mix_name = NULL;
- }
-
- if ((err = snd_mixer_open(&handle, 0)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer open error: %s\n", snd_strerror(err));
- return CONTROL_ERROR;
- }
-
- if ((err = snd_mixer_attach(handle, card)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer attach %s error: %s\n",
- card, snd_strerror(err));
- snd_mixer_close(handle);
- return CONTROL_ERROR;
- }
-
- if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer register error: %s\n", snd_strerror(err));
- snd_mixer_close(handle);
- return CONTROL_ERROR;
- }
- err = snd_mixer_load(handle);
- if (err < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer load error: %s\n", snd_strerror(err));
- snd_mixer_close(handle);
- return CONTROL_ERROR;
- }
-
- elem = snd_mixer_find_selem(handle, sid);
- if (!elem) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to find simple control '%s',%i.\n",
- snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
- snd_mixer_close(handle);
- return CONTROL_ERROR;
- }
-
- snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
- f_multi = (100 / (float)(pmax - pmin));
-
- switch (cmd) {
- case AOCONTROL_SET_VOLUME: {
- ao_control_vol_t *vol = arg;
- set_vol = vol->left / f_multi + pmin + 0.5;
-
- //setting channels
- if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting left channel, %s\n",
- snd_strerror(err));
- goto mixer_error;
- }
- mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol);
-
- set_vol = vol->right / f_multi + pmin + 0.5;
-
- if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting right channel, %s\n",
- snd_strerror(err));
- goto mixer_error;
- }
- mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n",
- set_vol, pmin, pmax, f_multi);
- break;
- }
- case AOCONTROL_GET_VOLUME: {
- ao_control_vol_t *vol = arg;
- snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
- vol->left = (get_vol - pmin) * f_multi;
- snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
- vol->right = (get_vol - pmin) * f_multi;
- mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right);
- break;
- }
- case AOCONTROL_SET_MUTE: {
- bool *mute = arg;
- if (!snd_mixer_selem_has_playback_switch(elem))
- goto mixer_error;
- if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
- snd_mixer_selem_set_playback_switch(
- elem, SND_MIXER_SCHN_FRONT_RIGHT, !*mute);
- }
- snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT,
- !*mute);
- break;
- }
- case AOCONTROL_GET_MUTE: {
- bool *mute = arg;
- if (!snd_mixer_selem_has_playback_switch(elem))
- goto mixer_error;
- int tmp = 1;
- snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT,
- &tmp);
- *mute = !tmp;
- if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
- snd_mixer_selem_get_playback_switch(
- elem, SND_MIXER_SCHN_FRONT_RIGHT, &tmp);
- *mute &= !tmp;
+ int err;
+ snd_mixer_elem_t *elem;
+ snd_mixer_selem_id_t *sid;
+
+ char *mix_name = "Master";
+ char *card = "default";
+ int mix_index = 0;
+
+ long pmin, pmax;
+ long get_vol, set_vol;
+ float f_multi;
+
+ if (AF_FORMAT_IS_IEC61937(ao->format))
+ return CONTROL_TRUE;
+
+ if (ao->opts->mixer_channel) {
+ char *test_mix_index;
+
+ mix_name = strdup(ao->opts->mixer_channel);
+ if ((test_mix_index = strchr(mix_name, ','))) {
+ *test_mix_index = 0;
+ test_mix_index++;
+ mix_index = strtol(test_mix_index, &test_mix_index, 0);
+
+ if (*test_mix_index) {
+ mp_tmsg(MSGT_AO, MSGL_ERR,
+ "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n");
+ mix_index = 0;
+ }
+ }
+ }
+ if (ao->opts->mixer_device)
+ card = ao->opts->mixer_device;
+
+ //allocate simple id
+ snd_mixer_selem_id_alloca(&sid);
+
+ //sets simple-mixer index and name
+ snd_mixer_selem_id_set_index(sid, mix_index);
+ snd_mixer_selem_id_set_name(sid, mix_name);
+
+ if (ao->opts->mixer_channel) {
+ free(mix_name);
+ mix_name = NULL;
}
- break;
- }
- }
- snd_mixer_close(handle);
- return CONTROL_OK;
- mixer_error:
- snd_mixer_close(handle);
- return CONTROL_ERROR;
+
+ err = snd_mixer_open(&handle, 0);
+ CHECK_ALSA_ERROR("Mixer open error");
+
+ err = snd_mixer_attach(handle, card);
+ CHECK_ALSA_ERROR("Mixer attach error");
+
+ err = snd_mixer_selem_register(handle, NULL, NULL);
+ CHECK_ALSA_ERROR("Mixer register error");
+
+ err = snd_mixer_load(handle);
+ CHECK_ALSA_ERROR("Mixer load error");
+
+ elem = snd_mixer_find_selem(handle, sid);
+ if (!elem) {
+ mp_tmsg(MSGT_AO, MSGL_ERR,
+ "[AO_ALSA] Unable to find simple control '%s',%i.\n",
+ snd_mixer_selem_id_get_name(sid),
+ snd_mixer_selem_id_get_index(sid));
+ goto alsa_error;
+ }
+
+ snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
+ f_multi = (100 / (float)(pmax - pmin));
+
+ switch (cmd) {
+ case AOCONTROL_SET_VOLUME: {
+ ao_control_vol_t *vol = arg;
+ set_vol = vol->left / f_multi + pmin + 0.5;
+
+ //setting channels
+ err = snd_mixer_selem_set_playback_volume
+ (elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol);
+ CHECK_ALSA_ERROR("Error setting left channel");
+ mp_msg(MSGT_AO, MSGL_DBG2, "left=%li, ", set_vol);
+
+ set_vol = vol->right / f_multi + pmin + 0.5;
+
+ err = snd_mixer_selem_set_playback_volume
+ (elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol);
+ CHECK_ALSA_ERROR("Error setting right channel");
+ mp_msg(MSGT_AO, MSGL_DBG2,
+ "right=%li, pmin=%li, pmax=%li, mult=%f\n",
+ set_vol, pmin, pmax,
+ f_multi);
+ break;
+ }
+ case AOCONTROL_GET_VOLUME: {
+ ao_control_vol_t *vol = arg;
+ snd_mixer_selem_get_playback_volume
+ (elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
+ vol->left = (get_vol - pmin) * f_multi;
+ snd_mixer_selem_get_playback_volume
+ (elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
+ vol->right = (get_vol - pmin) * f_multi;
+ mp_msg(MSGT_AO, MSGL_DBG2, "left=%f, right=%f\n", vol->left,
+ vol->right);
+ break;
+ }
+ case AOCONTROL_SET_MUTE: {
+ bool *mute = arg;
+ if (!snd_mixer_selem_has_playback_switch(elem))
+ goto alsa_error;
+ if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
+ snd_mixer_selem_set_playback_switch
+ (elem, SND_MIXER_SCHN_FRONT_RIGHT, !*mute);
+ }
+ snd_mixer_selem_set_playback_switch
+ (elem, SND_MIXER_SCHN_FRONT_LEFT, !*mute);
+ break;
+ }
+ case AOCONTROL_GET_MUTE: {
+ bool *mute = arg;
+ if (!snd_mixer_selem_has_playback_switch(elem))
+ goto alsa_error;
+ int tmp = 1;
+ snd_mixer_selem_get_playback_switch
+ (elem, SND_MIXER_SCHN_FRONT_LEFT, &tmp);
+ *mute = !tmp;
+ if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
+ snd_mixer_selem_get_playback_switch
+ (elem, SND_MIXER_SCHN_FRONT_RIGHT, &tmp);
+ *mute &= !tmp;
+ }
+ break;
+ }
+ }
+ snd_mixer_close(handle);
+ return CONTROL_OK;
}
- } //end switch
- return CONTROL_UNKNOWN;
+ } //end switch
+ return CONTROL_UNKNOWN;
+
+alsa_error:
+ if (handle)
+ snd_mixer_close(handle);
+ return CONTROL_ERROR;
}
-static void parse_device (char *dest, const char *src, int len)
+static void parse_device(char *dest, const char *src, int len)
{
- char *tmp;
- memmove(dest, src, len);
- dest[len] = 0;
- while ((tmp = strrchr(dest, '.')))
- tmp[0] = ',';
- while ((tmp = strrchr(dest, '=')))
- tmp[0] = ':';
+ char *tmp;
+ memmove(dest, src, len);
+ dest[len] = 0;
+ while ((tmp = strrchr(dest, '.')))
+ tmp[0] = ',';
+ while ((tmp = strrchr(dest, '=')))
+ tmp[0] = ':';
}
-static void print_help (void)
+static void print_help(void)
{
- mp_tmsg (MSGT_AO, MSGL_FATAL,
- "\n[AO_ALSA] -ao alsa commandline help:\n"\
- "[AO_ALSA] Example: mpv -ao alsa:device=hw=0.3\n"\
- "[AO_ALSA] Sets first card fourth hardware device.\n\n"\
- "[AO_ALSA] Options:\n"\
- "[AO_ALSA] noblock\n"\
- "[AO_ALSA] Opens device in non-blocking mode.\n"\
- "[AO_ALSA] device=<device-name>\n"\
- "[AO_ALSA] Sets device (change , to . and : to =)\n");
+ mp_tmsg(MSGT_AO, MSGL_FATAL,
+ "\n[AO_ALSA] -ao alsa commandline help:\n" \
+ "[AO_ALSA] Example: mpv -ao alsa:device=hw=0.3\n" \
+ "[AO_ALSA] Sets first card fourth hardware device.\n\n" \
+ "[AO_ALSA] Options:\n" \
+ "[AO_ALSA] noblock\n" \
+ "[AO_ALSA] Opens device in non-blocking mode.\n" \
+ "[AO_ALSA] device=<device-name>\n" \
+ "[AO_ALSA] Sets device (change , to . and : to =)\n");
}
-static int str_maxlen(void *strp) {
- strarg_t *str = strp;
- return str->len <= ALSA_DEVICE_SIZE;
+static int str_maxlen(void *strp)
+{
+ strarg_t *str = strp;
+ return str->len <= ALSA_DEVICE_SIZE;
}
-static int try_open_device(const char *device, int open_mode, int try_ac3)
+
+static const int mp_to_alsa_format[][2] = {
+ {AF_FORMAT_S8, SND_PCM_FORMAT_S8},
+ {AF_FORMAT_U8, SND_PCM_FORMAT_U8},
+ {AF_FORMAT_U16_LE, SND_PCM_FORMAT_U16_LE},
+ {AF_FORMAT_U16_BE, SND_PCM_FORMAT_U16_BE},
+ {AF_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE},
+ {AF_FORMAT_S16_BE, SND_PCM_FORMAT_S16_BE},
+ {AF_FORMAT_U32_LE, SND_PCM_FORMAT_U32_LE},
+ {AF_FORMAT_U32_BE, SND_PCM_FORMAT_U32_BE},
+ {AF_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE},
+ {AF_FORMAT_S32_BE, SND_PCM_FORMAT_S32_BE},
+ {AF_FORMAT_U24_LE, SND_PCM_FORMAT_U24_3LE},
+ {AF_FORMAT_U24_BE, SND_PCM_FORMAT_U24_3BE},
+ {AF_FORMAT_S24_LE, SND_PCM_FORMAT_S24_3LE},
+ {AF_FORMAT_S24_BE, SND_PCM_FORMAT_S24_3BE},
+ {AF_FORMAT_FLOAT_LE, SND_PCM_FORMAT_FLOAT_LE},
+ {AF_FORMAT_FLOAT_BE, SND_PCM_FORMAT_FLOAT_BE},
+ {AF_FORMAT_AC3_LE, SND_PCM_FORMAT_S16_LE},
+ {AF_FORMAT_AC3_BE, SND_PCM_FORMAT_S16_BE},
+ {AF_FORMAT_IEC61937_LE, SND_PCM_FORMAT_S16_LE},
+ {AF_FORMAT_IEC61937_BE, SND_PCM_FORMAT_S16_BE},
+ {AF_FORMAT_MPEG2, SND_PCM_FORMAT_MPEG},
+ {AF_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN},
+};
+
+static int find_alsa_format(int af_format)
{
- int err, len;
- char *ac3_device, *args;
-
- if (try_ac3) {
- /* to set the non-audio bit, use AES0=6 */
- len = strlen(device);
- ac3_device = malloc(len + 7 + 1);
- if (!ac3_device)
- return -ENOMEM;
- strcpy(ac3_device, device);
- args = strchr(ac3_device, ':');
- if (!args) {
- /* no existing parameters: add it behind device name */
- strcat(ac3_device, ":AES0=6");
- } else {
- do
- ++args;
- while (isspace(*args));
- if (*args == '\0') {
- /* ":" but no parameters */
- strcat(ac3_device, "AES0=6");
- } else if (*args != '{') {
- /* a simple list of parameters: add it at the end of the list */
- strcat(ac3_device, ",AES0=6");
- } else {
- /* parameters in config syntax: add it inside the { } block */
- do
- --len;
- while (len > 0 && isspace(ac3_device[len]));
- if (ac3_device[len] == '}')
- strcpy(ac3_device + len, " AES0=6}");
- }
+ for (int n = 0; mp_to_alsa_format[n][0] != AF_FORMAT_UNKNOWN; n++) {
+ if (mp_to_alsa_format[n][0] == af_format)
+ return mp_to_alsa_format[n][1];
+ }
+ return SND_PCM_FORMAT_UNKNOWN;
+}
+
+// Lists device names and their implied channel map.
+// The second item must be resolvable with mp_chmap_from_str().
+// Source: http://www.alsa-project.org/main/index.php/DeviceNames
+// (Speaker names are slightly different from mpv's.)
+static const char *device_channel_layouts[][2] = {
+ {"default", "fc"},
+ {"default", "fl-fr"},
+ {"rear", "bl-br"},
+ {"center_lfe", "fc-lfe"},
+ {"side", "sl-sr"},
+ {"surround40", "fl-fr-bl-br"},
+ {"surround50", "fl-fr-bl-br-fc"},
+ {"surround41", "fl-fr-bl-br-lfe"},
+ {"surround51", "fl-fr-bl-br-fc-lfe"},
+ {"surround71", "fl-fr-bl-br-fc-lfe-sl-sr"},
+};
+
+#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0]))
+
+#define NUM_ALSA_CHMAPS ARRAY_LEN(device_channel_layouts)
+
+static const char *select_chmap(struct ao *ao)
+{
+ struct mp_chmap_sel sel = {0};
+ struct mp_chmap maps[NUM_ALSA_CHMAPS];
+ for (int n = 0; n < NUM_ALSA_CHMAPS; n++) {
+ mp_chmap_from_str(&maps[n], bstr0(device_channel_layouts[n][1]));
+ mp_chmap_sel_add_map(&sel, &maps[n]);
+ };
+
+ if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
+ return NULL;
+
+ for (int n = 0; n < NUM_ALSA_CHMAPS; n++) {
+ if (mp_chmap_equals(&ao->channels, &maps[n]))
+ return device_channel_layouts[n][0];
+ }
+
+ char *name = mp_chmap_to_str(&ao->channels);
+ mp_tmsg(MSGT_AO, MSGL_ERR,
+ "[AO_ALSA] channel layout %s (%d ch) not supported.\n",
+ name, ao->channels.num);
+ talloc_free(name);
+ return "default";
+}
+
+static int try_open_device(struct ao *ao, const char *device, int open_mode,
+ int try_ac3)
+{
+ struct priv *p = ao->priv;
+ int err, len;
+ char *ac3_device, *args;
+
+ if (try_ac3) {
+ /* to set the non-audio bit, use AES0=6 */
+ len = strlen(device);
+ ac3_device = malloc(len + 7 + 1);
+ if (!ac3_device)
+ return -ENOMEM;
+ strcpy(ac3_device, device);
+ args = strchr(ac3_device, ':');
+ if (!args) {
+ /* no existing parameters: add it behind device name */
+ strcat(ac3_device, ":AES0=6");
+ } else {
+ do {
+ ++args;
+ } while (isspace(*args));
+ if (*args == '\0') {
+ /* ":" but no parameters */
+ strcat(ac3_device, "AES0=6");
+ } else if (*args != '{') {
+ /* a simple list of parameters: add it at the end of the list */
+ strcat(ac3_device, ",AES0=6");
+ } else {
+ /* parameters in config syntax: add it inside the { } block */
+ do {
+ --len;
+ } while (len > 0 && isspace(ac3_device[len]));
+ if (ac3_device[len] == '}')
+ strcpy(ac3_device + len, " AES0=6}");
+ }
+ }
+ err = snd_pcm_open
+ (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, open_mode);
+ free(ac3_device);
+ if (!err)
+ return 0;
}
- err = snd_pcm_open(&alsa_handler, ac3_device, SND_PCM_STREAM_PLAYBACK,
- open_mode);
- free(ac3_device);
- if (!err)
- return 0;
- }
- return snd_pcm_open(&alsa_handler, device, SND_PCM_STREAM_PLAYBACK,
- open_mode);
+ return snd_pcm_open
+ (&p->alsa, device, SND_PCM_STREAM_PLAYBACK, open_mode);
}
/*
open & setup audio device
- return: 1=success 0=fail
-*/
-static int init(int rate_hz, int channels, int format, int flags)
+ return: 0=success -1=fail
+ */
+static int init(struct ao *ao, char *params)
{
int err;
int block;
@@ -340,89 +421,29 @@ static int init(int rate_hz, int channels, int format, int flags)
snd_pcm_uframes_t bufsize;
snd_pcm_uframes_t boundary;
const opt_t subopts[] = {
- {"block", OPT_ARG_BOOL, &block, NULL},
- {"device", OPT_ARG_STR, &device, str_maxlen},
- {NULL}
+ {"block", OPT_ARG_BOOL, &block, NULL},
+ {"device", OPT_ARG_STR, &device, str_maxlen},
+ {NULL}
};
+ struct priv *p = talloc_zero(ao, struct priv);
+ ao->priv = p;
+
char alsa_device[ALSA_DEVICE_SIZE + 1];
// make sure alsa_device is null-terminated even when using strncpy etc.
memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
- channels, format);
- alsa_handler = NULL;
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
+ mp_msg(MSGT_AO, MSGL_V,
+ "alsa-init: requested format: %d Hz, %d channels, %x\n",
+ ao->samplerate, ao->channels.num, ao->format);
+ p->alsa = NULL;
+ mp_msg(MSGT_AO, MSGL_V, "alsa-init: using ALSA %s\n", snd_asoundlib_version());
- prepause_frames = 0;
- delay_before_pause = 0;
+ p->prepause_frames = 0;
+ p->delay_before_pause = 0;
snd_lib_error_set_handler(alsa_error_handler);
- ao_data.samplerate = rate_hz;
- ao_data.format = format;
- ao_data.channels = channels;
-
- switch (format)
- {
- case AF_FORMAT_S8:
- alsa_format = SND_PCM_FORMAT_S8;
- break;
- case AF_FORMAT_U8:
- alsa_format = SND_PCM_FORMAT_U8;
- break;
- case AF_FORMAT_U16_LE:
- alsa_format = SND_PCM_FORMAT_U16_LE;
- break;
- case AF_FORMAT_U16_BE:
- alsa_format = SND_PCM_FORMAT_U16_BE;
- break;
- case AF_FORMAT_AC3_LE:
- case AF_FORMAT_S16_LE:
- case AF_FORMAT_IEC61937_LE:
- alsa_format = SND_PCM_FORMAT_S16_LE;
- break;
- case AF_FORMAT_AC3_BE:
- case AF_FORMAT_S16_BE:
- case AF_FORMAT_IEC61937_BE:
- alsa_format = SND_PCM_FORMAT_S16_BE;
- break;
- case AF_FORMAT_U32_LE:
- alsa_format = SND_PCM_FORMAT_U32_LE;
- break;
- case AF_FORMAT_U32_BE:
- alsa_format = SND_PCM_FORMAT_U32_BE;
- break;
- case AF_FORMAT_S32_LE:
- alsa_format = SND_PCM_FORMAT_S32_LE;
- break;
- case AF_FORMAT_S32_BE:
- alsa_format = SND_PCM_FORMAT_S32_BE;
- break;
- case AF_FORMAT_U24_LE:
- alsa_format = SND_PCM_FORMAT_U24_3LE;
- break;
- case AF_FORMAT_U24_BE:
- alsa_format = SND_PCM_FORMAT_U24_3BE;
- break;
- case AF_FORMAT_S24_LE:
- alsa_format = SND_PCM_FORMAT_S24_3LE;
- break;
- case AF_FORMAT_S24_BE:
- alsa_format = SND_PCM_FORMAT_S24_3BE;
- break;
- case AF_FORMAT_FLOAT_LE:
- alsa_format = SND_PCM_FORMAT_FLOAT_LE;
- break;
- case AF_FORMAT_FLOAT_BE:
- alsa_format = SND_PCM_FORMAT_FLOAT_BE;
- break;
-
- default:
- alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
- break;
- }
-
//subdevice parsing
// set defaults
block = 1;
@@ -432,347 +453,271 @@ static int init(int rate_hz, int channels, int format, int flags)
* while opening the abstract alias for the spdif subdevice
* 'iec958'
*/
- if (AF_FORMAT_IS_IEC61937(format)) {
- device.str = "iec958";
- mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels);
- }
- else
- /* in any case for multichannel playback we should select
- * appropriate device
- */
- switch (channels) {
- case 1:
- case 2:
- device.str = "default";
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
- break;
- case 4:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- // hack - use the converter plugin
- device.str = "plug:surround40";
- else
- device.str = "surround40";
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
- break;
- case 6:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- device.str = "plug:surround51";
- else
- device.str = "surround51";
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
- break;
- case 8:
- if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
- device.str = "plug:surround71";
- else
- device.str = "surround71";
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n");
- break;
- default:
- device.str = "default";
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] %d channels are not supported.\n",channels);
+ device.str = NULL;
+ if (AF_FORMAT_IS_IEC61937(ao->format)) {
+ device.str = "iec958";
+ mp_msg(MSGT_AO, MSGL_V,
+ "alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n",
+ ao->channels.num);
+ } else {
+ device.str = select_chmap(ao);
+ if (strcmp(device.str, "default") != 0 && ao->format == AF_FORMAT_FLOAT_NE)
+ {
+ // hack - use the converter plugin (why the heck?)
+ device.str = talloc_asprintf(ao, "plug:%s", device.str);
}
+ }
device.len = strlen(device.str);
- if (subopt_parse(ao_subdevice, subopts) != 0) {
+ if (subopt_parse(params, subopts) != 0) {
print_help();
return 0;
}
parse_device(alsa_device, device.str, device.len);
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);
-
- alsa_can_pause = 1;
-
- if (!alsa_handler) {
- int open_mode = block ? 0 : SND_PCM_NONBLOCK;
- int isac3 = AF_FORMAT_IS_IEC61937(format);
- //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
- if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0)
- {
- if (err != -EBUSY && !block) {
- mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Open in nonblock-mode failed, trying to open in block-mode.\n");
- if ((err = try_open_device(alsa_device, 0, isac3)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err));
- return 0;
- }
- } else {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err));
- return 0;
- }
- }
-
- if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AL_ALSA] Error setting block-mode %s.\n", snd_strerror(err));
- } else {
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opened in blocking mode\n");
- }
-
- snd_pcm_hw_params_t *alsa_hwparams;
- snd_pcm_sw_params_t *alsa_swparams;
-
- snd_pcm_hw_params_alloca(&alsa_hwparams);
- snd_pcm_sw_params_alloca(&alsa_swparams);
-
- // setting hw-parameters
- if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get initial parameters: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED);
- if (err < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set access type: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- /* workaround for nonsupported formats
- sets default format to S16_LE if the given formats aren't supported */
- if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
- alsa_format)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_INFO,
- "[AO_ALSA] Format %s is not supported by hardware, trying default.\n", af_fmt2str_short(format));
- alsa_format = SND_PCM_FORMAT_S16_LE;
- if (AF_FORMAT_IS_AC3(ao_data.format))
- ao_data.format = AF_FORMAT_AC3_LE;
- else if (AF_FORMAT_IS_IEC61937(ao_data.format))
- ao_data.format = AF_FORMAT_IEC61937_LE;
- else
- ao_data.format = AF_FORMAT_S16_LE;
- }
-
- if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
- alsa_format)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set format: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
- &ao_data.channels)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set channels: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
- prefer our own resampler, since that allows users to choose the resampler,
- even per file if desired */
- if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
- 0)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to disable resampling: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
- &ao_data.samplerate, NULL)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set samplerate-2: %s\n",
- snd_strerror(err));
- return 0;
+ mp_msg(MSGT_AO, MSGL_V, "alsa-init: using device %s\n", alsa_device);
+
+ p->can_pause = 1;
+
+ int open_mode = block ? 0 : SND_PCM_NONBLOCK;
+ int isac3 = AF_FORMAT_IS_IEC61937(ao->format);
+ //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
+ err = try_open_device(ao, alsa_device, open_mode, isac3);
+ if (err < 0) {
+ if (err != -EBUSY && !block) {
+ mp_tmsg(MSGT_AO, MSGL_INFO, "[AO_ALSA] Open in nonblock-mode "
+ "failed, trying to open in block-mode.\n");
+ err = try_open_device(ao, alsa_device, 0, isac3);
}
+ CHECK_ALSA_ERROR("Playback open error");
+ }
- bytes_per_sample = af_fmt2bits(ao_data.format) / 8;
- bytes_per_sample *= ao_data.channels;
- ao_data.bps = ao_data.samplerate * bytes_per_sample;
-
- if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
- &(unsigned int){BUFFER_TIME}, NULL)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set buffer time near: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
- &(unsigned int){FRAGCOUNT}, NULL)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set periods: %s\n",
- snd_strerror(err));
- return 0;
- }
-
- /* finally install hardware parameters */
- if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set hw-parameters: %s\n",
- snd_strerror(err));
- return 0;
- }
- // end setting hw-params
-
-
- // gets buffersize for control
- if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get buffersize: %s\n", snd_strerror(err));
- return 0;
- }
- else {
- ao_data.buffersize = bufsize * bytes_per_sample;
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
- }
-
- if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO ALSA] Unable to get period size: %s\n", snd_strerror(err));
- return 0;
- } else {
- mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
- }
- ao_data.outburst = chunk_size * bytes_per_sample;
-
- /* setting software parameters */
- if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n",
- snd_strerror(err));
- return 0;
- }
- if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get boundary: %s\n",
- snd_strerror(err));
- return 0;
- }
- /* start playing when one period has been written */
- if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set start threshold: %s\n",
- snd_strerror(err));
- return 0;
- }
- /* disable underrun reporting */
- if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set stop threshold: %s\n",
- snd_strerror(err));
- return 0;
- }
- /* play silence when there is an underrun */
- if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set silence size: %s\n",
- snd_strerror(err));
- return 0;
- }
- if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n",
- snd_strerror(err));
- return 0;
- }
- /* end setting sw-params */
-
- alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
-
- mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
- ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize,
- snd_pcm_format_description(alsa_format));
-
- } // end switch alsa_handler (spdif)
- return 1;
+ err = snd_pcm_nonblock(p->alsa, 0);
+ if (err < 0) {
+ mp_tmsg(MSGT_AO, MSGL_ERR,
+ "[AL_ALSA] Error setting block-mode %s.\n",
+ snd_strerror(err));
+ } else {
+ mp_msg(MSGT_AO, MSGL_V, "alsa-init: pcm opened in blocking mode\n");
+ }
+
+ snd_pcm_hw_params_t *alsa_hwparams;
+ snd_pcm_sw_params_t *alsa_swparams;
+
+ snd_pcm_hw_params_alloca(&alsa_hwparams);
+ snd_pcm_sw_params_alloca(&alsa_swparams);
+
+ // setting hw-parameters
+ err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
+ CHECK_ALSA_ERROR("Unable to get initial parameters");
+
+ err = snd_pcm_hw_params_set_access
+ (p->alsa, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
+ CHECK_ALSA_ERROR("Unable to set access type");
+
+ p->alsa_fmt = find_alsa_format(ao->format);
+ if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) {
+ p->alsa_fmt = SND_PCM_FORMAT_S16;
+ ao->format = AF_FORMAT_S16_NE;
+ }
+
+ err = snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt);
+ if (err < 0) {
+ mp_tmsg(MSGT_AO, MSGL_INFO, "[AO_ALSA] Format %s is not supported "
+ "by hardware, trying default.\n", af_fmt2str_short(ao->format));
+ p->alsa_fmt = SND_PCM_FORMAT_S16_LE;
+ if (AF_FORMAT_IS_AC3(ao->format))
+ ao->format = AF_FORMAT_AC3_LE;
+ else if (AF_FORMAT_IS_IEC61937(ao->format))
+ ao->format = AF_FORMAT_IEC61937_LE;
+ else
+ ao->format = AF_FORMAT_S16_LE;
+ }
+
+ err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);
+ CHECK_ALSA_ERROR("Unable to set format");
+
+ int num_channels = ao->channels.num;
+ err = snd_pcm_hw_params_set_channels_near
+ (p->alsa, alsa_hwparams, &num_channels);
+ CHECK_ALSA_ERROR("Unable to set channels");
+
+ if (num_channels != ao->channels.num) {
+ mp_tmsg(MSGT_AO, MSGL_ERR,
+ "[AO_ALSA] Couldn't get requested number of channels.\n");
+ mp_chmap_from_channels_alsa(&ao->channels, num_channels);
+ }
+
+ /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
+ prefer our own resampler, since that allows users to choose the resampler,
+ even per file if desired */
+ err = snd_pcm_hw_params_set_rate_resample(p->alsa, alsa_hwparams, 0);
+ CHECK_ALSA_ERROR("Unable to disable resampling");
+
+ err = snd_pcm_hw_params_set_rate_near
+ (p->alsa, alsa_hwparams, &ao->samplerate, NULL);
+ CHECK_ALSA_ERROR("Unable to set samplerate-2");
+
+ p->bytes_per_sample = af_fmt2bits(ao->format) / 8;
+ p->bytes_per_sample *= ao->channels.num;
+ ao->bps = ao->samplerate * p->bytes_per_sample;
+
+ err = snd_pcm_hw_params_set_buffer_time_near
+ (p->alsa, alsa_hwparams, &(unsigned int){BUFFER_TIME}, NULL);
+ CHECK_ALSA_ERROR("Unable to set buffer time near");
+
+ err = snd_pcm_hw_params_set_periods_near
+ (p->alsa, alsa_hwparams, &(unsigned int){FRAGCOUNT}, NULL);
+ CHECK_ALSA_ERROR("Unable to set periods");
+
+ /* finally install hardware parameters */
+ err = snd_pcm_hw_params(p->alsa, alsa_hwparams);
+ CHECK_ALSA_ERROR("Unable to set hw-parameters");
+
+ // end setting hw-params
+
+ // gets buffersize for control
+ err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize);
+ CHECK_ALSA_ERROR("Unable to get buffersize");
+
+ ao->buffersize = bufsize * p->bytes_per_sample;
+ mp_msg(MSGT_AO, MSGL_V, "alsa-init: got buffersize=%i\n",
+ ao->buffersize);
+
+ err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL);
+ CHECK_ALSA_ERROR("Unable to get period size");
+
+ mp_msg(MSGT_AO, MSGL_V, "alsa-init: got period size %li\n", chunk_size);
+ ao->outburst = chunk_size * p->bytes_per_sample;
+
+ /* setting software parameters */
+ err = snd_pcm_sw_params_current(p->alsa, alsa_swparams);
+ CHECK_ALSA_ERROR("Unable to get sw-parameters");
+
+ err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary);
+ CHECK_ALSA_ERROR("Unable to get boundary");
+
+ /* start playing when one period has been written */
+ err = snd_pcm_sw_params_set_start_threshold
+ (p->alsa, alsa_swparams, chunk_size);
+ CHECK_ALSA_ERROR("Unable to set start threshold");
+
+ /* disable underrun reporting */
+ err = snd_pcm_sw_params_set_stop_threshold
+ (p->alsa, alsa_swparams, boundary);
+ CHECK_ALSA_ERROR("Unable to set stop threshold");
+
+ /* play silence when there is an underrun */
+ err = snd_pcm_sw_params_set_silence_size
+ (p->alsa, alsa_swparams, boundary);
+ CHECK_ALSA_ERROR("Unable to set silence size");
+
+ err = snd_pcm_sw_params(p->alsa, alsa_swparams);
+ CHECK_ALSA_ERROR("Unable to get sw-parameters");
+
+ /* end setting sw-params */
+
+ p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
+
+ mp_msg(MSGT_AO, MSGL_V,
+ "alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
+ ao->samplerate, ao->channels.num, (int)p->bytes_per_sample,
+ ao->buffersize, snd_pcm_format_description(p->alsa_fmt));
+
+ return 0;
+
+alsa_error:
+ return -1;
} // end init
/* close audio device */
-static void uninit(int immed)
+static void uninit(struct ao *ao, bool immed)
{
+ struct priv *p = ao->priv;
- if (alsa_handler) {
- int err;
+ if (p->alsa) {
+ int err;
+
+ if (!immed)
+ snd_pcm_drain(p->alsa);
- if (!immed)
- snd_pcm_drain(alsa_handler);
-
- if ((err = snd_pcm_close(alsa_handler)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm close error: %s\n", snd_strerror(err));
- return;
- }
- else {
- alsa_handler = NULL;
- mp_msg(MSGT_AO,MSGL_V,"alsa-uninit: pcm closed\n");
+ err = snd_pcm_close(p->alsa);
+ CHECK_ALSA_ERROR("pcm close error");
+
+ p->alsa = NULL;
+ mp_msg(MSGT_AO, MSGL_V, "alsa-uninit: pcm closed\n");
+ } else {
+ mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] No handler defined!\n");
}
- }
- else {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] No handler defined!\n");
- }
+
+alsa_error: ;
}
-static void audio_pause(void)
+static void audio_pause(struct ao *ao)
{
+ struct priv *p = ao->priv;
int err;
- if (alsa_can_pause) {
- delay_before_pause = get_delay();
- if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm pause error: %s\n", snd_strerror(err));
- return;
- }
- mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n");
+ if (p->can_pause) {
+ p->delay_before_pause = get_delay(ao);
+ err = snd_pcm_pause(p->alsa, 1);
+ CHECK_ALSA_ERROR("pcm pause error");
+ mp_msg(MSGT_AO, MSGL_V, "alsa-pause: pause supported by hardware\n");
} else {
- if (snd_pcm_delay(alsa_handler, &prepause_frames) < 0
- || prepause_frames < 0)
- prepause_frames = 0;
- delay_before_pause = prepause_frames / (float)ao_data.samplerate;
+ if (snd_pcm_delay(p->alsa, &p->prepause_frames) < 0
+ || p->prepause_frames < 0)
+ p->prepause_frames = 0;
+ p->delay_before_pause = p->prepause_frames / (float)ao->samplerate;
- if ((err = snd_pcm_drop(alsa_handler)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm drop error: %s\n", snd_strerror(err));
- return;
- }
+ err = snd_pcm_drop(p->alsa);
+ CHECK_ALSA_ERROR("pcm drop error");
}
+
+alsa_error: ;
}
-static void audio_resume(void)
+static void audio_resume(struct ao *ao)
{
+ struct priv *p = ao->priv;
int err;
- if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
- mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
- while ((err = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1);
+ if (snd_pcm_state(p->alsa) == SND_PCM_STATE_SUSPENDED) {
+ mp_tmsg(MSGT_AO, MSGL_INFO,
+ "[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
+ while ((err = snd_pcm_resume(p->alsa)) == -EAGAIN)
+ sleep(1);
}
- if (alsa_can_pause) {
- if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm resume error: %s\n", snd_strerror(err));
- return;
- }
- mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
+ if (p->can_pause) {
+ err = snd_pcm_pause(p->alsa, 0);
+ CHECK_ALSA_ERROR("pcm resume error");
+ mp_msg(MSGT_AO, MSGL_V, "alsa-resume: resume supported by hardware\n");
} else {
- if ((err = snd_pcm_prepare(alsa_handler)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
- return;
- }
- if (prepause_frames) {
- void *silence = calloc(prepause_frames, bytes_per_sample);
- play(silence, prepause_frames * bytes_per_sample, 0);
+ err = snd_pcm_prepare(p->alsa);
+ CHECK_ALSA_ERROR("pcm prepare error");
+ if (p->prepause_frames) {
+ void *silence = calloc(p->prepause_frames, p->bytes_per_sample);
+ play(ao, silence, p->prepause_frames * p->bytes_per_sample, 0);
free(silence);
}
}
+
+alsa_error: ;
}
/* stop playing and empty buffers (for seeking/pause) */
-static void reset(void)
+static void reset(struct ao *ao)
{
+ struct priv *p = ao->priv;
int err;
- prepause_frames = 0;
- delay_before_pause = 0;
- if ((err = snd_pcm_drop(alsa_handler)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
- return;
- }
- if ((err = snd_pcm_prepare(alsa_handler)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
- return;
- }
- return;
+ p->prepause_frames = 0;
+ p->delay_before_pause = 0;
+ err = snd_pcm_drop(p->alsa);
+ CHECK_ALSA_ERROR("pcm prepare error");
+ err = snd_pcm_prepare(p->alsa);
+ CHECK_ALSA_ERROR("pcm prepare error");
+
+alsa_error: ;
}
/*
@@ -780,91 +725,115 @@ static void reset(void)
returns: number of bytes played
modified last at 29.06.02 by jp
thanxs for marius <marius@rospot.com> for giving us the light ;)
-*/
+ */
-static int play(void* data, int len, int flags)
+static int play(struct ao *ao, void *data, int len, int flags)
{
- int num_frames;
- snd_pcm_sframes_t res = 0;
- if (!(flags & AOPLAY_FINAL_CHUNK))
- len = len / ao_data.outburst * ao_data.outburst;
- num_frames = len / bytes_per_sample;
+ struct priv *p = ao->priv;
+ int num_frames;
+ snd_pcm_sframes_t res = 0;
+ if (!(flags & AOPLAY_FINAL_CHUNK))
+ len = len / ao->outburst * ao->outburst;
+ num_frames = len / p->bytes_per_sample;
- //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
+ //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
- if (!alsa_handler) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Device configuration error.");
- return 0;
- }
+ if (!p->alsa) {
+ mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Device configuration error.");
+ return 0;
+ }
- if (num_frames == 0)
- return 0;
+ if (num_frames == 0)
+ return 0;
+
+ do {
+ res = snd_pcm_writei(p->alsa, data, num_frames);
+
+ if (res == -EINTR) {
+ /* nothing to do */
+ res = 0;
+ } else if (res == -ESTRPIPE) { /* suspend */
+ mp_tmsg(MSGT_AO, MSGL_INFO,
+ "[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
+ while ((res = snd_pcm_resume(p->alsa)) == -EAGAIN)
+ sleep(1);
+ }
+ if (res < 0) {
+ mp_tmsg(MSGT_AO, MSGL_ERR, "[AO_ALSA] Write error: %s\n",
+ snd_strerror(res));
+ mp_tmsg(MSGT_AO, MSGL_INFO,
+ "[AO_ALSA] Trying to reset soundcard.\n");
+ res = snd_pcm_prepare(p->alsa);
+ int err = res;
+ CHECK_ALSA_ERROR("pcm prepare error");
+ res = 0;
+ }
+ } while (res == 0);
+
+ return res < 0 ? 0 : res * p->bytes_per_sample;
- do {
- res = snd_pcm_writei(alsa_handler, data, num_frames);
-
- if (res == -EINTR) {
- /* nothing to do */
- res = 0;
- }
- else if (res == -ESTRPIPE) { /* suspend */
- mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
- while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
- sleep(1);
- }
- if (res < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Write error: %s\n", snd_strerror(res));
- mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Trying to reset soundcard.\n");
- if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(res));
- break;
- }
- res = 0;
- }
- } while (res == 0);
-
- return res < 0 ? 0 : res * bytes_per_sample;
+alsa_error:
+ return 0;
}
/* how many byes are free in the buffer */
-static int get_space(void)
+static int get_space(struct ao *ao)
{
+ struct priv *p = ao->priv;
snd_pcm_status_t *status;
- int ret;
+ int err;
snd_pcm_status_alloca(&status);
- if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
- {
- mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Cannot get pcm status: %s\n", snd_strerror(ret));
- return 0;
- }
+ err = snd_pcm_status(p->alsa, status);
+ CHECK_ALSA_ERROR("cannot get pcm status");
- unsigned space = snd_pcm_status_get_avail(status) * bytes_per_sample;
- if (space > ao_data.buffersize) // Buffer underrun?
- space = ao_data.buffersize;
+ unsigned space = snd_pcm_status_get_avail(status) * p->bytes_per_sample;
+ if (space > ao->buffersize) // Buffer underrun?
+ space = ao->buffersize;
return space;
+
+alsa_error:
+ return 0;
}
/* delay in seconds between first and last sample in buffer */
-static float get_delay(void)
+static float get_delay(struct ao *ao)
{
- if (alsa_handler) {
- snd_pcm_sframes_t delay;
+ struct priv *p = ao->priv;
+ if (p->alsa) {
+ snd_pcm_sframes_t delay;
- if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_PAUSED)
- return delay_before_pause;
+ if (snd_pcm_state(p->alsa) == SND_PCM_STATE_PAUSED)
+ return p->delay_before_pause;
- if (snd_pcm_delay(alsa_handler, &delay) < 0)
- return 0;
+ if (snd_pcm_delay(p->alsa, &delay) < 0)
+ return 0;
- if (delay < 0) {
- /* underrun - move the application pointer forward to catch up */
- snd_pcm_forward(alsa_handler, -delay);
- delay = 0;
- }
- return (float)delay / (float)ao_data.samplerate;
- } else {
- return 0;
- }
+ if (delay < 0) {
+ /* underrun - move the application pointer forward to catch up */
+ snd_pcm_forward(p->alsa, -delay);
+ delay = 0;
+ }
+ return (float)delay / (float)ao->samplerate;
+ } else
+ return 0;
}
+
+const struct ao_driver audio_out_alsa = {
+ .info = &(const struct ao_info) {
+ "ALSA-0.9.x-1.x audio output",
+ "alsa",
+ "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
+ "under development"
+ },
+ .init = init,
+ .uninit = uninit,
+ .control = control,
+ .get_space = get_space,
+ .play = play,
+ .get_delay = get_delay,
+ .pause = audio_pause,
+ .resume = audio_resume,
+ .reset = reset,
+};
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 7993eac910..083c50faff 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -412,7 +412,7 @@ static void print_help(void)
free(devids);
}
-static int init(int rate,int channels,int format,int flags)
+static int init(int rate,const struct mp_chmap *channels,int format,int flags)
{
AudioStreamBasicDescription inDesc;
AudioComponentDescription desc;
@@ -439,7 +439,7 @@ int device_id, display_help = 0;
return 0;
}
- ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, channels, af_fmt2str_short(format), flags);
+ ao_msg(MSGT_AO,MSGL_V, "init([%dHz][%dch][%s][%d])\n", rate, ao_data.channels.num, af_fmt2str_short(format), flags);
ao = calloc(1, sizeof(ao_coreaudio_t));
@@ -499,10 +499,15 @@ int device_id, display_help = 0;
// Save selected device id
ao->i_selected_dev = devid_def;
+ struct mp_chmap_sel chmap_sel = {0};
+ mp_chmap_sel_add_waveext(&chmap_sel);
+ if (!ao_chmap_sel_adjust(&ao_data, &chmap_sel, &ao_data.channels))
+ goto err_out;
+
// Build Description for the input format
inDesc.mSampleRate=rate;
inDesc.mFormatID=ao->b_supports_digital ? kAudioFormat60958AC3 : kAudioFormatLinearPCM;
- inDesc.mChannelsPerFrame=channels;
+ inDesc.mChannelsPerFrame=ao_data.channels.num;
inDesc.mBitsPerChannel=af_fmt2bits(format);
if((format&AF_FORMAT_POINT_MASK)==AF_FORMAT_F) {
@@ -521,7 +526,7 @@ int device_id, display_help = 0;
inDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
inDesc.mFramesPerPacket = 1;
- ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*channels*(inDesc.mBitsPerChannel/8);
+ ao->packetSize = inDesc.mBytesPerPacket = inDesc.mBytesPerFrame = inDesc.mFramesPerPacket*ao_data.channels.num*(inDesc.mBitsPerChannel/8);
print_format(MSGL_V, "source:",&inDesc);
if (ao->b_supports_digital)
@@ -605,7 +610,8 @@ int device_id, display_help = 0;
ao->chunk_size = maxFrames;//*inDesc.mBytesPerFrame;
ao_data.samplerate = inDesc.mSampleRate;
- ao_data.channels = inDesc.mChannelsPerFrame;
+ if (!ao_chmap_sel_get_def(&ao_data, &chmap_sel, &ao_data.channels, inDesc.mChannelsPerFrame))
+ goto err_out2;
ao_data.bps = ao_data.samplerate * inDesc.mBytesPerFrame;
ao_data.outburst = ao->chunk_size;
ao_data.buffersize = ao_data.bps;
@@ -837,7 +843,8 @@ static int OpenSPDIF(void)
ao->chunk_size = ao->stream_format.mBytesPerPacket;
ao_data.samplerate = ao->stream_format.mSampleRate;
- ao_data.channels = ao->stream_format.mChannelsPerFrame;
+ // Applies default ordering; ok because AC3 data is always in mpv internal channel order
+ mp_chmap_from_channels(&ao_data.channels, ao->stream_format.mChannelsPerFrame);
ao_data.bps = ao_data.samplerate * (ao->stream_format.mBytesPerPacket/ao->stream_format.mFramesPerPacket);
ao_data.outburst = ao->chunk_size;
ao_data.buffersize = ao_data.bps;
@@ -1073,7 +1080,6 @@ static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
static int play(void* output_samples,int num_bytes,int flags)
{
int wrote, b_digital;
- SInt32 exit_reason;
// Check whether we need to reset the digital output stream.
if (ao->b_digital && ao->b_stream_format_changed)
@@ -1103,10 +1109,6 @@ static int play(void* output_samples,int num_bytes,int flags)
wrote=write_buffer(output_samples, num_bytes);
audio_resume();
- do {
- exit_reason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
- } while (exit_reason == kCFRunLoopRunHandledSource);
-
return wrote;
}
diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c
index 8d3124122c..967084d3ae 100644
--- a/audio/out/ao_dsound.c
+++ b/audio/out/ao_dsound.c
@@ -32,9 +32,13 @@
#include <dsound.h>
#include <math.h>
+#include <libavutil/avutil.h>
+#include <libavutil/common.h>
+
#include "config.h"
#include "audio/format.h"
#include "ao.h"
+#include "audio/reorder_ch.h"
#include "audio_out_internal.h"
#include "core/mp_msg.h"
#include "osdep/timer.h"
@@ -60,26 +64,6 @@ LIBAO_EXTERN(dsound)
static const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x1,0x0000,0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
-#define SPEAKER_FRONT_LEFT 0x1
-#define SPEAKER_FRONT_RIGHT 0x2
-#define SPEAKER_FRONT_CENTER 0x4
-#define SPEAKER_LOW_FREQUENCY 0x8
-#define SPEAKER_BACK_LEFT 0x10
-#define SPEAKER_BACK_RIGHT 0x20
-#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
-#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
-#define SPEAKER_BACK_CENTER 0x100
-#define SPEAKER_SIDE_LEFT 0x200
-#define SPEAKER_SIDE_RIGHT 0x400
-#define SPEAKER_TOP_CENTER 0x800
-#define SPEAKER_TOP_FRONT_LEFT 0x1000
-#define SPEAKER_TOP_FRONT_CENTER 0x2000
-#define SPEAKER_TOP_FRONT_RIGHT 0x4000
-#define SPEAKER_TOP_BACK_LEFT 0x8000
-#define SPEAKER_TOP_BACK_CENTER 0x10000
-#define SPEAKER_TOP_BACK_RIGHT 0x20000
-#define SPEAKER_RESERVED 0x80000000
-
#if 0
#define DSSPEAKER_HEADPHONE 0x00000001
#define DSSPEAKER_MONO 0x00000002
@@ -103,13 +87,6 @@ typedef struct {
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
#endif
-static const int channel_mask[] = {
- SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY,
- SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT,
- SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY,
- SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY
-};
-
static HINSTANCE hdsound_dll = NULL; ///handle to the dll
static LPDIRECTSOUND hds = NULL; ///direct sound object
static LPDIRECTSOUNDBUFFER hdspribuf = NULL; ///primary direct sound buffer
@@ -329,32 +306,14 @@ static int write_buffer(unsigned char *data, int len)
if (SUCCEEDED(res))
{
- if( (ao_data.channels == 6) && !AF_FORMAT_IS_AC3(ao_data.format) ) {
- // reorder channels while writing to pointers.
- // it's this easy because buffer size and len are always
- // aligned to multiples of channels*bytespersample
- // there's probably some room for speed improvements here
- const int chantable[6] = {0, 1, 4, 5, 2, 3}; // reorder "matrix"
- int i, j;
- int numsamp,sampsize;
-
- sampsize = af_fmt2bits(ao_data.format)>>3; // bytes per sample
- numsamp = dwBytes1 / (ao_data.channels * sampsize); // number of samples for each channel in this buffer
-
- for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) {
- memcpy((char*)lpvPtr1+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize);
- }
-
- if (NULL != lpvPtr2 )
- {
- numsamp = dwBytes2 / (ao_data.channels * sampsize);
- for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) {
- memcpy((char*)lpvPtr2+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+dwBytes1+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize);
- }
- }
+ if (!AF_FORMAT_IS_AC3(ao_data.format)) {
+ memcpy(lpvPtr1, data, dwBytes1);
+ if (lpvPtr2 != NULL)
+ memcpy(lpvPtr2, (char *)data + dwBytes1, dwBytes2);
write_offset+=dwBytes1+dwBytes2;
- if(write_offset>=buffer_size)write_offset=dwBytes2;
+ if(write_offset>=buffer_size)
+ write_offset=dwBytes2;
} else {
// Write to pointers without reordering.
memcpy(lpvPtr1,data,dwBytes1);
@@ -418,7 +377,7 @@ static int control(int cmd, void *arg)
\param flags unused
\return 1=success 0=fail
*/
-static int init(int rate, int channels, int format, int flags)
+static int init(int rate, const struct mp_chmap *channels, int format, int flags)
{
int res;
if (!InitDirectSound()) return 0;
@@ -431,15 +390,14 @@ static int init(int rate, int channels, int format, int flags)
DSBUFFERDESC dsbpridesc;
DSBUFFERDESC dsbdesc;
- //check if the channel count and format is supported in general
- if (channels > 6) {
- UninitDirectSound();
- mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: 8 channel audio not yet supported\n");
- return 0;
- }
-
- if (AF_FORMAT_IS_AC3(format))
+ if (AF_FORMAT_IS_AC3(format)) {
format = AF_FORMAT_AC3_NE;
+ } else {
+ struct mp_chmap_sel sel = {0};
+ mp_chmap_sel_add_waveext(&sel);
+ if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
+ return 0;
+ }
switch(format){
case AF_FORMAT_AC3_NE:
case AF_FORMAT_S24_LE:
@@ -451,25 +409,24 @@ static int init(int rate, int channels, int format, int flags)
format=AF_FORMAT_S16_LE;
}
//fill global ao_data
- ao_data.channels = channels;
ao_data.samplerate = rate;
ao_data.format = format;
- ao_data.bps = channels * rate * (af_fmt2bits(format)>>3);
+ ao_data.bps = ao_data.channels.num * rate * (af_fmt2bits(format)>>3);
if(ao_data.buffersize==-1) ao_data.buffersize = ao_data.bps; // space for 1 sec
- mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, af_fmt2str_short(format));
+ mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, ao_data.channels.num, af_fmt2str_short(format));
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, ao_data.buffersize / ao_data.bps * 1000);
//fill waveformatex
ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
- wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
- wformat.Format.nChannels = channels;
+ wformat.Format.cbSize = (ao_data.channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
+ wformat.Format.nChannels = ao_data.channels.num;
wformat.Format.nSamplesPerSec = rate;
if (AF_FORMAT_IS_AC3(format)) {
wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wformat.Format.wBitsPerSample = 16;
wformat.Format.nBlockAlign = 4;
} else {
- wformat.Format.wFormatTag = (channels > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
+ wformat.Format.wFormatTag = (ao_data.channels.num > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
wformat.Format.wBitsPerSample = af_fmt2bits(format);
wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3);
}
@@ -489,8 +446,8 @@ static int init(int rate, int channels, int format, int flags)
| DSBCAPS_GLOBALFOCUS /** Allows background playing */
| DSBCAPS_CTRLVOLUME; /** volume control enabled */
- if (channels > 2) {
- wformat.dwChannelMask = channel_mask[channels - 3];
+ if (ao_data.channels.num > 2) {
+ wformat.dwChannelMask = mp_chmap_to_waveext(&ao_data.channels);
wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample;
// Needed for 5.1 on emu101k - shit soundblaster
diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c
index 2762954040..0f8baeab86 100644
--- a/audio/out/ao_jack.c
+++ b/audio/out/ao_jack.c
@@ -50,7 +50,7 @@ static const ao_info_t info =
LIBAO_EXTERN(jack)
//! maximum number of channels supported, avoids lots of mallocs
-#define MAX_CHANS 8
+#define MAX_CHANS MP_NUM_CHANNELS
static jack_port_t *ports[MAX_CHANS];
static int num_ports; ///< Number of used ports == number of channels
static jack_client_t *client;
@@ -202,7 +202,8 @@ static void print_help (void)
);
}
-static int init(int rate, int channels, int format, int flags) {
+static int init(int rate, const struct mp_chmap *channels, int format, int flags)
+{
const char **matching_ports = NULL;
char *port_name = NULL;
char *client_name = NULL;
@@ -222,10 +223,12 @@ static int init(int rate, int channels, int format, int flags) {
print_help();
return 0;
}
- if (channels > MAX_CHANS) {
- mp_msg(MSGT_AO, MSGL_FATAL, "[JACK] Invalid number of channels: %i\n", channels);
+
+ struct mp_chmap_sel sel = {0};
+ mp_chmap_sel_add_waveext(&sel);
+ if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
goto err_out;
- }
+
if (!client_name) {
client_name = malloc(40);
sprintf(client_name, "mpv [%d]", getpid());
@@ -249,9 +252,9 @@ static int init(int rate, int channels, int format, int flags) {
goto err_out;
}
i = 1;
+ num_ports = ao_data.channels.num;
while (matching_ports[i]) i++;
- if (channels > i) channels = i;
- num_ports = channels;
+ if (num_ports > i) num_ports = i;
// create out output ports
for (i = 0; i < num_ports; i++) {
@@ -274,14 +277,19 @@ static int init(int rate, int channels, int format, int flags) {
}
}
rate = jack_get_sample_rate(client);
- jack_latency = (float)(jack_port_get_total_latency(client, ports[0]) +
- jack_get_buffer_size(client)) / (float)rate;
+ jack_latency_range_t jack_latency_range;
+ jack_port_get_latency_range(ports[0], JackPlaybackLatency,
+ &jack_latency_range);
+ jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(client))
+ / (float)rate;
callback_interval = 0;
- ao_data.channels = channels;
+ if (!ao_chmap_sel_get_def(&ao_data, &sel, &ao_data.channels, num_ports))
+ goto err_out;
+
ao_data.samplerate = rate;
ao_data.format = AF_FORMAT_FLOAT_NE;
- ao_data.bps = channels * rate * sizeof(float);
+ ao_data.bps = ao_data.channels.num * rate * sizeof(float);
ao_data.buffersize = CHUNK_SIZE * NUM_CHUNKS;
ao_data.outburst = CHUNK_SIZE;
free(matching_ports);
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index ab82ad9d6d..d8185a8dca 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -101,7 +101,14 @@ static int init(struct ao *ao, char *params)
ac->stream->codec->time_base.den = ao->samplerate;
ac->stream->codec->sample_rate = ao->samplerate;
- ac->stream->codec->channels = ao->channels;
+
+ struct mp_chmap_sel sel = {0};
+ mp_chmap_sel_add_any(&sel);
+ if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
+ return -1;
+ mp_chmap_reorder_to_lavc(&ao->channels);
+ ac->stream->codec->channels = ao->channels.num;
+ ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
@@ -243,36 +250,6 @@ out_takefirst:
ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8;
- switch (ao->channels) {
- case 1:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_MONO;
- break;
- case 2:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- break;
- /* someone please check if these are what mplayer normally assumes
- case 3:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_SURROUND;
- break;
- case 4:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_2_2;
- break;
- */
- case 5:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT0;
- break;
- case 6:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_5POINT1;
- break;
- case 8:
- ac->stream->codec->channel_layout = AV_CH_LAYOUT_7POINT1;
- break;
- default:
- mp_msg(MSGT_ENCODE, MSGL_ERR,
- "ao-lavc: unknown channel layout; hoping for the best\n");
- break;
- }
-
if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0)
return -1;
@@ -282,11 +259,12 @@ out_takefirst:
if (ac->pcmhack) {
ac->aframesize = 16384; // "enough"
- ac->buffer_size = ac->aframesize * ac->pcmhack * ao->channels * 2 + 200;
+ ac->buffer_size =
+ ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200;
} else {
ac->aframesize = ac->stream->codec->frame_size;
- ac->buffer_size = ac->aframesize * ac->sample_size * ao->channels * 2 +
- 200;
+ ac->buffer_size =
+ ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200;
}
if (ac->buffer_size < FF_MIN_BUFFER_SIZE)
ac->buffer_size = FF_MIN_BUFFER_SIZE;
@@ -304,10 +282,10 @@ out_takefirst:
ac->offset_left = ac->offset;
//fill_ao_data:
- ao->outburst = ac->aframesize * ac->sample_size * ao->channels *
- ac->framecount;
+ ao->outburst =
+ ac->aframesize * ac->sample_size * ao->channels.num * ac->framecount;
ao->buffersize = ao->outburst * 2;
- ao->bps = ao->channels * ao->samplerate * ac->sample_size;
+ ao->bps = ao->channels.num * ao->samplerate * ac->sample_size;
ao->untimed = true;
ao->priv = ac;
@@ -331,6 +309,7 @@ static void fill_with_padding(void *buf, int cnt, int sz, const void *padding)
// close audio device
static int encode(struct ao *ao, double apts, void *data);
+static int play(struct ao *ao, void *data, int len, int flags);
static void uninit(struct ao *ao, bool cut_audio)
{
struct priv *ac = ao->priv;
@@ -343,21 +322,31 @@ static void uninit(struct ao *ao, bool cut_audio)
}
if (ac->buffer) {
- double pts = ao->pts + ac->offset / (double) ao->samplerate;
if (ao->buffer.len > 0) {
- void *paddingbuf = talloc_size(ao,
- ac->aframesize * ao->channels * ac->sample_size);
+ // TRICK: append aframesize-1 samples to the end, then play() will
+ // encode all it can
+ size_t extralen =
+ (ac->aframesize - 1) * ao->channels.num * ac->sample_size;
+ void *paddingbuf = talloc_size(ao, ao->buffer.len + extralen);
memcpy(paddingbuf, ao->buffer.start, ao->buffer.len);
fill_with_padding((char *) paddingbuf + ao->buffer.len,
- (ac->aframesize * ao->channels * ac->sample_size
- - ao->buffer.len) / ac->sample_size,
+ extralen / ac->sample_size,
ac->sample_size, ac->sample_padding);
- encode(ao, pts, paddingbuf);
- pts += ac->aframesize / (double) ao->samplerate;
+ int written = play(ao, paddingbuf, ao->buffer.len + extralen, 0);
+ if (written < ao->buffer.len) {
+ mp_msg(MSGT_ENCODE, MSGL_ERR,
+ "ao-lavc: did not write enough data at the end\n");
+ }
talloc_free(paddingbuf);
ao->buffer.len = 0;
}
- while (encode(ao, pts, NULL) > 0) ;
+
+ double outpts = ac->expected_next_pts;
+ if (!ectx->options->rawts && ectx->options->copyts)
+ outpts += ectx->discontinuity_pts_offset;
+ outpts += encode_lavc_getoffset(ectx, ac->stream);
+
+ while (encode(ao, outpts, NULL) > 0) ;
}
ao->priv = NULL;
@@ -381,12 +370,6 @@ static int encode(struct ao *ao, double apts, void *data)
int status, gotpacket;
ac->aframecount++;
- if (data && (ao->channels == 5 || ao->channels == 6 || ao->channels == 8)) {
- reorder_channel_nch(data, AF_CHANNEL_LAYOUT_MPLAYER_DEFAULT,
- AF_CHANNEL_LAYOUT_LAVC_DEFAULT,
- ao->channels,
- ac->aframesize * ao->channels, ac->sample_size);
- }
if (data)
ectx->audio_pts_offset = realapts - apts;
@@ -400,12 +383,18 @@ static int encode(struct ao *ao, double apts, void *data)
frame->nb_samples = ac->aframesize;
if (ac->planarize) {
- void *data2 = talloc_size(ao, ac->aframesize * ao->channels * ac->sample_size);
- reorder_to_planar(data2, data, ac->sample_size, ao->channels, ac->aframesize);
+ void *data2 = talloc_size(ao, ac->aframesize * ao->channels.num *
+ ac->sample_size);
+ reorder_to_planar(data2, data, ac->sample_size, ao->channels.num,
+ ac->aframesize);
data = data2;
}
- if (avcodec_fill_audio_frame(frame, ao->channels, ac->stream->codec->sample_fmt, data, ac->aframesize * ao->channels * ac->sample_size, 1)) {
+ size_t audiolen = ac->aframesize * ao->channels.num * ac->sample_size;
+ if (avcodec_fill_audio_frame(frame, ao->channels.num,
+ ac->stream->codec->sample_fmt, data,
+ audiolen, 1))
+ {
mp_msg(MSGT_ENCODE, MSGL_ERR, "ao-lavc: error filling\n");
return -1;
}
@@ -512,15 +501,16 @@ static int play(struct ao *ao, void *data, int len, int flags)
double pts = ao->pts;
double outpts;
- len /= ac->sample_size * ao->channels;
+ len /= ac->sample_size * ao->channels.num;
if (!encode_lavc_start(ectx)) {
mp_msg(MSGT_ENCODE, MSGL_WARN,
- "ao-lavc: not ready yet for encoding audio\n");
+ "ao-lavc: not ready yet for encoding audio\n");
return 0;
}
if (pts == MP_NOPTS_VALUE) {
- mp_msg(MSGT_ENCODE, MSGL_WARN, "ao-lavc: frame without pts, please report; synthesizing pts instead\n");
+ mp_msg(MSGT_ENCODE, MSGL_WARN,
+ "ao-lavc: frame without pts, please report; synthesizing pts instead\n");
// synthesize pts from previous expected next pts
pts = ac->expected_next_pts;
}
@@ -581,7 +571,7 @@ static int play(struct ao *ao, void *data, int len, int flags)
if (ac->offset_left <= -len) {
// skip whole frame
ac->offset_left += len;
- return len * ac->sample_size * ao->channels;
+ return len * ac->sample_size * ao->channels.num;
} else {
// skip part of this frame, buffer/encode the rest
bufpos -= ac->offset_left;
@@ -592,11 +582,11 @@ static int play(struct ao *ao, void *data, int len, int flags)
// make a temporary buffer, filled with zeroes at the start
// (don't worry, only happens once)
- paddingbuf = talloc_size(ac, ac->sample_size * ao->channels *
+ paddingbuf = talloc_size(ac, ac->sample_size * ao->channels.num *
(ac->offset_left + len));
fill_with_padding(paddingbuf, ac->offset_left, ac->sample_size,
ac->sample_padding);
- data = (char *) paddingbuf + ac->sample_size * ao->channels *
+ data = (char *) paddingbuf + ac->sample_size * ao->channels.num *
ac->offset_left;
bufpos -= ac->offset_left; // yes, negati