[Pkg-mpd-commits] [pkg-mpd] 01/07: Imported Upstream version 0.19.18

Florian Schlichting fsfs at moszumanska.debian.org
Thu Aug 18 21:55:27 UTC 2016


This is an automated email from the git hooks/post-receive script.

fsfs pushed a commit to branch master
in repository pkg-mpd.

commit 7be2afa7debb811219abf16d67b5947ba88812aa
Author: Florian Schlichting <fsfs at debian.org>
Date:   Thu Aug 18 22:52:40 2016 +0200

    Imported Upstream version 0.19.18
---
 INSTALL                                            |   2 +-
 Makefile.am                                        |  12 +-
 Makefile.in                                        | 171 ++++-
 NEWS                                               |  15 +
 config.h.in                                        |   3 +
 configure                                          | 256 +++++---
 configure.ac                                       |  35 +-
 doc/developer.xml                                  |   2 +-
 doc/doxygen.conf                                   |   2 +-
 doc/mpdconf.example                                |   2 +-
 src/Compiler.h                                     |   2 +-
 src/archive/plugins/Bzip2ArchivePlugin.cxx         |   2 +-
 src/db/update/ExcludeList.cxx                      |   2 +
 src/decoder/DecoderThread.cxx                      |   1 +
 src/decoder/plugins/FfmpegDecoderPlugin.cxx        | 707 +++++++++++----------
 src/decoder/plugins/FfmpegIo.cxx                   | 100 +++
 .../plugins/{FfmpegMetaData.hxx => FfmpegIo.hxx}   |  34 +-
 src/decoder/plugins/FfmpegMetaData.cxx             |  32 +-
 src/decoder/plugins/FfmpegMetaData.hxx             |   4 +-
 src/decoder/plugins/SidplayDecoderPlugin.cxx       | 382 ++++++-----
 src/fs/AllocatedPath.hxx                           |   2 +-
 src/fs/Path.hxx                                    |  20 +-
 .../plugins/FfmpegMetaData.hxx => fs/Path2.cxx}    |  24 +-
 .../FfmpegMetaData.hxx => lib/ffmpeg/Buffer.hxx}   |  48 +-
 .../FfmpegMetaData.hxx => lib/ffmpeg/Init.cxx}     |  26 +-
 .../FfmpegMetaData.hxx => lib/ffmpeg/Init.hxx}     |  18 +-
 src/lib/ffmpeg/LogCallback.cxx                     |  66 ++
 .../ffmpeg/LogCallback.hxx}                        |  18 +-
 .../FfmpegMetaData.hxx => lib/ffmpeg/LogError.cxx} |  33 +-
 .../FfmpegMetaData.hxx => lib/ffmpeg/LogError.hxx} |  19 +-
 src/lib/ffmpeg/Time.hxx                            | 104 +++
 src/lib/nfs/Manager.cxx                            |  12 +
 src/lib/nfs/Manager.hxx                            |   4 +
 src/output/plugins/ShoutOutputPlugin.cxx           |   4 +-
 .../FfmpegMetaData.hxx => pcm/Interleave.cxx}      |  41 +-
 .../FfmpegMetaData.hxx => pcm/Interleave.hxx}      |  25 +-
 src/util/ScopeExit.hxx                             |  89 +++
 37 files changed, 1534 insertions(+), 785 deletions(-)

diff --git a/INSTALL b/INSTALL
index a45c4fb..97107ba 100644
--- a/INSTALL
+++ b/INSTALL
@@ -12,7 +12,7 @@ install MPD.  If more information is desired, read the user manual:
 Dependencies
 ------------
 
-gcc 4.6 or later - http://gcc.gnu.org/
+gcc 4.7 or later - http://gcc.gnu.org/
 clang 3.2 or later - http://clang.llvm.org/
 Any other C++11 compliant compiler should also work.
 
diff --git a/Makefile.am b/Makefile.am
index 7cd68f8..744b966 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -359,6 +359,7 @@ libutil_a_SOURCES = \
 	src/util/Clamp.hxx \
 	src/util/Alloc.cxx src/util/Alloc.hxx \
 	src/util/VarSize.hxx \
+	src/util/ScopeExit.hxx \
 	src/util/Error.cxx src/util/Error.hxx \
 	src/util/Domain.hxx \
 	src/util/ReusableArray.hxx \
@@ -462,6 +463,7 @@ ICU_LDADD = libicu.a $(ICU_LIBS)
 libpcm_a_SOURCES = \
 	src/pcm/Domain.cxx src/pcm/Domain.hxx \
 	src/pcm/Traits.hxx \
+	src/pcm/Interleave.cxx src/pcm/Interleave.hxx \
 	src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
 	src/pcm/PcmExport.cxx src/pcm/PcmExport.hxx \
 	src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
@@ -528,7 +530,7 @@ libfs_a_SOURCES = \
 	src/fs/Traits.cxx src/fs/Traits.hxx \
 	src/fs/Config.cxx src/fs/Config.hxx \
 	src/fs/Charset.cxx src/fs/Charset.hxx \
-	src/fs/Path.cxx src/fs/Path.hxx \
+	src/fs/Path.cxx src/fs/Path2.cxx src/fs/Path.hxx \
 	src/fs/AllocatedPath.cxx src/fs/AllocatedPath.hxx \
 	src/fs/FileSystem.cxx src/fs/FileSystem.hxx \
 	src/fs/StandardDirectory.cxx src/fs/StandardDirectory.hxx \
@@ -799,6 +801,11 @@ endif
 if HAVE_FFMPEG
 noinst_LIBRARIES += libffmpeg.a
 libffmpeg_a_SOURCES = \
+	src/lib/ffmpeg/Init.cxx src/lib/ffmpeg/Init.hxx \
+	src/lib/ffmpeg/Time.hxx \
+	src/lib/ffmpeg/Buffer.hxx \
+	src/lib/ffmpeg/LogError.cxx src/lib/ffmpeg/LogError.hxx \
+	src/lib/ffmpeg/LogCallback.cxx src/lib/ffmpeg/LogCallback.hxx \
 	src/lib/ffmpeg/Error.cxx src/lib/ffmpeg/Error.hxx \
 	src/lib/ffmpeg/Domain.cxx src/lib/ffmpeg/Domain.hxx
 libffmpeg_a_CPPFLAGS = $(AM_CPPFLAGS) \
@@ -980,6 +987,8 @@ endif
 
 if HAVE_FFMPEG
 libdecoder_a_SOURCES += \
+	src/decoder/plugins/FfmpegIo.cxx \
+	src/decoder/plugins/FfmpegIo.hxx \
 	src/decoder/plugins/FfmpegMetaData.cxx \
 	src/decoder/plugins/FfmpegMetaData.hxx \
 	src/decoder/plugins/FfmpegDecoderPlugin.cxx \
@@ -1867,6 +1876,7 @@ test_run_convert_SOURCES = test/run_convert.cxx \
 	src/AudioParser.cxx
 test_run_convert_LDADD = \
 	$(PCM_LIBS) \
+	libconf.a \
 	libutil.a \
 	$(GLIB_LIBS)
 
diff --git a/Makefile.in b/Makefile.in
index 840ba0c..7e06e9b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -328,6 +328,8 @@ host_triplet = @host@
 @ENABLE_WILDMIDI_TRUE@	src/decoder/plugins/WildmidiDecoderPlugin.hxx
 
 @HAVE_FFMPEG_TRUE at am__append_50 = \
+ at HAVE_FFMPEG_TRUE@	src/decoder/plugins/FfmpegIo.cxx \
+ at HAVE_FFMPEG_TRUE@	src/decoder/plugins/FfmpegIo.hxx \
 @HAVE_FFMPEG_TRUE@	src/decoder/plugins/FfmpegMetaData.cxx \
 @HAVE_FFMPEG_TRUE@	src/decoder/plugins/FfmpegMetaData.hxx \
 @HAVE_FFMPEG_TRUE@	src/decoder/plugins/FfmpegDecoderPlugin.cxx \
@@ -784,6 +786,8 @@ am__libdecoder_a_SOURCES_DIST =  \
 	src/decoder/plugins/FluidsynthDecoderPlugin.hxx \
 	src/decoder/plugins/WildmidiDecoderPlugin.cxx \
 	src/decoder/plugins/WildmidiDecoderPlugin.hxx \
+	src/decoder/plugins/FfmpegIo.cxx \
+	src/decoder/plugins/FfmpegIo.hxx \
 	src/decoder/plugins/FfmpegMetaData.cxx \
 	src/decoder/plugins/FfmpegMetaData.hxx \
 	src/decoder/plugins/FfmpegDecoderPlugin.cxx \
@@ -824,7 +828,8 @@ am__libdecoder_a_SOURCES_DIST =  \
 @ENABLE_SIDPLAY_TRUE at am__objects_20 = src/decoder/plugins/libdecoder_a-SidplayDecoderPlugin.$(OBJEXT)
 @ENABLE_FLUIDSYNTH_TRUE at am__objects_21 = src/decoder/plugins/libdecoder_a-FluidsynthDecoderPlugin.$(OBJEXT)
 @ENABLE_WILDMIDI_TRUE at am__objects_22 = src/decoder/plugins/libdecoder_a-WildmidiDecoderPlugin.$(OBJEXT)
- at HAVE_FFMPEG_TRUE@am__objects_23 = src/decoder/plugins/libdecoder_a-FfmpegMetaData.$(OBJEXT) \
+ at HAVE_FFMPEG_TRUE@am__objects_23 = src/decoder/plugins/libdecoder_a-FfmpegIo.$(OBJEXT) \
+ at HAVE_FFMPEG_TRUE@	src/decoder/plugins/libdecoder_a-FfmpegMetaData.$(OBJEXT) \
 @HAVE_FFMPEG_TRUE@	src/decoder/plugins/libdecoder_a-FfmpegDecoderPlugin.$(OBJEXT)
 @ENABLE_SNDFILE_TRUE at am__objects_24 = src/decoder/plugins/libdecoder_a-SndfileDecoderPlugin.$(OBJEXT)
 @HAVE_GME_TRUE at am__objects_25 = src/decoder/plugins/libdecoder_a-GmeDecoderPlugin.$(OBJEXT)
@@ -897,10 +902,17 @@ am_libevent_a_OBJECTS = src/event/PollGroupPoll.$(OBJEXT) \
 libevent_a_OBJECTS = $(am_libevent_a_OBJECTS)
 libffmpeg_a_AR = $(AR) $(ARFLAGS)
 libffmpeg_a_LIBADD =
-am__libffmpeg_a_SOURCES_DIST = src/lib/ffmpeg/Error.cxx \
+am__libffmpeg_a_SOURCES_DIST = src/lib/ffmpeg/Init.cxx \
+	src/lib/ffmpeg/Init.hxx src/lib/ffmpeg/Time.hxx \
+	src/lib/ffmpeg/Buffer.hxx src/lib/ffmpeg/LogError.cxx \
+	src/lib/ffmpeg/LogError.hxx src/lib/ffmpeg/LogCallback.cxx \
+	src/lib/ffmpeg/LogCallback.hxx src/lib/ffmpeg/Error.cxx \
 	src/lib/ffmpeg/Error.hxx src/lib/ffmpeg/Domain.cxx \
 	src/lib/ffmpeg/Domain.hxx
 @HAVE_FFMPEG_TRUE at am_libffmpeg_a_OBJECTS =  \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/libffmpeg_a-Init.$(OBJEXT) \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/libffmpeg_a-LogError.$(OBJEXT) \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/libffmpeg_a-LogCallback.$(OBJEXT) \
 @HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/libffmpeg_a-Error.$(OBJEXT) \
 @HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/libffmpeg_a-Domain.$(OBJEXT)
 libffmpeg_a_OBJECTS = $(am_libffmpeg_a_OBJECTS)
@@ -930,7 +942,7 @@ am__libfs_a_SOURCES_DIST = src/fs/io/Reader.hxx \
 	src/fs/Domain.hxx src/fs/Limits.hxx src/fs/Traits.cxx \
 	src/fs/Traits.hxx src/fs/Config.cxx src/fs/Config.hxx \
 	src/fs/Charset.cxx src/fs/Charset.hxx src/fs/Path.cxx \
-	src/fs/Path.hxx src/fs/AllocatedPath.cxx \
+	src/fs/Path2.cxx src/fs/Path.hxx src/fs/AllocatedPath.cxx \
 	src/fs/AllocatedPath.hxx src/fs/FileSystem.cxx \
 	src/fs/FileSystem.hxx src/fs/StandardDirectory.cxx \
 	src/fs/StandardDirectory.hxx src/fs/CheckFile.cxx \
@@ -954,6 +966,7 @@ am_libfs_a_OBJECTS = src/fs/io/libfs_a-PeekReader.$(OBJEXT) \
 	src/fs/libfs_a-Traits.$(OBJEXT) \
 	src/fs/libfs_a-Config.$(OBJEXT) \
 	src/fs/libfs_a-Charset.$(OBJEXT) src/fs/libfs_a-Path.$(OBJEXT) \
+	src/fs/libfs_a-Path2.$(OBJEXT) \
 	src/fs/libfs_a-AllocatedPath.$(OBJEXT) \
 	src/fs/libfs_a-FileSystem.$(OBJEXT) \
 	src/fs/libfs_a-StandardDirectory.$(OBJEXT) \
@@ -1521,14 +1534,15 @@ liboutput_plugins_a_OBJECTS = $(am_liboutput_plugins_a_OBJECTS)
 libpcm_a_AR = $(AR) $(ARFLAGS)
 libpcm_a_LIBADD =
 am__libpcm_a_SOURCES_DIST = src/pcm/Domain.cxx src/pcm/Domain.hxx \
-	src/pcm/Traits.hxx src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
-	src/pcm/PcmExport.cxx src/pcm/PcmExport.hxx \
-	src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
-	src/pcm/PcmDop.cxx src/pcm/PcmDop.hxx src/pcm/Volume.cxx \
-	src/pcm/Volume.hxx src/pcm/Silence.cxx src/pcm/Silence.hxx \
-	src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx src/pcm/PcmChannels.cxx \
-	src/pcm/PcmChannels.hxx src/pcm/PcmPack.cxx \
-	src/pcm/PcmPack.hxx src/pcm/PcmFormat.cxx \
+	src/pcm/Traits.hxx src/pcm/Interleave.cxx \
+	src/pcm/Interleave.hxx src/pcm/PcmBuffer.cxx \
+	src/pcm/PcmBuffer.hxx src/pcm/PcmExport.cxx \
+	src/pcm/PcmExport.hxx src/pcm/PcmConvert.cxx \
+	src/pcm/PcmConvert.hxx src/pcm/PcmDop.cxx src/pcm/PcmDop.hxx \
+	src/pcm/Volume.cxx src/pcm/Volume.hxx src/pcm/Silence.cxx \
+	src/pcm/Silence.hxx src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx \
+	src/pcm/PcmChannels.cxx src/pcm/PcmChannels.hxx \
+	src/pcm/PcmPack.cxx src/pcm/PcmPack.hxx src/pcm/PcmFormat.cxx \
 	src/pcm/PcmFormat.hxx src/pcm/FloatConvert.hxx \
 	src/pcm/ShiftConvert.hxx src/pcm/Neon.hxx \
 	src/pcm/FormatConverter.cxx src/pcm/FormatConverter.hxx \
@@ -1549,6 +1563,7 @@ am__libpcm_a_SOURCES_DIST = src/pcm/Domain.cxx src/pcm/Domain.hxx \
 @HAVE_SOXR_TRUE at am__objects_83 =  \
 @HAVE_SOXR_TRUE@	src/pcm/libpcm_a-SoxrResampler.$(OBJEXT)
 am_libpcm_a_OBJECTS = src/pcm/libpcm_a-Domain.$(OBJEXT) \
+	src/pcm/libpcm_a-Interleave.$(OBJEXT) \
 	src/pcm/libpcm_a-PcmBuffer.$(OBJEXT) \
 	src/pcm/libpcm_a-PcmExport.$(OBJEXT) \
 	src/pcm/libpcm_a-PcmConvert.$(OBJEXT) \
@@ -2008,7 +2023,7 @@ am__test_run_convert_SOURCES_DIST = test/run_convert.cxx src/Log.cxx \
 @ENABLE_TEST_TRUE@	src/AudioParser.$(OBJEXT)
 test_run_convert_OBJECTS = $(am_test_run_convert_OBJECTS)
 @ENABLE_TEST_TRUE at test_run_convert_DEPENDENCIES =  \
- at ENABLE_TEST_TRUE@	$(am__DEPENDENCIES_17) libutil.a \
+ at ENABLE_TEST_TRUE@	$(am__DEPENDENCIES_17) libconf.a libutil.a \
 @ENABLE_TEST_TRUE@	$(am__DEPENDENCIES_1)
 am__test_run_decoder_SOURCES_DIST = test/run_decoder.cxx \
 	test/FakeDecoderAPI.cxx test/FakeDecoderAPI.hxx \
@@ -3186,6 +3201,7 @@ libutil_a_SOURCES = \
 	src/util/Clamp.hxx \
 	src/util/Alloc.cxx src/util/Alloc.hxx \
 	src/util/VarSize.hxx \
+	src/util/ScopeExit.hxx \
 	src/util/Error.cxx src/util/Error.hxx \
 	src/util/Domain.hxx \
 	src/util/ReusableArray.hxx \
@@ -3279,14 +3295,15 @@ ICU_LDADD = libicu.a $(ICU_LIBS)
 
 # PCM library
 libpcm_a_SOURCES = src/pcm/Domain.cxx src/pcm/Domain.hxx \
-	src/pcm/Traits.hxx src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
-	src/pcm/PcmExport.cxx src/pcm/PcmExport.hxx \
-	src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
-	src/pcm/PcmDop.cxx src/pcm/PcmDop.hxx src/pcm/Volume.cxx \
-	src/pcm/Volume.hxx src/pcm/Silence.cxx src/pcm/Silence.hxx \
-	src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx src/pcm/PcmChannels.cxx \
-	src/pcm/PcmChannels.hxx src/pcm/PcmPack.cxx \
-	src/pcm/PcmPack.hxx src/pcm/PcmFormat.cxx \
+	src/pcm/Traits.hxx src/pcm/Interleave.cxx \
+	src/pcm/Interleave.hxx src/pcm/PcmBuffer.cxx \
+	src/pcm/PcmBuffer.hxx src/pcm/PcmExport.cxx \
+	src/pcm/PcmExport.hxx src/pcm/PcmConvert.cxx \
+	src/pcm/PcmConvert.hxx src/pcm/PcmDop.cxx src/pcm/PcmDop.hxx \
+	src/pcm/Volume.cxx src/pcm/Volume.hxx src/pcm/Silence.cxx \
+	src/pcm/Silence.hxx src/pcm/PcmMix.cxx src/pcm/PcmMix.hxx \
+	src/pcm/PcmChannels.cxx src/pcm/PcmChannels.hxx \
+	src/pcm/PcmPack.cxx src/pcm/PcmPack.hxx src/pcm/PcmFormat.cxx \
 	src/pcm/PcmFormat.hxx src/pcm/FloatConvert.hxx \
 	src/pcm/ShiftConvert.hxx src/pcm/Neon.hxx \
 	src/pcm/FormatConverter.cxx src/pcm/FormatConverter.hxx \
@@ -3321,7 +3338,7 @@ libfs_a_SOURCES = src/fs/io/Reader.hxx src/fs/io/PeekReader.cxx \
 	src/fs/Domain.hxx src/fs/Limits.hxx src/fs/Traits.cxx \
 	src/fs/Traits.hxx src/fs/Config.cxx src/fs/Config.hxx \
 	src/fs/Charset.cxx src/fs/Charset.hxx src/fs/Path.cxx \
-	src/fs/Path.hxx src/fs/AllocatedPath.cxx \
+	src/fs/Path2.cxx src/fs/Path.hxx src/fs/AllocatedPath.cxx \
 	src/fs/AllocatedPath.hxx src/fs/FileSystem.cxx \
 	src/fs/FileSystem.hxx src/fs/StandardDirectory.cxx \
 	src/fs/StandardDirectory.hxx src/fs/CheckFile.cxx \
@@ -3479,6 +3496,11 @@ libtag_a_SOURCES = src/tag/TagType.h src/tag/Tag.cxx src/tag/Tag.hxx \
 	src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
 	src/tag/ApeTag.cxx src/tag/ApeTag.hxx $(am__append_30)
 @HAVE_FFMPEG_TRUE at libffmpeg_a_SOURCES = \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/Init.cxx src/lib/ffmpeg/Init.hxx \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/Time.hxx \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/Buffer.hxx \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/LogError.cxx src/lib/ffmpeg/LogError.hxx \
+ at HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/LogCallback.cxx src/lib/ffmpeg/LogCallback.hxx \
 @HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/Error.cxx src/lib/ffmpeg/Error.hxx \
 @HAVE_FFMPEG_TRUE@	src/lib/ffmpeg/Domain.cxx src/lib/ffmpeg/Domain.hxx
 
@@ -4057,6 +4079,7 @@ FILTER_LIBS = \
 
 @ENABLE_TEST_TRUE at test_run_convert_LDADD = \
 @ENABLE_TEST_TRUE@	$(PCM_LIBS) \
+ at ENABLE_TEST_TRUE@	libconf.a \
 @ENABLE_TEST_TRUE@	libutil.a \
 @ENABLE_TEST_TRUE@	$(GLIB_LIBS)
 
@@ -4676,6 +4699,9 @@ src/decoder/plugins/libdecoder_a-FluidsynthDecoderPlugin.$(OBJEXT):  \
 src/decoder/plugins/libdecoder_a-WildmidiDecoderPlugin.$(OBJEXT):  \
 	src/decoder/plugins/$(am__dirstamp) \
 	src/decoder/plugins/$(DEPDIR)/$(am__dirstamp)
+src/decoder/plugins/libdecoder_a-FfmpegIo.$(OBJEXT):  \
+	src/decoder/plugins/$(am__dirstamp) \
+	src/decoder/plugins/$(DEPDIR)/$(am__dirstamp)
 src/decoder/plugins/libdecoder_a-FfmpegMetaData.$(OBJEXT):  \
 	src/decoder/plugins/$(am__dirstamp) \
 	src/decoder/plugins/$(DEPDIR)/$(am__dirstamp)
@@ -4783,6 +4809,15 @@ src/lib/ffmpeg/$(am__dirstamp):
 src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) src/lib/ffmpeg/$(DEPDIR)
 	@: > src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp)
+src/lib/ffmpeg/libffmpeg_a-Init.$(OBJEXT):  \
+	src/lib/ffmpeg/$(am__dirstamp) \
+	src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp)
+src/lib/ffmpeg/libffmpeg_a-LogError.$(OBJEXT):  \
+	src/lib/ffmpeg/$(am__dirstamp) \
+	src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp)
+src/lib/ffmpeg/libffmpeg_a-LogCallback.$(OBJEXT):  \
+	src/lib/ffmpeg/$(am__dirstamp) \
+	src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp)
 src/lib/ffmpeg/libffmpeg_a-Error.$(OBJEXT):  \
 	src/lib/ffmpeg/$(am__dirstamp) \
 	src/lib/ffmpeg/$(DEPDIR)/$(am__dirstamp)
@@ -4872,6 +4907,8 @@ src/fs/libfs_a-Charset.$(OBJEXT): src/fs/$(am__dirstamp) \
 	src/fs/$(DEPDIR)/$(am__dirstamp)
 src/fs/libfs_a-Path.$(OBJEXT): src/fs/$(am__dirstamp) \
 	src/fs/$(DEPDIR)/$(am__dirstamp)
+src/fs/libfs_a-Path2.$(OBJEXT): src/fs/$(am__dirstamp) \
+	src/fs/$(DEPDIR)/$(am__dirstamp)
 src/fs/libfs_a-AllocatedPath.$(OBJEXT): src/fs/$(am__dirstamp) \
 	src/fs/$(DEPDIR)/$(am__dirstamp)
 src/fs/libfs_a-FileSystem.$(OBJEXT): src/fs/$(am__dirstamp) \
@@ -5678,6 +5715,8 @@ src/pcm/$(DEPDIR)/$(am__dirstamp):
 	@: > src/pcm/$(DEPDIR)/$(am__dirstamp)
 src/pcm/libpcm_a-Domain.$(OBJEXT): src/pcm/$(am__dirstamp) \
 	src/pcm/$(DEPDIR)/$(am__dirstamp)
+src/pcm/libpcm_a-Interleave.$(OBJEXT): src/pcm/$(am__dirstamp) \
+	src/pcm/$(DEPDIR)/$(am__dirstamp)
 src/pcm/libpcm_a-PcmBuffer.$(OBJEXT): src/pcm/$(am__dirstamp) \
 	src/pcm/$(DEPDIR)/$(am__dirstamp)
 src/pcm/libpcm_a-PcmExport.$(OBJEXT): src/pcm/$(am__dirstamp) \
@@ -6668,6 +6707,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-DsfDecoderPlugin.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FaadDecoderPlugin.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegDecoderPlugin.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegMetaData.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FlacCommon.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/decoder/plugins/$(DEPDIR)/libdecoder_a-FlacDecoderPlugin.Po at am__quote@
@@ -6743,6 +6783,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-Domain.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-FileSystem.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-Path.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-Path2.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-StandardDirectory.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/$(DEPDIR)/libfs_a-Traits.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/fs/io/$(DEPDIR)/libfs_a-AutoGunzipReader.Po at am__quote@
@@ -6783,6 +6824,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/expat/$(DEPDIR)/libplaylist_plugins_a-ExpatParser.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Domain.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Error.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/icu/$(DEPDIR)/libicu_a-Collate.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/icu/$(DEPDIR)/libicu_a-Error.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/lib/icu/$(DEPDIR)/libicu_a-Init.Po at am__quote@
@@ -6885,6 +6929,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-FallbackResampler.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-FormatConverter.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-GlueResampler.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-Interleave.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-LibsamplerateResampler.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-PcmBuffer.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/pcm/$(DEPDIR)/libpcm_a-PcmChannels.Po at am__quote@
@@ -7767,6 +7812,20 @@ src/decoder/plugins/libdecoder_a-WildmidiDecoderPlugin.obj: src/decoder/plugins/
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/decoder/plugins/libdecoder_a-WildmidiDecoderPlugin.obj `if test -f 'src/decoder/plugins/WildmidiDecoderPlugin.cxx'; then $(CYGPATH_W) 'src/decoder/plugins/WildmidiDecoderPlugin.cxx'; else $(CYGPATH_W) '$(srcdir)/src/decoder/plugins/WildmidiDecoderPlugin.cxx'; fi`
 
+src/decoder/plugins/libdecoder_a-FfmpegIo.o: src/decoder/plugins/FfmpegIo.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/decoder/plugins/libdecoder_a-FfmpegIo.o -MD -MP -MF src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Tpo -c -o src/decoder/plugins/libdecoder_a-FfmpegIo.o `test -f 'src/decoder/plugins/FfmpegIo.cxx' || echo '$(srcdir)/'`src/decoder/plugins/FfmpegIo.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Tpo src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/decoder/plugins/FfmpegIo.cxx' object='src/decoder/plugins/libdecoder_a-FfmpegIo.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/decoder/plugins/libdecoder_a-FfmpegIo.o `test -f 'src/decoder/plugins/FfmpegIo.cxx' || echo '$(srcdir)/'`src/decoder/plugins/FfmpegIo.cxx
+
+src/decoder/plugins/libdecoder_a-FfmpegIo.obj: src/decoder/plugins/FfmpegIo.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/decoder/plugins/libdecoder_a-FfmpegIo.obj -MD -MP -MF src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Tpo -c -o src/decoder/plugins/libdecoder_a-FfmpegIo.obj `if test -f 'src/decoder/plugins/FfmpegIo.cxx'; then $(CYGPATH_W) 'src/decoder/plugins/FfmpegIo.cxx'; else $(CYGPATH_W) '$(srcdir)/src/decoder/plugins/FfmpegIo.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Tpo src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegIo.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/decoder/plugins/FfmpegIo.cxx' object='src/decoder/plugins/libdecoder_a-FfmpegIo.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/decoder/plugins/libdecoder_a-FfmpegIo.obj `if test -f 'src/decoder/plugins/FfmpegIo.cxx'; then $(CYGPATH_W) 'src/decoder/plugins/FfmpegIo.cxx'; else $(CYGPATH_W) '$(srcdir)/src/decoder/plugins/FfmpegIo.cxx'; fi`
+
 src/decoder/plugins/libdecoder_a-FfmpegMetaData.o: src/decoder/plugins/FfmpegMetaData.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdecoder_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/decoder/plugins/libdecoder_a-FfmpegMetaData.o -MD -MP -MF src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegMetaData.Tpo -c -o src/decoder/plugins/libdecoder_a-FfmpegMetaData.o `test -f 'src/decoder/plugins/FfmpegMetaData.cxx' || echo '$(srcdir)/'`src/decoder/plugins/FfmpegMetaData.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegMetaData.Tpo src/decoder/plugins/$(DEPDIR)/libdecoder_a-FfmpegMetaData.Po
@@ -7963,6 +8022,48 @@ src/encoder/plugins/libencoder_plugins_a-ShineEncoderPlugin.obj: src/encoder/plu
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libencoder_plugins_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/encoder/plugins/libencoder_plugins_a-ShineEncoderPlugin.obj `if test -f 'src/encoder/plugins/ShineEncoderPlugin.cxx'; then $(CYGPATH_W) 'src/encoder/plugins/ShineEncoderPlugin.cxx'; else $(CYGPATH_W) '$(srcdir)/src/encoder/plugins/ShineEncoderPlugin.cxx'; fi`
 
+src/lib/ffmpeg/libffmpeg_a-Init.o: src/lib/ffmpeg/Init.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-Init.o -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-Init.o `test -f 'src/lib/ffmpeg/Init.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/Init.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/Init.cxx' object='src/lib/ffmpeg/libffmpeg_a-Init.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-Init.o `test -f 'src/lib/ffmpeg/Init.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/Init.cxx
+
+src/lib/ffmpeg/libffmpeg_a-Init.obj: src/lib/ffmpeg/Init.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-Init.obj -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-Init.obj `if test -f 'src/lib/ffmpeg/Init.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/Init.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/Init.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Init.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/Init.cxx' object='src/lib/ffmpeg/libffmpeg_a-Init.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-Init.obj `if test -f 'src/lib/ffmpeg/Init.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/Init.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/Init.cxx'; fi`
+
+src/lib/ffmpeg/libffmpeg_a-LogError.o: src/lib/ffmpeg/LogError.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-LogError.o -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-LogError.o `test -f 'src/lib/ffmpeg/LogError.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/LogError.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/LogError.cxx' object='src/lib/ffmpeg/libffmpeg_a-LogError.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-LogError.o `test -f 'src/lib/ffmpeg/LogError.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/LogError.cxx
+
+src/lib/ffmpeg/libffmpeg_a-LogError.obj: src/lib/ffmpeg/LogError.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-LogError.obj -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-LogError.obj `if test -f 'src/lib/ffmpeg/LogError.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/LogError.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/LogError.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogError.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/LogError.cxx' object='src/lib/ffmpeg/libffmpeg_a-LogError.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-LogError.obj `if test -f 'src/lib/ffmpeg/LogError.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/LogError.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/LogError.cxx'; fi`
+
+src/lib/ffmpeg/libffmpeg_a-LogCallback.o: src/lib/ffmpeg/LogCallback.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-LogCallback.o -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-LogCallback.o `test -f 'src/lib/ffmpeg/LogCallback.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/LogCallback.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/LogCallback.cxx' object='src/lib/ffmpeg/libffmpeg_a-LogCallback.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-LogCallback.o `test -f 'src/lib/ffmpeg/LogCallback.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/LogCallback.cxx
+
+src/lib/ffmpeg/libffmpeg_a-LogCallback.obj: src/lib/ffmpeg/LogCallback.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-LogCallback.obj -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-LogCallback.obj `if test -f 'src/lib/ffmpeg/LogCallback.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/LogCallback.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/LogCallback.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-LogCallback.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/lib/ffmpeg/LogCallback.cxx' object='src/lib/ffmpeg/libffmpeg_a-LogCallback.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/lib/ffmpeg/libffmpeg_a-LogCallback.obj `if test -f 'src/lib/ffmpeg/LogCallback.cxx'; then $(CYGPATH_W) 'src/lib/ffmpeg/LogCallback.cxx'; else $(CYGPATH_W) '$(srcdir)/src/lib/ffmpeg/LogCallback.cxx'; fi`
+
 src/lib/ffmpeg/libffmpeg_a-Error.o: src/lib/ffmpeg/Error.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libffmpeg_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/lib/ffmpeg/libffmpeg_a-Error.o -MD -MP -MF src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Error.Tpo -c -o src/lib/ffmpeg/libffmpeg_a-Error.o `test -f 'src/lib/ffmpeg/Error.cxx' || echo '$(srcdir)/'`src/lib/ffmpeg/Error.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Error.Tpo src/lib/ffmpeg/$(DEPDIR)/libffmpeg_a-Error.Po
@@ -8145,6 +8246,20 @@ src/fs/libfs_a-Path.obj: src/fs/Path.cxx
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/fs/libfs_a-Path.obj `if test -f 'src/fs/Path.cxx'; then $(CYGPATH_W) 'src/fs/Path.cxx'; else $(CYGPATH_W) '$(srcdir)/src/fs/Path.cxx'; fi`
 
+src/fs/libfs_a-Path2.o: src/fs/Path2.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/fs/libfs_a-Path2.o -MD -MP -MF src/fs/$(DEPDIR)/libfs_a-Path2.Tpo -c -o src/fs/libfs_a-Path2.o `test -f 'src/fs/Path2.cxx' || echo '$(srcdir)/'`src/fs/Path2.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/fs/$(DEPDIR)/libfs_a-Path2.Tpo src/fs/$(DEPDIR)/libfs_a-Path2.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/fs/Path2.cxx' object='src/fs/libfs_a-Path2.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/fs/libfs_a-Path2.o `test -f 'src/fs/Path2.cxx' || echo '$(srcdir)/'`src/fs/Path2.cxx
+
+src/fs/libfs_a-Path2.obj: src/fs/Path2.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/fs/libfs_a-Path2.obj -MD -MP -MF src/fs/$(DEPDIR)/libfs_a-Path2.Tpo -c -o src/fs/libfs_a-Path2.obj `if test -f 'src/fs/Path2.cxx'; then $(CYGPATH_W) 'src/fs/Path2.cxx'; else $(CYGPATH_W) '$(srcdir)/src/fs/Path2.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/fs/$(DEPDIR)/libfs_a-Path2.Tpo src/fs/$(DEPDIR)/libfs_a-Path2.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/fs/Path2.cxx' object='src/fs/libfs_a-Path2.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/fs/libfs_a-Path2.obj `if test -f 'src/fs/Path2.cxx'; then $(CYGPATH_W) 'src/fs/Path2.cxx'; else $(CYGPATH_W) '$(srcdir)/src/fs/Path2.cxx'; fi`
+
 src/fs/libfs_a-AllocatedPath.o: src/fs/AllocatedPath.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfs_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/fs/libfs_a-AllocatedPath.o -MD -MP -MF src/fs/$(DEPDIR)/libfs_a-AllocatedPath.Tpo -c -o src/fs/libfs_a-AllocatedPath.o `test -f 'src/fs/AllocatedPath.cxx' || echo '$(srcdir)/'`src/fs/AllocatedPath.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/fs/$(DEPDIR)/libfs_a-AllocatedPath.Tpo src/fs/$(DEPDIR)/libfs_a-AllocatedPath.Po
@@ -11477,6 +11592,20 @@ src/pcm/libpcm_a-Domain.obj: src/pcm/Domain.cxx
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/pcm/libpcm_a-Domain.obj `if test -f 'src/pcm/Domain.cxx'; then $(CYGPATH_W) 'src/pcm/Domain.cxx'; else $(CYGPATH_W) '$(srcdir)/src/pcm/Domain.cxx'; fi`
 
+src/pcm/libpcm_a-Interleave.o: src/pcm/Interleave.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/pcm/libpcm_a-Interleave.o -MD -MP -MF src/pcm/$(DEPDIR)/libpcm_a-Interleave.Tpo -c -o src/pcm/libpcm_a-Interleave.o `test -f 'src/pcm/Interleave.cxx' || echo '$(srcdir)/'`src/pcm/Interleave.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/pcm/$(DEPDIR)/libpcm_a-Interleave.Tpo src/pcm/$(DEPDIR)/libpcm_a-Interleave.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/pcm/Interleave.cxx' object='src/pcm/libpcm_a-Interleave.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/pcm/libpcm_a-Interleave.o `test -f 'src/pcm/Interleave.cxx' || echo '$(srcdir)/'`src/pcm/Interleave.cxx
+
+src/pcm/libpcm_a-Interleave.obj: src/pcm/Interleave.cxx
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/pcm/libpcm_a-Interleave.obj -MD -MP -MF src/pcm/$(DEPDIR)/libpcm_a-Interleave.Tpo -c -o src/pcm/libpcm_a-Interleave.obj `if test -f 'src/pcm/Interleave.cxx'; then $(CYGPATH_W) 'src/pcm/Interleave.cxx'; else $(CYGPATH_W) '$(srcdir)/src/pcm/Interleave.cxx'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/pcm/$(DEPDIR)/libpcm_a-Interleave.Tpo src/pcm/$(DEPDIR)/libpcm_a-Interleave.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='src/pcm/Interleave.cxx' object='src/pcm/libpcm_a-Interleave.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/pcm/libpcm_a-Interleave.obj `if test -f 'src/pcm/Interleave.cxx'; then $(CYGPATH_W) 'src/pcm/Interleave.cxx'; else $(CYGPATH_W) '$(srcdir)/src/pcm/Interleave.cxx'; fi`
+
 src/pcm/libpcm_a-PcmBuffer.o: src/pcm/PcmBuffer.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpcm_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/pcm/libpcm_a-PcmBuffer.o -MD -MP -MF src/pcm/$(DEPDIR)/libpcm_a-PcmBuffer.Tpo -c -o src/pcm/libpcm_a-PcmBuffer.o `test -f 'src/pcm/PcmBuffer.cxx' || echo '$(srcdir)/'`src/pcm/PcmBuffer.cxx
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) src/pcm/$(DEPDIR)/libpcm_a-PcmBuffer.Tpo src/pcm/$(DEPDIR)/libpcm_a-PcmBuffer.Po
diff --git a/NEWS b/NEWS
index df7493f..f490282 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+ver 0.19.18 (2016/08/05)
+* decoder
+  - ffmpeg: fix crash with older FFmpeg versions (< 3.0)
+  - ffmpeg: log detailed error message
+  - ffmpeg: support FFmpeg 3.1
+  - sidplay: detect libsidplay2 with pkg-config
+  - sidplay: log detailed error message
+  - sidplay: read the "date" tag
+  - sidplay: allow building with libsidplayfp instead of libsidplay2
+* output
+  - shout: recognize setting "encoder" instead of "encoding"
+* fix memory leak after stream failure
+* fix build failure with Boost 1.61
+* require gcc 4.7 or newer
+
 ver 0.19.17 (2016/07/09)
 * decoder
   - flac: fix assertion failure while seeking
diff --git a/config.h.in b/config.h.in
index 1acac96..155ad1c 100644
--- a/config.h.in
+++ b/config.h.in
@@ -270,6 +270,9 @@
 /* Define to enable the shoutcast output */
 #undef HAVE_SHOUT
 
+/* Define if libsidplayfp is used instead of libsidplay2 */
+#undef HAVE_SIDPLAYFP
+
 /* Define to enable libsoxr */
 #undef HAVE_SOXR
 
diff --git a/configure b/configure
index 8389a30..1a22fb8 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for mpd 0.19.17.
+# Generated by GNU Autoconf 2.69 for mpd 0.19.18.
 #
 # Report bugs to <musicpd-dev-team at lists.sourceforge.net>.
 #
@@ -580,8 +580,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='mpd'
 PACKAGE_TARNAME='mpd'
-PACKAGE_VERSION='0.19.17'
-PACKAGE_STRING='mpd 0.19.17'
+PACKAGE_VERSION='0.19.18'
+PACKAGE_STRING='mpd 0.19.18'
 PACKAGE_BUGREPORT='musicpd-dev-team at lists.sourceforge.net'
 PACKAGE_URL=''
 
@@ -712,8 +712,8 @@ WAVPACK_LIBS
 WAVPACK_CFLAGS
 ENABLE_SIDPLAY_FALSE
 ENABLE_SIDPLAY_TRUE
-SIDPLAY_CFLAGS
 SIDPLAY_LIBS
+SIDPLAY_CFLAGS
 ENABLE_VORBIS_DECODER_FALSE
 ENABLE_VORBIS_DECODER_TRUE
 VORBIS_LIBS
@@ -1185,6 +1185,8 @@ SNDFILE_CFLAGS
 SNDFILE_LIBS
 VORBIS_CFLAGS
 VORBIS_LIBS
+SIDPLAY_CFLAGS
+SIDPLAY_LIBS
 WAVPACK_CFLAGS
 WAVPACK_LIBS
 SHINE_CFLAGS
@@ -1757,7 +1759,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures mpd 0.19.17 to adapt to many kinds of systems.
+\`configure' configures mpd 0.19.18 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1828,7 +1830,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of mpd 0.19.17:";;
+     short | recursive ) echo "Configuration of mpd 0.19.18:";;
    esac
   cat <<\_ACEOF
 
@@ -2069,6 +2071,10 @@ Some influential environment variables:
   VORBIS_CFLAGS
               C compiler flags for VORBIS, overriding pkg-config
   VORBIS_LIBS linker flags for VORBIS, overriding pkg-config
+  SIDPLAY_CFLAGS
+              C compiler flags for SIDPLAY, overriding pkg-config
+  SIDPLAY_LIBS
+              linker flags for SIDPLAY, overriding pkg-config
   WAVPACK_CFLAGS
               C compiler flags for WAVPACK, overriding pkg-config
   WAVPACK_LIBS
@@ -2169,7 +2175,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-mpd configure 0.19.17
+mpd configure 0.19.18
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2622,7 +2628,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by mpd $as_me 0.19.17, which was
+It was created by mpd $as_me 0.19.18, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2973,7 +2979,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 VERSION_MAJOR=0
 VERSION_MINOR=19
-VERSION_REVISION=17
+VERSION_REVISION=18
 VERSION_EXTRA=0
 
 
@@ -3492,7 +3498,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='mpd'
- VERSION='0.19.17'
+ VERSION='0.19.18'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -8158,15 +8164,6 @@ else
 fi
 
 
-	if test x$enable_glib = xno; then
-		if test x$enable_sidplay = xauto; then
-			enable_sidplay=no
-		elif test x$enable_sidplay = xyes; then
-			as_fn_error $? "Cannot use --enable-sidplay with --disable-glib" "$LINENO" 5
-		fi
-	fi
-
-
 # Check whether --enable-shine-encoder was given.
 if test "${enable_shine_encoder+set}" = set; then :
   enableval=$enable_shine_encoder;
@@ -14460,44 +14457,152 @@ fi
 
 
 if test x$enable_sidplay != xno; then
-	# we're not using pkg-config here
-	# because libsidplay2's .pc file requires libtool
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsidplay2" >&5
-$as_echo_n "checking for main in -lsidplay2... " >&6; }
-if ${ac_cv_lib_sidplay2_main+:} false; then :
-  $as_echo_n "(cached) " >&6
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SIDPLAY" >&5
+$as_echo_n "checking for SIDPLAY... " >&6; }
+
+if test -n "$SIDPLAY_CFLAGS"; then
+    pkg_cv_SIDPLAY_CFLAGS="$SIDPLAY_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsidplayfp libsidutils\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsidplayfp libsidutils") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SIDPLAY_CFLAGS=`$PKG_CONFIG --cflags "libsidplayfp libsidutils" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsidplay2  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SIDPLAY_LIBS"; then
+    pkg_cv_SIDPLAY_LIBS="$SIDPLAY_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsidplayfp libsidutils\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsidplayfp libsidutils") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SIDPLAY_LIBS=`$PKG_CONFIG --libs "libsidplayfp libsidutils" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
 
 
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_sidplay2_main=yes
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  ac_cv_lib_sidplay2_main=no
+        _pkg_short_errors_supported=no
 fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+        if test $_pkg_short_errors_supported = yes; then
+	        SIDPLAY_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsidplayfp libsidutils" 2>&1`
+        else
+	        SIDPLAY_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsidplayfp libsidutils" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$SIDPLAY_PKG_ERRORS" >&5
+
+	found_sidplayfp=no
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	found_sidplayfp=no
+else
+	SIDPLAY_CFLAGS=$pkg_cv_SIDPLAY_CFLAGS
+	SIDPLAY_LIBS=$pkg_cv_SIDPLAY_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	found_sidplayfp=yes
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sidplay2_main" >&5
-$as_echo "$ac_cv_lib_sidplay2_main" >&6; }
-if test "x$ac_cv_lib_sidplay2_main" = xyes; then :
-  found_sidplay=yes
+	found_sidplay=$found_sidplayfp
+fi
+
+if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SIDPLAY" >&5
+$as_echo_n "checking for SIDPLAY... " >&6; }
+
+if test -n "$SIDPLAY_CFLAGS"; then
+    pkg_cv_SIDPLAY_CFLAGS="$SIDPLAY_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsidplay2 libsidutils\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsidplay2 libsidutils") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SIDPLAY_CFLAGS=`$PKG_CONFIG --cflags "libsidplay2 libsidutils" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
 else
-  found_sidplay=no
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SIDPLAY_LIBS"; then
+    pkg_cv_SIDPLAY_LIBS="$SIDPLAY_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsidplay2 libsidutils\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsidplay2 libsidutils") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SIDPLAY_LIBS=`$PKG_CONFIG --libs "libsidplay2 libsidutils" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
 fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        SIDPLAY_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsidplay2 libsidutils" 2>&1`
+        else
+	        SIDPLAY_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsidplay2 libsidutils" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$SIDPLAY_PKG_ERRORS" >&5
+
+	found_sidplay=no
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	found_sidplay=no
+else
+	SIDPLAY_CFLAGS=$pkg_cv_SIDPLAY_CFLAGS
+	SIDPLAY_LIBS=$pkg_cv_SIDPLAY_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	found_sidplay=yes
+fi
 
 
 	name="sidplay"
@@ -14524,7 +14629,7 @@ $as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
 
 fi
 
-if test x$enable_sidplay != xno; then
+if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lresid-builder" >&5
 $as_echo_n "checking for main in -lresid-builder... " >&6; }
 if ${ac_cv_lib_resid_builder_main+:} false; then :
@@ -14562,51 +14667,12 @@ else
 fi
 
 
-	if test x$found_sidplay = xyes; then
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsidutils" >&5
-$as_echo_n "checking for main in -lsidutils... " >&6; }
-if ${ac_cv_lib_sidutils_main+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsidutils  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_sidutils_main=yes
-else
-  ac_cv_lib_sidutils_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sidutils_main" >&5
-$as_echo "$ac_cv_lib_sidutils_main" >&6; }
-if test "x$ac_cv_lib_sidutils_main" = xyes; then :
-  :
-else
-  found_sidplay=no
-fi
-
-	fi
-
 
 	name="sidplay"
 	var="enable_sidplay"
 	found="found_$name"
 	feature="sidplay decoder plugin"
-	msg="libresid-builder or libsidutils not found"
+	msg="libresid-builder not found"
 
 	if eval "test x`echo '$'$var` = xno"; then
 		eval "$found=no"
@@ -14642,13 +14708,15 @@ $as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
 fi
 
 if test x$enable_sidplay = xyes; then
-	SIDPLAY_LIBS="-lsidplay2 -lresid-builder -lsidutils"
-
+	SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder"
 
+$as_echo "#define ENABLE_SIDPLAY 1" >>confdefs.h
 
+	if test x$found_sidplayfp = xyes; then
 
-$as_echo "#define ENABLE_SIDPLAY 1" >>confdefs.h
+$as_echo "#define HAVE_SIDPLAYFP 1" >>confdefs.h
 
+	fi
 fi
 
  if test x$enable_sidplay = xyes; then
@@ -20895,7 +20963,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mpd $as_me 0.19.17, which was
+This file was extended by mpd $as_me 0.19.18, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -20961,7 +21029,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mpd config.status 0.19.17
+mpd config.status 0.19.18
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index b5d59c2..1a3a20c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
 AC_PREREQ(2.60)
 
-AC_INIT(mpd, 0.19.17, musicpd-dev-team at lists.sourceforge.net)
+AC_INIT(mpd, 0.19.18, musicpd-dev-team at lists.sourceforge.net)
 
 VERSION_MAJOR=0
 VERSION_MINOR=19
-VERSION_REVISION=17
+VERSION_REVISION=18
 VERSION_EXTRA=0
 
 AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -542,8 +542,6 @@ AC_ARG_ENABLE(sidplay,
 	AS_HELP_STRING([--enable-sidplay],
 		[enable C64 SID support via libsidplay2]),,
 	enable_sidplay=auto)
-MPD_DEPENDS([enable_sidplay], [enable_glib],
-	[Cannot use --enable-sidplay with --disable-glib])
 
 AC_ARG_ENABLE(shine-encoder,
 	AS_HELP_STRING([--enable-shine-encoder],
@@ -1335,31 +1333,36 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
 
 dnl --------------------------------- sidplay ---------------------------------
 if test x$enable_sidplay != xno; then
-	# we're not using pkg-config here
-	# because libsidplay2's .pc file requires libtool
-	AC_CHECK_LIB([sidplay2],[main],[found_sidplay=yes],[found_sidplay=no],[])
+	dnl Check for libsidplayfp first
+	PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils],
+		[found_sidplayfp=yes],
+		[found_sidplayfp=no])
+	found_sidplay=$found_sidplayfp
+fi
+
+if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
+	PKG_CHECK_MODULES([SIDPLAY], [libsidplay2 libsidutils],
+		[found_sidplay=yes],
+		[found_sidplay=no])
 
 	MPD_AUTO_PRE(sidplay, [sidplay decoder plugin],
 		[libsidplay2 not found])
 fi
 
-if test x$enable_sidplay != xno; then
+if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
 	AC_CHECK_LIB([resid-builder], [main],
 		[found_sidplay=yes], [found_sidplay=no])
 
-	if test x$found_sidplay = xyes; then
-		AC_CHECK_LIB([sidutils],[main],[:],[found_sidplay=no],[])
-	fi
-
 	MPD_AUTO_RESULT(sidplay, [sidplay decoder plugin],
-		[libresid-builder or libsidutils not found])
+		[libresid-builder not found])
 fi
 
 if test x$enable_sidplay = xyes; then
-	AC_SUBST(SIDPLAY_LIBS,"-lsidplay2 -lresid-builder -lsidutils")
-	AC_SUBST(SIDPLAY_CFLAGS,)
-
+	SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder"
 	AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplay2 support])
+	if test x$found_sidplayfp = xyes; then
+		AC_DEFINE(HAVE_SIDPLAYFP, 1, [Define if libsidplayfp is used instead of libsidplay2])
+	fi
 fi
 
 AM_CONDITIONAL(ENABLE_SIDPLAY, test x$enable_sidplay = xyes)
diff --git a/doc/developer.xml b/doc/developer.xml
index 074c7f3..f07c520 100644
--- a/doc/developer.xml
+++ b/doc/developer.xml
@@ -41,7 +41,7 @@
       <listitem>
         <para>
           the code should be C++11 compliant, and must compile with
-          <application>GCC</application> 4.6 and
+          <application>GCC</application> 4.7 and
           <application>clang</application> 3.2
         </para>
       </listitem>
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
index ac2bdae..fb9131a 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf
@@ -31,7 +31,7 @@ PROJECT_NAME           = MPD
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER = 0.19.17
+PROJECT_NUMBER = 0.19.18
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
 # base path where the generated documentation will be put.
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index 6ba0351..21d4b41 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -231,7 +231,7 @@ input {
 #
 #audio_output {
 #	type		"shout"
-#	encoding	"ogg"			# optional
+#	encoder		"vorbis"		# optional
 #	name		"My Shout Stream"
 #	host		"localhost"
 #	port		"8000"
diff --git a/src/Compiler.h b/src/Compiler.h
index fea9715..5a28c3d 100644
--- a/src/Compiler.h
+++ b/src/Compiler.h
@@ -45,7 +45,7 @@
 #    error Sorry, your clang version is too old.  You need at least version 3.1.
 #  endif
 #elif defined(__GNUC__)
-#  if GCC_OLDER_THAN(4,6)
+#  if GCC_OLDER_THAN(4,7)
 #    error Sorry, your gcc version is too old.  You need at least version 4.6.
 #  endif
 #else
diff --git a/src/archive/plugins/Bzip2ArchivePlugin.cxx b/src/archive/plugins/Bzip2ArchivePlugin.cxx
index 2b92049..8548cb1 100644
--- a/src/archive/plugins/Bzip2ArchivePlugin.cxx
+++ b/src/archive/plugins/Bzip2ArchivePlugin.cxx
@@ -53,7 +53,7 @@ public:
 
 	Bzip2ArchiveFile(Path path, InputStream *_is)
 		:ArchiveFile(bz2_archive_plugin),
-		 name(PathTraitsFS::GetBase(path.c_str())),
+		 name(path.GetBase().c_str()),
 		 istream(_is) {
 		// remove .bz2 suffix
 		const size_t len = name.length();
diff --git a/src/db/update/ExcludeList.cxx b/src/db/update/ExcludeList.cxx
index cf92ac8..029bed9 100644
--- a/src/db/update/ExcludeList.cxx
+++ b/src/db/update/ExcludeList.cxx
@@ -34,7 +34,9 @@
 #include <string.h>
 #include <errno.h>
 
+#ifdef HAVE_GLIB
 static constexpr Domain exclude_list_domain("exclude_list");
+#endif
 
 bool
 ExcludeList::LoadFile(Path path_fs)
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index d5f73c3..2e407e6 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -98,6 +98,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
 
 	if (!is->Check(error)) {
 		dc.Unlock();
+		delete is;
 
 		LogError(error);
 		return nullptr;
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 6404450..7695dcb 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -20,16 +20,24 @@
 /* necessary because libavutil/common.h uses UINT64_C */
 #define __STDC_CONSTANT_MACROS
 
+#include "lib/ffmpeg/Time.hxx"
 #include "config.h"
 #include "FfmpegDecoderPlugin.hxx"
 #include "lib/ffmpeg/Domain.hxx"
+#include "lib/ffmpeg/Error.hxx"
+#include "lib/ffmpeg/LogError.hxx"
+#include "lib/ffmpeg/Init.hxx"
+#include "lib/ffmpeg/Buffer.hxx"
 #include "../DecoderAPI.hxx"
 #include "FfmpegMetaData.hxx"
+#include "FfmpegIo.hxx"
+#include "pcm/Interleave.hxx"
 #include "tag/TagHandler.hxx"
 #include "input/InputStream.hxx"
 #include "CheckAudioFormat.hxx"
+#include "util/ScopeExit.hxx"
+#include "util/ConstBuffer.hxx"
 #include "util/Error.hxx"
-#include "util/Domain.hxx"
 #include "LogV.hxx"
 
 extern "C" {
@@ -38,7 +46,6 @@ extern "C" {
 #include <libavformat/avio.h>
 #include <libavutil/avutil.h>
 #include <libavutil/log.h>
-#include <libavutil/mathematics.h>
 
 #if LIBAVUTIL_VERSION_MAJOR >= 53
 #include <libavutil/frame.h>
@@ -48,270 +55,144 @@ extern "C" {
 #include <assert.h>
 #include <string.h>
 
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-static LogLevel
-import_ffmpeg_level(int level)
+static AVFormatContext *
+FfmpegOpenInput(AVIOContext *pb,
+		const char *filename,
+		AVInputFormat *fmt,
+		Error &error)
 {
-	if (level <= AV_LOG_FATAL)
-		return LogLevel::ERROR;
+	AVFormatContext *context = avformat_alloc_context();
+	if (context == nullptr) {
+		error.Set(ffmpeg_domain, "Out of memory");
+		return nullptr;
+	}
 
-	if (level <= AV_LOG_WARNING)
-		return LogLevel::WARNING;
+	context->pb = pb;
 
-	if (level <= AV_LOG_INFO)
-		return LogLevel::INFO;
+	int err = avformat_open_input(&context, filename, fmt, nullptr);
+	if (err < 0) {
+		avformat_free_context(context);
+		SetFfmpegError(error, err, "avformat_open_input() failed");
+		return nullptr;
+	}
 
-	return LogLevel::DEBUG;
+	return context;
 }
 
-static void
-mpd_ffmpeg_log_callback(gcc_unused void *ptr, int level,
-			const char *fmt, va_list vl)
+static bool
+ffmpeg_init(gcc_unused const config_param &param)
 {
-	const AVClass * cls = nullptr;
-
-	if (ptr != nullptr)
-		cls = *(const AVClass *const*)ptr;
-
-	if (cls != nullptr) {
-		char domain[64];
-		snprintf(domain, sizeof(domain), "%s/%s",
-			 ffmpeg_domain.GetName(), cls->item_name(ptr));
-		const Domain d(domain);
-		LogFormatV(d, import_ffmpeg_level(level), fmt, vl);
-	}
+	FfmpegInit();
+	return true;
 }
 
-struct AvioStream {
-	Decoder *const decoder;
-	InputStream &input;
-
-	AVIOContext *io;
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 25, 0) /* FFmpeg 3.1 */
 
-	AvioStream(Decoder *_decoder, InputStream &_input)
-		:decoder(_decoder), input(_input), io(nullptr) {}
-
-	~AvioStream() {
-		if (io != nullptr) {
-			av_free(io->buffer);
-			av_free(io);
-		}
-	}
-
-	bool Open();
-};
-
-static int
-mpd_ffmpeg_stream_read(void *opaque, uint8_t *buf, int size)
+gcc_pure
+static const AVCodecParameters &
+GetCodecParameters(const AVStream &stream)
 {
-	AvioStream *stream = (AvioStream *)opaque;
-
-	return decoder_read(stream->decoder, stream->input,
-			    (void *)buf, size);
+	return *stream.codecpar;
 }
 
-static int64_t
-mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
+gcc_pure
+static AVSampleFormat
+GetSampleFormat(const AVCodecParameters &codec_params)
 {
-	AvioStream *stream = (AvioStream *)opaque;
-
-	switch (whence) {
-	case SEEK_SET:
-		break;
-
-	case SEEK_CUR:
-		pos += stream->input.GetOffset();
-		break;
-
-	case SEEK_END:
-		if (!stream->input.KnownSize())
-			return -1;
-
-		pos += stream->input.GetSize();
-		break;
-
-	case AVSEEK_SIZE:
-		if (!stream->input.KnownSize())
-			return -1;
-
-		return stream->input.GetSize();
-
-	default:
-		return -1;
-	}
-
-	if (!stream->input.LockSeek(pos, IgnoreError()))
-		return -1;
-
-	return stream->input.GetOffset();
+	return AVSampleFormat(codec_params.format);
 }
 
-bool
-AvioStream::Open()
-{
-	constexpr size_t BUFFER_SIZE = 8192;
-	auto buffer = (unsigned char *)av_malloc(BUFFER_SIZE);
-	if (buffer == nullptr)
-		return false;
+#else
 
-	io = avio_alloc_context(buffer, BUFFER_SIZE,
-				false, this,
-				mpd_ffmpeg_stream_read, nullptr,
-				input.IsSeekable()
-				? mpd_ffmpeg_stream_seek : nullptr);
-	/* If avio_alloc_context() fails, who frees the buffer?  The
-	   libavformat API documentation does not specify this, it
-	   only says that AVIOContext.buffer must be freed in the end,
-	   however no AVIOContext exists in that failure code path. */
-	return io != nullptr;
+gcc_pure
+static const AVCodecContext &
+GetCodecParameters(const AVStream &stream)
+{
+	return *stream.codec;
 }
 
-/**
- * API compatibility wrapper for av_open_input_stream() and
- * avformat_open_input().
- */
-static int
-mpd_ffmpeg_open_input(AVFormatContext **ic_ptr,
-		      AVIOContext *pb,
-		      const char *filename,
-		      AVInputFormat *fmt)
+gcc_pure
+static AVSampleFormat
+GetSampleFormat(const AVCodecContext &codec_context)
 {
-	AVFormatContext *context = avformat_alloc_context();
-	if (context == nullptr)
-		return AVERROR(ENOMEM);
-
-	context->pb = pb;
-	*ic_ptr = context;
-	return avformat_open_input(ic_ptr, filename, fmt, nullptr);
+	return codec_context.sample_fmt;
 }
 
+#endif
+
+gcc_pure
 static bool
-ffmpeg_init(gcc_unused const config_param &param)
+IsAudio(const AVStream &stream)
 {
-	av_log_set_callback(mpd_ffmpeg_log_callback);
-
-	av_register_all();
-	return true;
+	return GetCodecParameters(stream).codec_type == AVMEDIA_TYPE_AUDIO;
 }
 
+gcc_pure
 static int
 ffmpeg_find_audio_stream(const AVFormatContext &format_context)
 {
 	for (unsigned i = 0; i < format_context.nb_streams; ++i)
-		if (format_context.streams[i]->codec->codec_type ==
-		    AVMEDIA_TYPE_AUDIO)
+		if (IsAudio(*format_context.streams[i]))
 			return i;
 
 	return -1;
 }
 
-gcc_const
-static double
-time_from_ffmpeg(int64_t t, const AVRational time_base)
-{
-	assert(t != (int64_t)AV_NOPTS_VALUE);
-
-	return (double)av_rescale_q(t, time_base, (AVRational){1, 1024})
-		/ (double)1024;
-}
-
-template<typename Ratio>
-static constexpr AVRational
-RatioToAVRational()
-{
-	return { Ratio::num, Ratio::den };
-}
-
-gcc_const
-static int64_t
-time_to_ffmpeg(SongTime t, const AVRational time_base)
-{
-	return av_rescale_q(t.count(),
-			    RatioToAVRational<SongTime::period>(),
-			    time_base);
-}
-
-/**
- * Replace #AV_NOPTS_VALUE with the given fallback.
- */
-static constexpr int64_t
-timestamp_fallback(int64_t t, int64_t fallback)
-{
-	return gcc_likely(t != int64_t(AV_NOPTS_VALUE))
-		? t
-		: fallback;
-}
-
 /**
  * Accessor for AVStream::start_time that replaces AV_NOPTS_VALUE with
  * zero.  We can't use AV_NOPTS_VALUE in calculations, and we simply
  * assume that the stream's start time is zero, which appears to be
  * the best way out of that situation.
  */
-static int64_t
+static constexpr int64_t
 start_time_fallback(const AVStream &stream)
 {
-	return timestamp_fallback(stream.start_time, 0);
-}
-
-static void
-copy_interleave_frame2(uint8_t *dest, uint8_t **src,
-		       unsigned nframes, unsigned nchannels,
-		       unsigned sample_size)
-{
-	for (unsigned frame = 0; frame < nframes; ++frame) {
-		for (unsigned channel = 0; channel < nchannels; ++channel) {
-			memcpy(dest, src[channel] + frame * sample_size,
-			       sample_size);
-			dest += sample_size;
-		}
-	}
+	return FfmpegTimestampFallback(stream.start_time, 0);
 }
 
 /**
- * Copy PCM data from a AVFrame to an interleaved buffer.
+ * Copy PCM data from a non-empty AVFrame to an interleaved buffer.
  */
-static int
+static ConstBuffer<void>
 copy_interleave_frame(const AVCodecContext &codec_context,
 		      const AVFrame &frame,
-		      uint8_t **output_buffer,
-		      uint8_t **global_buffer, int *global_buffer_size)
+		      FfmpegBuffer &global_buffer,
+		      Error &error)
 {
+	assert(frame.nb_samples > 0);
+
 	int plane_size;
 	const int data_size =
 		av_samples_get_buffer_size(&plane_size,
 					   codec_context.channels,
 					   frame.nb_samples,
 					   codec_context.sample_fmt, 1);
-	if (data_size <= 0)
-		return data_size;
+	assert(data_size != 0);
+	if (data_size < 0) {
+		SetFfmpegError(error, data_size);
+		return 0;
+	}
 
+	void *output_buffer;
 	if (av_sample_fmt_is_planar(codec_context.sample_fmt) &&
 	    codec_context.channels > 1) {
-		if(*global_buffer_size < data_size) {
-			av_freep(global_buffer);
-
-			*global_buffer = (uint8_t*)av_malloc(data_size);
-
-			if (!*global_buffer)
-				/* Not enough memory - shouldn't happen */
-				return AVERROR(ENOMEM);
-			*global_buffer_size = data_size;
+		output_buffer = global_buffer.GetT<uint8_t>(data_size);
+		if (output_buffer == nullptr) {
+			/* Not enough memory - shouldn't happen */
+			error.SetErrno(ENOMEM);
+			return 0;
 		}
-		*output_buffer = *global_buffer;
-		copy_interleave_frame2(*output_buffer, frame.extended_data,
-				       frame.nb_samples,
-				       codec_context.channels,
-				       av_get_bytes_per_sample(codec_context.sample_fmt));
+
+		PcmInterleave(output_buffer,
+			      ConstBuffer<const void *>((const void *const*)frame.extended_data,
+							codec_context.channels),
+			      frame.nb_samples,
+			      av_get_bytes_per_sample(codec_context.sample_fmt));
 	} else {
-		*output_buffer = frame.extended_data[0];
+		output_buffer = frame.extended_data[0];
 	}
 
-	return data_size;
+	return { output_buffer, (size_t)data_size };
 }
 
 /**
@@ -343,6 +224,94 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
 }
 
 /**
+ * Invoke decoder_data() with the contents of an #AVFrame.
+ */
+static DecoderCommand
+FfmpegSendFrame(Decoder &decoder, InputStream &is,
+		AVCodecContext &codec_context,
+		const AVFrame &frame,
+		size_t &skip_bytes,
+		FfmpegBuffer &buffer)
+{
+	Error error;
+	auto output_buffer =
+		copy_interleave_frame(codec_context, frame,
+				      buffer, error);
+	if (output_buffer.IsNull()) {
+		/* this must be a serious error, e.g. OOM */
+		LogError(error);
+		return DecoderCommand::STOP;
+	}
+
+	if (skip_bytes > 0) {
+		if (skip_bytes >= output_buffer.size) {
+			skip_bytes -= output_buffer.size;
+			return DecoderCommand::NONE;
+		}
+
+		output_buffer.data =
+			(const uint8_t *)output_buffer.data + skip_bytes;
+		output_buffer.size -= skip_bytes;
+		skip_bytes = 0;
+	}
+
+	return decoder_data(decoder, is,
+			    output_buffer.data, output_buffer.size,
+			    codec_context.bit_rate / 1000);
+}
+
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0)
+
+static DecoderCommand
+FfmpegReceiveFrames(Decoder &decoder, InputStream &is,
+		    AVCodecContext &codec_context,
+		    AVFrame &frame,
+		    size_t &skip_bytes,
+		    FfmpegBuffer &buffer,
+		    bool &eof)
+{
+	while (true) {
+		DecoderCommand cmd;
+
+		int err = avcodec_receive_frame(&codec_context, &frame);
+		switch (err) {
+		case 0:
+			cmd = FfmpegSendFrame(decoder, is, codec_context,
+					      frame, skip_bytes,
+					      buffer);
+			if (cmd != DecoderCommand::NONE)
+				return cmd;
+
+			break;
+
+		case AVERROR_EOF:
+			eof = true;
+			return DecoderCommand::NONE;
+
+		case AVERROR(EAGAIN):
+			/* need to call avcodec_send_packet() */
+			return DecoderCommand::NONE;
+
+		default:
+			{
+				char msg[256];
+				av_strerror(err, msg, sizeof(msg));
+				FormatWarning(ffmpeg_domain,
+					      "avcodec_send_packet() failed: %s",
+					      msg);
+			}
+
+			return DecoderCommand::STOP;
+		}
+	}
+}
+
+#endif
+
+/**
+ * Decode an #AVPacket and send the resulting PCM data to the decoder
+ * API.
+ *
  * @param min_frame skip all data before this PCM frame number; this
  * is used after seeking to skip data in an AVPacket until the exact
  * desired time stamp has been reached
@@ -352,9 +321,9 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
 		   AVPacket &&packet,
 		   AVCodecContext &codec_context,
 		   const AVStream &stream,
-		   AVFrame *frame,
+		   AVFrame &frame,
 		   uint64_t min_frame, size_t pcm_frame_size,
-		   uint8_t **buffer, int *buffer_size)
+		   FfmpegBuffer &buffer)
 {
 	size_t skip_bytes = 0;
 
@@ -367,59 +336,85 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
 				skip_bytes = pcm_frame_size * (min_frame - cur_frame);
 		} else
 			decoder_timestamp(decoder,
-					  time_from_ffmpeg(pts, stream.time_base));
+					  FfmpegTimeToDouble(pts,
+							     stream.time_base));
 	}
 
-	uint8_t *output_buffer;
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0)
+	bool eof = false;
 
+	int err = avcodec_send_packet(&codec_context, &packet);
+	switch (err) {
+	case 0:
+		break;
+
+	case AVERROR_EOF:
+		eof = true;
+		break;
+
+	default:
+		{
+			char msg[256];
+			av_strerror(err, msg, sizeof(msg));
+			FormatWarning(ffmpeg_domain,
+				      "avcodec_send_packet() failed: %s", msg);
+		}
+
+		return DecoderCommand::NONE;
+	}
+
+	auto cmd = FfmpegReceiveFrames(decoder, is, codec_context,
+				       frame,
+				       skip_bytes, buffer, eof);
+
+	if (eof)
+		cmd = DecoderCommand::STOP;
+#else
 	DecoderCommand cmd = DecoderCommand::NONE;
 	while (packet.size > 0 && cmd == DecoderCommand::NONE) {
-		int audio_size = 0;
 		int got_frame = 0;
 		int len = avcodec_decode_audio4(&codec_context,
-						frame, &got_frame,
+						&frame, &got_frame,
 						&packet);
-		if (len >= 0 && got_frame) {
-			audio_size = copy_interleave_frame(codec_context,
-							   *frame,
-							   &output_buffer,
-							   buffer, buffer_size);
-			if (audio_size < 0)
-				len = audio_size;
-		}
-
 		if (len < 0) {
 			/* if error, we skip the frame */
-			LogDefault(ffmpeg_domain,
-				   "decoding failed, frame skipped");
+			LogFfmpegError(len, "decoding failed, frame skipped");
 			break;
 		}
 
 		packet.data += len;
 		packet.size -= len;
 
-		if (audio_size <= 0)
+		if (!got_frame || frame.nb_samples <= 0)
 			continue;
 
-		const uint8_t *data = output_buffer;
-		if (skip_bytes > 0) {
-			if (skip_bytes >= size_t(audio_size)) {
-				skip_bytes -= audio_size;
-				continue;
-			}
-
-			data += skip_bytes;
-			audio_size -= skip_bytes;
-			skip_bytes = 0;
-		}
-
-		cmd = decoder_data(decoder, is,
-				   data, audio_size,
-				   codec_context.bit_rate / 1000);
+		cmd = FfmpegSendFrame(decoder, is, codec_context,
+				      frame, skip_bytes,
+				      buffer);
 	}
+#endif
+
 	return cmd;
 }
 
+static DecoderCommand
+ffmpeg_send_packet(Decoder &decoder, InputStream &is,
+		   const AVPacket &packet,
+		   AVCodecContext &codec_context,
+		   const AVStream &stream,
+		   AVFrame &frame,
+		   uint64_t min_frame, size_t pcm_frame_size,
+		   FfmpegBuffer &buffer)
+{
+	return ffmpeg_send_packet(decoder, is,
+				  /* copy the AVPacket, because FFmpeg
+				     < 3.0 requires this */
+				  AVPacket(packet),
+				  codec_context, stream,
+				  frame, min_frame, pcm_frame_size,
+				  buffer);
+}
+
 gcc_const
 static SampleFormat
 ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
@@ -458,10 +453,8 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
 static AVInputFormat *
 ffmpeg_probe(Decoder *decoder, InputStream &is)
 {
-	enum {
-		BUFFER_SIZE = 16384,
-		PADDING = 16,
-	};
+	constexpr size_t BUFFER_SIZE = 16384;
+	constexpr size_t PADDING = 16;
 
 	unsigned char buffer[BUFFER_SIZE];
 	size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE);
@@ -501,52 +494,33 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
 }
 
 static void
-ffmpeg_decode(Decoder &decoder, InputStream &input)
+FfmpegDecode(Decoder &decoder, InputStream &input,
+	     AVFormatContext &format_context)
 {
-	AVInputFormat *input_format = ffmpeg_probe(&decoder, input);
-	if (input_format == nullptr)
-		return;
-
-	FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)",
-		    input_format->name, input_format->long_name);
-
-	AvioStream stream(&decoder, input);
-	if (!stream.Open()) {
-		LogError(ffmpeg_domain, "Failed to open stream");
-		return;
-	}
-
-	//ffmpeg works with ours "fileops" helper
-	AVFormatContext *format_context = nullptr;
-	if (mpd_ffmpeg_open_input(&format_context, stream.io,
-				  input.GetURI(),
-				  input_format) != 0) {
-		LogError(ffmpeg_domain, "Open failed");
-		return;
-	}
-
 	const int find_result =
-		avformat_find_stream_info(format_context, nullptr);
+		avformat_find_stream_info(&format_context, nullptr);
 	if (find_result < 0) {
 		LogError(ffmpeg_domain, "Couldn't find stream info");
-		avformat_close_input(&format_context);
 		return;
 	}
 
-	int audio_stream = ffmpeg_find_audio_stream(*format_context);
+	int audio_stream = ffmpeg_find_audio_stream(format_context);
 	if (audio_stream == -1) {
 		LogError(ffmpeg_domain, "No audio stream inside");
-		avformat_close_input(&format_context);
 		return;
 	}
 
-	AVStream *av_stream = format_context->streams[audio_stream];
+	AVStream &av_stream = *format_context.streams[audio_stream];
 
-	AVCodecContext *codec_context = av_stream->codec;
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 5, 0)
+	AVCodecContext *codec_context = av_stream.codec;
+#endif
+
+	const auto &codec_params = GetCodecParameters(av_stream);
 
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
 	const AVCodecDescriptor *codec_descriptor =
-		avcodec_descriptor_get(codec_context->codec_id);
+		avcodec_descriptor_get(codec_params.codec_id);
 	if (codec_descriptor != nullptr)
 		FormatDebug(ffmpeg_domain, "codec '%s'",
 			    codec_descriptor->name);
@@ -556,30 +530,39 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
 			    codec_context->codec_name);
 #endif
 
-	AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);
+	AVCodec *codec = avcodec_find_decoder(codec_params.codec_id);
 
 	if (!codec) {
 		LogError(ffmpeg_domain, "Unsupported audio codec");
-		avformat_close_input(&format_context);
 		return;
 	}
 
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 5, 0)
+	AVCodecContext *codec_context = avcodec_alloc_context3(codec);
+	if (codec_context == nullptr) {
+		LogError(ffmpeg_domain, "avcodec_alloc_context3() failed");
+		return;
+	}
+
+	AtScopeExit(&codec_context) {
+		avcodec_free_context(&codec_context);
+	};
+#endif
+
 	const SampleFormat sample_format =
-		ffmpeg_sample_format(codec_context->sample_fmt);
+		ffmpeg_sample_format(GetSampleFormat(codec_params));
 	if (sample_format == SampleFormat::UNDEFINED) {
 		// (error message already done by ffmpeg_sample_format())
-		avformat_close_input(&format_context);
 		return;
 	}
 
 	Error error;
 	AudioFormat audio_format;
 	if (!audio_format_init_checked(audio_format,
-				       codec_context->sample_rate,
+				       codec_params.sample_rate,
 				       sample_format,
-				       codec_context->channels, error)) {
+				       codec_params.channels, error)) {
 		LogError(error);
-		avformat_close_input(&format_context);
 		return;
 	}
 
@@ -591,15 +574,17 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
 	const int open_result = avcodec_open2(codec_context, codec, nullptr);
 	if (open_result < 0) {
 		LogError(ffmpeg_domain, "Could not open codec");
-		avformat_close_input(&format_context);
 		return;
 	}
 
+#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 5, 0)
+	AtScopeExit(codec_context) {
+		avcodec_close(codec_context);
+	};
+#endif
+
 	const SignedSongTime total_time =
-		format_context->duration != (int64_t)AV_NOPTS_VALUE
-		? SignedSongTime::FromScale<uint64_t>(format_context->duration,
-						      AV_TIME_BASE)
-		: SignedSongTime::Negative();
+		FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base);
 
 	decoder_initialized(decoder, audio_format,
 			    input.IsSeekable(), total_time);
@@ -611,30 +596,57 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
 #endif
 	if (!frame) {
 		LogError(ffmpeg_domain, "Could not allocate frame");
-		avformat_close_input(&format_context);
 		return;
 	}
 
-	uint8_t *interleaved_buffer = nullptr;
-	int interleaved_buffer_size = 0;
+	AtScopeExit(&frame) {
+#if LIBAVUTIL_VERSION_MAJOR >= 53
+		av_frame_free(&frame);
+#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
+		avcodec_free_frame(&frame);
+#else
+		av_free(frame);
+#endif
+	};
+
+	FfmpegBuffer interleaved_buffer;
 
 	uint64_t min_frame = 0;
 
-	DecoderCommand cmd;
-	do {
+	DecoderCommand cmd = decoder_get_command(decoder);
+	while (cmd != DecoderCommand::STOP) {
+		if (cmd == DecoderCommand::SEEK) {
+			int64_t where =
+				ToFfmpegTime(decoder_seek_time(decoder),
+					     av_stream.time_base) +
+				start_time_fallback(av_stream);
+
+			/* AVSEEK_FLAG_BACKWARD asks FFmpeg to seek to
+			   the packet boundary before the seek time
+			   stamp, not after */
+			if (av_seek_frame(&format_context, audio_stream, where,
+					  AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
+				decoder_seek_error(decoder);
+			else {
+				avcodec_flush_buffers(codec_context);
+				min_frame = decoder_seek_where_frame(decoder);
+				decoder_command_finished(decoder);
+			}
+		}
+
 		AVPacket packet;
-		if (av_read_frame(format_context, &packet) < 0)
+		if (av_read_frame(&format_context, &packet) < 0)
 			/* end of file */
 			break;
 
 		if (packet.stream_index == audio_stream) {
 			cmd = ffmpeg_send_packet(decoder, input,
-						 std::move(packet),
+						 packet,
 						 *codec_context,
-						 *av_stream,
-						 frame,
+						 av_stream,
+						 *frame,
 						 min_frame, audio_format.GetFrameSize(),
-						 &interleaved_buffer, &interleaved_buffer_size);
+						 interleaved_buffer);
 			min_frame = 0;
 		} else
 			cmd = decoder_get_command(decoder);
@@ -644,42 +656,65 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
 #else
 		av_free_packet(&packet);
 #endif
+	}
+}
 
-		if (cmd == DecoderCommand::SEEK) {
-			int64_t where =
-				time_to_ffmpeg(decoder_seek_time(decoder),
-					       av_stream->time_base) +
-				start_time_fallback(*av_stream);
+static void
+ffmpeg_decode(Decoder &decoder, InputStream &input)
+{
+	AVInputFormat *input_format = ffmpeg_probe(&decoder, input);
+	if (input_format == nullptr)
+		return;
 
-			/* AVSEEK_FLAG_BACKWARD asks FFmpeg to seek to
-			   the packet boundary before the seek time
-			   stamp, not after */
+	FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)",
+		    input_format->name, input_format->long_name);
 
-			if (av_seek_frame(format_context, audio_stream, where,
-					  AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
-				decoder_seek_error(decoder);
-			else {
-				avcodec_flush_buffers(codec_context);
-				min_frame = decoder_seek_where_frame(decoder);
-				decoder_command_finished(decoder);
-			}
-		}
-	} while (cmd != DecoderCommand::STOP);
+	AvioStream stream(&decoder, input);
+	if (!stream.Open()) {
+		LogError(ffmpeg_domain, "Failed to open stream");
+		return;
+	}
 
-#if LIBAVUTIL_VERSION_MAJOR >= 53
-	av_frame_free(&frame);
-#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
-	avcodec_free_frame(&frame);
-#else
-	av_freep(&frame);
-#endif
-	av_freep(&interleaved_buffer);
+	Error error;
+	AVFormatContext *format_context =
+		FfmpegOpenInput(stream.io, input.GetURI(), input_format, error);
+	if (format_context == nullptr) {
+		LogError(error);
+		return;
+	}
+
+	AtScopeExit(&format_context) {
+		avformat_close_input(&format_context);
+	};
+
+	FfmpegDecode(decoder, input, *format_context);
+}
+
+static bool
+FfmpegScanStream(AVFormatContext &format_context,
+		 const struct tag_handler &handler, void *handler_ctx)
+{
+	const int find_result =
+		avformat_find_stream_info(&format_context, nullptr);
+	if (find_result < 0)
+		return false;
+
+	if (format_context.duration != (int64_t)AV_NOPTS_VALUE) {
+		const auto duration =
+			SongTime::FromScale<uint64_t>(format_context.duration,
+						      AV_TIME_BASE);
+		tag_handler_invoke_duration(&handler, handler_ctx, duration);
+	}
 
-	avcodec_close(codec_context);
-	avformat_close_input(&format_context);
+	FfmpegScanDictionary(format_context.metadata, &handler, handler_ctx);
+	int idx = ffmpeg_find_audio_stream(format_context);
+	if (idx >= 0)
+		FfmpegScanDictionary(format_context.streams[idx]->metadata,
+				     &handler, handler_ctx);
+
+	return true;
 }
 
-//no tag reading in ffmpeg, check if playable
 static bool
 ffmpeg_scan_stream(InputStream &is,
 		   const struct tag_handler *handler, void *handler_ctx)
@@ -692,33 +727,17 @@ ffmpeg_scan_stream(InputStream &is,
 	if (!stream.Open())
 		return false;
 
-	AVFormatContext *f = nullptr;
-	if (mpd_ffmpeg_open_input(&f, stream.io, is.GetURI(),
-				  input_format) != 0)
+	AVFormatContext *f =
+		FfmpegOpenInput(stream.io, is.GetURI(), input_format,
+				IgnoreError());
+	if (f == nullptr)
 		return false;
 
-	const int find_result =
-		avformat_find_stream_info(f, nullptr);
-	if (find_result < 0) {
+	AtScopeExit(&f) {
 		avformat_close_input(&f);
-		return false;
-	}
-
-	if (f->duration != (int64_t)AV_NOPTS_VALUE) {
-		const auto duration =
-			SongTime::FromScale<uint64_t>(f->duration,
-						      AV_TIME_BASE);
-		tag_handler_invoke_duration(handler, handler_ctx, duration);
-	}
-
-	ffmpeg_scan_dictionary(f->metadata, handler, handler_ctx);
-	int idx = ffmpeg_find_audio_stream(*f);
-	if (idx >= 0)
-		ffmpeg_scan_dictionary(f->streams[idx]->metadata,
-				       handler, handler_ctx);
+	};
 
-	avformat_close_input(&f);
-	return true;
+	return FfmpegScanStream(*f, *handler, handler_ctx);
 }
 
 /**
diff --git a/src/decoder/plugins/FfmpegIo.cxx b/src/decoder/plugins/FfmpegIo.cxx
new file mode 100644
index 0000000..5f8452c
--- /dev/null
+++ b/src/decoder/plugins/FfmpegIo.cxx
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2003-2016 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "FfmpegIo.hxx"
+#include "../DecoderAPI.hxx"
+#include "input/InputStream.hxx"
+#include "util/Error.hxx"
+
+AvioStream::~AvioStream()
+{
+	if (io != nullptr) {
+		av_free(io->buffer);
+		av_free(io);
+	}
+}
+
+static int
+mpd_ffmpeg_stream_read(void *opaque, uint8_t *buf, int size)
+{
+	AvioStream *stream = (AvioStream *)opaque;
+
+	return decoder_read(stream->decoder, stream->input,
+			    (void *)buf, size);
+}
+
+static int64_t
+mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
+{
+	AvioStream *stream = (AvioStream *)opaque;
+
+	switch (whence) {
+	case SEEK_SET:
+		break;
+
+	case SEEK_CUR:
+		pos += stream->input.GetOffset();
+		break;
+
+	case SEEK_END:
+		if (!stream->input.KnownSize())
+			return -1;
+
+		pos += stream->input.GetSize();
+		break;
+
+	case AVSEEK_SIZE:
+		if (!stream->input.KnownSize())
+			return -1;
+
+		return stream->input.GetSize();
+
+	default:
+		return -1;
+	}
+
+	if (!stream->input.LockSeek(pos, IgnoreError()))
+		return -1;
+
+	return stream->input.GetOffset();
+}
+
+bool
+AvioStream::Open()
+{
+	constexpr size_t BUFFER_SIZE = 8192;
+	auto buffer = (unsigned char *)av_malloc(BUFFER_SIZE);
+	if (buffer == nullptr)
+		return false;
+
+	io = avio_alloc_context(buffer, BUFFER_SIZE,
+				false, this,
+				mpd_ffmpeg_stream_read, nullptr,
+				input.IsSeekable()
+				? mpd_ffmpeg_stream_seek : nullptr);
+	/* If avio_alloc_context() fails, who frees the buffer?  The
+	   libavformat API documentation does not specify this, it
+	   only says that AVIOContext.buffer must be freed in the end,
+	   however no AVIOContext exists in that failure code path. */
+	return io != nullptr;
+}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/decoder/plugins/FfmpegIo.hxx
similarity index 63%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/decoder/plugins/FfmpegIo.hxx
index 5eb41db..7c400de 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/decoder/plugins/FfmpegIo.hxx
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2016 The Music Player Daemon Project
  * http://www.musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,22 +17,32 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#ifndef MPD_FFMPEG_IO_HXX
+#define MPD_FFMPEG_IO_HXX
+
+#include "check.h"
 
 extern "C" {
-#include <libavutil/dict.h>
+#include "libavformat/avio.h"
 }
 
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
+#include <stdint.h>
+
+class InputStream;
+struct Decoder;
+
+struct AvioStream {
+	Decoder *const decoder;
+	InputStream &input;
+
+	AVIOContext *io;
+
+	AvioStream(Decoder *_decoder, InputStream &_input)
+		:decoder(_decoder), input(_input), io(nullptr) {}
 
-struct tag_handler;
+	~AvioStream();
 
-void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+	bool Open();
+};
 
 #endif
diff --git a/src/decoder/plugins/FfmpegMetaData.cxx b/src/decoder/plugins/FfmpegMetaData.cxx
index a394669..5a5c9e1 100644
--- a/src/decoder/plugins/FfmpegMetaData.cxx
+++ b/src/decoder/plugins/FfmpegMetaData.cxx
@@ -36,9 +36,9 @@ static const struct tag_table ffmpeg_tags[] = {
 };
 
 static void
-ffmpeg_copy_metadata(TagType type,
-		     AVDictionary *m, const char *name,
-		     const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanTag(TagType type,
+	      AVDictionary *m, const char *name,
+	      const struct tag_handler *handler, void *handler_ctx)
 {
 	AVDictionaryEntry *mt = nullptr;
 
@@ -48,8 +48,8 @@ ffmpeg_copy_metadata(TagType type,
 }
 
 static void
-ffmpeg_scan_pairs(AVDictionary *dict,
-		  const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanPairs(AVDictionary *dict,
+		const struct tag_handler *handler, void *handler_ctx)
 {
 	AVDictionaryEntry *i = nullptr;
 
@@ -59,18 +59,20 @@ ffmpeg_scan_pairs(AVDictionary *dict,
 }
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanDictionary(AVDictionary *dict,
+		     const struct tag_handler *handler, void *handler_ctx)
 {
-	for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
-		ffmpeg_copy_metadata(TagType(i), dict, tag_item_names[i],
-				     handler, handler_ctx);
+	if (handler->tag != nullptr) {
+		for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
+			FfmpegScanTag(TagType(i), dict, tag_item_names[i],
+				      handler, handler_ctx);
 
-	for (const struct tag_table *i = ffmpeg_tags;
-	     i->name != nullptr; ++i)
-		ffmpeg_copy_metadata(i->type, dict, i->name,
-				     handler, handler_ctx);
+		for (const struct tag_table *i = ffmpeg_tags;
+		     i->name != nullptr; ++i)
+			FfmpegScanTag(i->type, dict, i->name,
+				      handler, handler_ctx);
+	}
 
 	if (handler->pair != nullptr)
-		ffmpeg_scan_pairs(dict, handler, handler_ctx);
+		FfmpegScanPairs(dict, handler, handler_ctx);
 }
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/decoder/plugins/FfmpegMetaData.hxx
index 5eb41db..1f233fb 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/decoder/plugins/FfmpegMetaData.hxx
@@ -32,7 +32,7 @@ extern "C" {
 struct tag_handler;
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+FfmpegScanDictionary(AVDictionary *dict,
+		     const tag_handler *handler, void *handler_ctx);
 
 #endif
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index 8435f09..db4070b 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -22,67 +22,61 @@
 #include "../DecoderAPI.hxx"
 #include "tag/TagHandler.hxx"
 #include "fs/Path.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "util/Macros.hxx"
 #include "util/FormatString.hxx"
 #include "util/Domain.hxx"
+#include "util/Error.hxx"
 #include "system/ByteOrder.hxx"
+#include "system/FatalError.hxx"
 #include "Log.hxx"
 
-#include <errno.h>
-#include <stdlib.h>
 #include <string.h>
-#include <glib.h>
 
+#ifdef HAVE_SIDPLAYFP
+#include <sidplayfp/sidplayfp.h>
+#include <sidplayfp/SidInfo.h>
+#include <sidplayfp/SidConfig.h>
+#include <sidplayfp/SidTune.h>
+#include <sidplayfp/SidTuneInfo.h>
+#include <sidplayfp/builders/resid.h>
+#include <sidplayfp/builders/residfp.h>
+#include <sidplayfp/SidDatabase.h>
+#else
 #include <sidplay/sidplay2.h>
 #include <sidplay/builders/resid.h>
 #include <sidplay/utils/SidTuneMod.h>
+#include <sidplay/utils/SidDatabase.h>
+#endif
 
 #define SUBTUNE_PREFIX "tune_"
 
 static constexpr Domain sidplay_domain("sidplay");
 
-static GPatternSpec *path_with_subtune;
-static const char *songlength_file;
-static GKeyFile *songlength_database;
+static SidDatabase *songlength_database;
 
 static bool all_files_are_containers;
 static unsigned default_songlength;
 
 static bool filter_setting;
 
-static GKeyFile *
-sidplay_load_songlength_db(const char *path)
+static SidDatabase *
+sidplay_load_songlength_db(const Path path)
 {
-	GError *error = nullptr;
-	gchar *data;
-	gsize size;
-
-	if (!g_file_get_contents(path, &data, &size, &error)) {
+	SidDatabase *db = new SidDatabase();
+#ifdef HAVE_SIDPLAYFP
+	bool error = !db->open(path.c_str());
+#else
+	bool error = db->open(path.c_str()) < 0;
+#endif
+	if (error) {
 		FormatError(sidplay_domain,
 			    "unable to read songlengths file %s: %s",
-			    path, error->message);
-		g_error_free(error);
-		return nullptr;
-	}
-
-	/* replace any ; comment characters with # */
-	for (gsize i = 0; i < size; i++)
-		if (data[i] == ';')
-			data[i] = '#';
-
-	GKeyFile *db = g_key_file_new();
-	bool success = g_key_file_load_from_data(db, data, size,
-						 G_KEY_FILE_NONE, &error);
-	g_free(data);
-	if (!success) {
-		FormatError(sidplay_domain,
-			    "unable to parse songlengths file %s: %s",
-			    path, error->message);
-		g_error_free(error);
-		g_key_file_free(db);
+			    path.c_str(), db->error());
+		delete db;
 		return nullptr;
 	}
 
-	g_key_file_set_list_separator(db, ' ');
 	return db;
 }
 
@@ -90,18 +84,18 @@ static bool
 sidplay_init(const config_param &param)
 {
 	/* read the songlengths database file */
-	songlength_file = param.GetBlockValue("songlength_database");
-	if (songlength_file != nullptr)
-		songlength_database = sidplay_load_songlength_db(songlength_file);
+	Error error;
+	const auto database_path = param.GetBlockPath("songlength_database", error);
+	if (!database_path.IsNull())
+		songlength_database = sidplay_load_songlength_db(database_path);
+	else if (error.IsDefined())
+		FatalError(error);
 
 	default_songlength = param.GetBlockValue("default_songlength", 0u);
 
 	all_files_are_containers =
 		param.GetBlockValue("all_files_are_containers", true);
 
-	path_with_subtune=g_pattern_spec_new(
-			"*/" SUBTUNE_PREFIX "???.sid");
-
 	filter_setting = param.GetBlockValue("filter", true);
 
 	return true;
@@ -110,98 +104,81 @@ sidplay_init(const config_param &param)
 static void
 sidplay_finish()
 {
-	g_pattern_spec_free(path_with_subtune);
-
-	if(songlength_database)
-		g_key_file_free(songlength_database);
+	delete songlength_database;
 }
 
-/**
- * returns the file path stripped of any /tune_xxx.sid subtune
- * suffix
- */
-static char *
-get_container_name(Path path_fs)
+struct SidplayContainerPath {
+	AllocatedPath path;
+	unsigned track;
+};
+
+gcc_pure
+static unsigned
+ParseSubtuneName(const char *base)
 {
-	char *path_container = strdup(path_fs.c_str());
+	if (memcmp(base, SUBTUNE_PREFIX, sizeof(SUBTUNE_PREFIX) - 1) != 0)
+		return 0;
 
-	if(!g_pattern_match(path_with_subtune,
-		strlen(path_container), path_container, nullptr))
-		return path_container;
+	base += sizeof(SUBTUNE_PREFIX) - 1;
 
-	char *ptr=g_strrstr(path_container, "/" SUBTUNE_PREFIX);
-	if(ptr) *ptr='\0';
+	char *endptr;
+	auto track = strtoul(base, &endptr, 10);
+	if (endptr == base || *endptr != '.')
+		return 0;
 
-	return path_container;
+	return track;
 }
 
 /**
- * returns tune number from file.sid/tune_xxx.sid style path or 1 if
- * no subtune is appended
+ * returns the file path stripped of any /tune_xxx.* subtune suffix
+ * and the track number (or 1 if no "tune_xxx" suffix is present).
  */
-static unsigned
-get_song_num(const char *path_fs)
+static SidplayContainerPath
+ParseContainerPath(Path path_fs)
 {
-	if(g_pattern_match(path_with_subtune,
-		strlen(path_fs), path_fs, nullptr)) {
-		char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX);
-		if(!sub) return 1;
-
-		sub+=strlen("/" SUBTUNE_PREFIX);
-		int song_num=strtol(sub, nullptr, 10);
-
-		if (errno == EINVAL)
-			return 1;
-		else
-			return song_num;
-	} else
-		return 1;
+	const Path base = path_fs.GetBase();
+	unsigned track;
+	if (base.IsNull() ||
+	    (track = ParseSubtuneName(base.c_str())) < 1)
+		return { AllocatedPath(path_fs), 1 };
+
+	return { path_fs.GetDirectoryName(), track };
 }
 
-/* get the song length in seconds */
+#ifdef HAVE_SIDPLAYFP
+
 static SignedSongTime
-get_song_length(Path path_fs)
+get_song_length(SidTune &tune)
 {
 	if (songlength_database == nullptr)
 		return SignedSongTime::Negative();
 
-	char *sid_file = get_container_name(path_fs);
-	SidTuneMod tune(sid_file);
-	free(sid_file);
-	if(!tune) {
-		LogWarning(sidplay_domain,
-			   "failed to load file for calculating md5 sum");
+	const auto length = songlength_database->length(tune);
+	if (length < 0)
 		return SignedSongTime::Negative();
-	}
-	char md5sum[SIDTUNE_MD5_LENGTH+1];
-	tune.createMD5(md5sum);
 
-	const unsigned song_num = get_song_num(path_fs.c_str());
+	return SignedSongTime::FromS(length);
+}
 
-	gsize num_items;
-	gchar **values=g_key_file_get_string_list(songlength_database,
-		"Database", md5sum, &num_items, nullptr);
-	if(!values || song_num>num_items) {
-		g_strfreev(values);
-		return SignedSongTime::Negative();
-	}
+#else
 
-	int minutes=strtol(values[song_num-1], nullptr, 10);
-	if(errno==EINVAL) minutes=0;
+static SignedSongTime
+get_song_length(SidTuneMod &tune)
+{
+	assert(tune);
 
-	int seconds;
-	char *ptr=strchr(values[song_num-1], ':');
-	if(ptr) {
-		seconds=strtol(ptr+1, nullptr, 10);
-		if(errno==EINVAL) seconds=0;
-	} else
-		seconds=0;
+	if (songlength_database == nullptr)
+		return SignedSongTime::Negative();
 
-	g_strfreev(values);
+	const auto length = songlength_database->length(tune);
+	if (length < 0)
+		return SignedSongTime::Negative();
 
-	return SignedSongTime::FromS((minutes * 60) + seconds);
+	return SignedSongTime::FromS(length);
 }
 
+#endif
+
 static void
 sidplay_file_decode(Decoder &decoder, Path path_fs)
 {
@@ -209,26 +186,43 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 
 	/* load the tune */
 
-	char *path_container=get_container_name(path_fs);
-	SidTune tune(path_container, nullptr, true);
-	free(path_container);
-	if (!tune) {
-		LogWarning(sidplay_domain, "failed to load file");
+	const auto container = ParseContainerPath(path_fs);
+#ifdef HAVE_SIDPLAYFP
+	SidTune tune(container.path.c_str());
+#else
+	SidTuneMod tune(container.path.c_str());
+#endif
+	if (!tune.getStatus()) {
+#ifdef HAVE_SIDPLAYFP
+		const char *error = tune.statusString();
+#else
+		const char *error = tune.getInfo().statusString;
+#endif
+		FormatWarning(sidplay_domain, "failed to load file: %s",
+			      error);
 		return;
 	}
 
-	const int song_num = get_song_num(path_fs.c_str());
+	const int song_num = container.track;
 	tune.selectSong(song_num);
 
-	auto duration = get_song_length(path_fs);
+	auto duration = get_song_length(tune);
 	if (duration.IsNegative() && default_songlength > 0)
 		duration = SongTime::FromS(default_songlength);
 
 	/* initialize the player */
 
+#ifdef HAVE_SIDPLAYFP
+	sidplayfp player;
+#else
 	sidplay2 player;
-	int iret = player.load(&tune);
-	if (iret != 0) {
+#endif
+#ifdef HAVE_SIDPLAYFP
+	bool error = !player.load(&tune);
+#else
+	bool error = player.load(&tune) < 0;
+#endif
+	if (error) {
 		FormatWarning(sidplay_domain,
 			      "sidplay2.load() failed: %s", player.error());
 		return;
@@ -236,53 +230,104 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 
 	/* initialize the builder */
 
-	ReSIDBuilder builder("ReSID");
-	if (!builder) {
-		LogWarning(sidplay_domain,
-			   "failed to initialize ReSIDBuilder");
+#ifdef HAVE_SIDPLAYFP
+	ReSIDfpBuilder builder("ReSID");
+	if (!builder.getStatus()) {
+		FormatWarning(sidplay_domain,
+			      "failed to initialize ReSIDfpBuilder: %s",
+			      builder.error());
 		return;
 	}
 
+	builder.create(player.info().maxsids());
+	if (!builder.getStatus()) {
+		FormatWarning(sidplay_domain,
+			      "ReSIDfpBuilder.create() failed: %s",
+			      builder.error());
+		return;
+	}
+#else
+	ReSIDBuilder builder("ReSID");
 	builder.create(player.info().maxsids);
 	if (!builder) {
-		LogWarning(sidplay_domain, "ReSIDBuilder.create() failed");
+		FormatWarning(sidplay_domain, "ReSIDBuilder.create() failed: %s",
+			      builder.error());
 		return;
 	}
+#endif
 
 	builder.filter(filter_setting);
+#ifdef HAVE_SIDPLAYFP
+	if (!builder.getStatus()) {
+		FormatWarning(sidplay_domain,
+			      "ReSIDfpBuilder.filter() failed: %s",
+			      builder.error());
+		return;
+	}
+#else
 	if (!builder) {
-		LogWarning(sidplay_domain, "ReSIDBuilder.filter() failed");
+		FormatWarning(sidplay_domain, "ReSIDBuilder.filter() failed: %s",
+			      builder.error());
 		return;
 	}
+#endif
 
 	/* configure the player */
 
-	sid2_config_t config = player.config();
+	auto config = player.config();
 
+#ifndef HAVE_SIDPLAYFP
 	config.clockDefault = SID2_CLOCK_PAL;
 	config.clockForced = true;
 	config.clockSpeed = SID2_CLOCK_CORRECT;
+#endif
 	config.frequency = 48000;
+#ifndef HAVE_SIDPLAYFP
 	config.optimisation = SID2_DEFAULT_OPTIMISATION;
 
 	config.precision = 16;
 	config.sidDefault = SID2_MOS6581;
+#endif
 	config.sidEmulation = &builder;
+#ifdef HAVE_SIDPLAYFP
+	config.samplingMethod = SidConfig::INTERPOLATE;
+	config.fastSampling = false;
+#else
 	config.sidModel = SID2_MODEL_CORRECT;
 	config.sidSamples = true;
 	config.sampleFormat = IsLittleEndian()
 		? SID2_LITTLE_SIGNED
 		: SID2_BIG_SIGNED;
-	if (tune.isStereo()) {
+#endif
+
+#ifdef HAVE_SIDPLAYFP
+	const bool stereo = tune.getInfo()->sidChips() >= 2;
+#else
+	const bool stereo = tune.isStereo();
+#endif
+
+	if (stereo) {
+#ifdef HAVE_SIDPLAYFP
+		config.playback = SidConfig::STEREO;
+#else
 		config.playback = sid2_stereo;
+#endif
 		channels = 2;
 	} else {
+#ifdef HAVE_SIDPLAYFP
+		config.playback = SidConfig::MONO;
+#else
 		config.playback = sid2_mono;
+#endif
 		channels = 1;
 	}
 
-	iret = player.config(config);
-	if (iret != 0) {
+#ifdef HAVE_SIDPLAYFP
+	error = !player.config(config);
+#else
+	error = player.config(config) < 0;
+#endif
+	if (error) {
 		FormatWarning(sidplay_domain,
 			      "sidplay2.config() failed: %s", player.error());
 		return;
@@ -297,17 +342,21 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 
 	/* .. and play */
 
+#ifdef HAVE_SIDPLAYFP
+	constexpr unsigned timebase = 1;
+#else
 	const unsigned timebase = player.timebase();
+#endif
 	const unsigned end = duration.IsNegative()
 		? 0u
 		: duration.ToScale<uint64_t>(timebase);
 
 	DecoderCommand cmd;
 	do {
-		char buffer[4096];
+		short buffer[4096];
 		size_t nbytes;
 
-		nbytes = player.play(buffer, sizeof(buffer));
+		nbytes = player.play(buffer, ARRAY_SIZE(buffer));
 		if (nbytes == 0)
 			break;
 
@@ -328,7 +377,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 
 			/* ignore data until target time is reached */
 			while(data_time<target_time) {
-				nbytes=player.play(buffer, sizeof(buffer));
+				nbytes=player.play(buffer, ARRAY_SIZE(buffer));
 				if(nbytes==0)
 					break;
 				data_time = player.time();
@@ -343,41 +392,72 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
 	} while (cmd != DecoderCommand::STOP);
 }
 
+gcc_pure
+static const char *
+GetInfoString(const SidTuneInfo &info, unsigned i)
+{
+#ifdef HAVE_SIDPLAYFP
+	return info.numberOfInfoStrings() > i
+		? info.infoString(i)
+		: nullptr;
+#else
+	return info.numberOfInfoStrings > i
+		? info.infoString[i]
+		: nullptr;
+#endif
+}
+
 static bool
 sidplay_scan_file(Path path_fs,
 		  const struct tag_handler *handler, void *handler_ctx)
 {
-	const int song_num = get_song_num(path_fs.c_str());
-	char *path_container=get_container_name(path_fs);
-
-	SidTune tune(path_container, nullptr, true);
-	free(path_container);
-	if (!tune)
+	const auto container = ParseContainerPath(path_fs);
+	const unsigned song_num = container.track;
+
+#ifdef HAVE_SIDPLAYFP
+	SidTune tune(container.path.c_str());
+#else
+	SidTuneMod tune(container.path.c_str());
+#endif
+	if (!tune.getStatus())
 		return false;
 
+	tune.selectSong(song_num);
+
+#ifdef HAVE_SIDPLAYFP
+	const SidTuneInfo &info = *tune.getInfo();
+	const unsigned n_tracks = info.songs();
+#else
 	const SidTuneInfo &info = tune.getInfo();
+	const unsigned n_tracks = info.songs;
+#endif
 
 	/* title */
-	const char *title;
-	if (info.numberOfInfoStrings > 0 && info.infoString[0] != nullptr)
-		title=info.infoString[0];
-	else
-		title="";
+	const char *title = GetInfoString(info, 0);
+	if (title == nullptr)
+		title = "";
 
-	if(info.songs>1) {
+	if (n_tracks > 1) {
 		char tag_title[1024];
 		snprintf(tag_title, sizeof(tag_title),
-			 "%s (%d/%d)",
-			 title, song_num, info.songs);
+			 "%s (%d/%u)",
+			 title, song_num, n_tracks);
 		tag_handler_invoke_tag(handler, handler_ctx,
 				       TAG_TITLE, tag_title);
 	} else
 		tag_handler_invoke_tag(handler, handler_ctx, TAG_TITLE, title);
 
 	/* artist */
-	if (info.numberOfInfoStrings > 1 && info.infoString[1] != nullptr)
+	const char *artist = GetInfoString(info, 1);
+	if (artist != nullptr)
 		tag_handler_invoke_tag(handler, handler_ctx, TAG_ARTIST,
-				       info.infoString[1]);
+				       artist);
+
+	/* date */
+	const char *date = GetInfoString(info, 2);
+	if (date != nullptr)
+		tag_handler_invoke_tag(handler, handler_ctx, TAG_DATE,
+				       date);
 
 	/* track */
 	char track[16];
@@ -385,7 +465,7 @@ sidplay_scan_file(Path path_fs,
 	tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
 
 	/* time */
-	const auto duration = get_song_length(path_fs);
+	const auto duration = get_song_length(tune);
 	if (!duration.IsNegative())
 		tag_handler_invoke_duration(handler, handler_ctx,
 					    SongTime(duration));
@@ -397,19 +477,25 @@ static char *
 sidplay_container_scan(Path path_fs, const unsigned int tnum)
 {
 	SidTune tune(path_fs.c_str(), nullptr, true);
-	if (!tune)
+	if (!tune.getStatus())
 		return nullptr;
 
-	const SidTuneInfo &info=tune.getInfo();
+#ifdef HAVE_SIDPLAYFP
+	const SidTuneInfo &info = *tune.getInfo();
+	const unsigned n_tracks = info.songs();
+#else
+	const SidTuneInfo &info = tune.getInfo();
+	const unsigned n_tracks = info.songs;
+#endif
 
 	/* Don't treat sids containing a single tune
 		as containers */
-	if(!all_files_are_containers && info.songs<2)
+	if(!all_files_are_containers && n_tracks < 2)
 		return nullptr;
 
 	/* Construct container/tune path names, eg.
 		Delta.sid/tune_001.sid */
-	if(tnum<=info.songs) {
+	if (tnum <= n_tracks) {
 		return FormatNew(SUBTUNE_PREFIX "%03u.sid", tnum);
 	} else
 		return nullptr;
diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx
index c345470..e3281b7 100644
--- a/src/fs/AllocatedPath.hxx
+++ b/src/fs/AllocatedPath.hxx
@@ -252,7 +252,7 @@ public:
 	void ChopSeparators();
 
 	gcc_pure
-	bool IsAbsolute() {
+	bool IsAbsolute() const {
 		return PathTraitsFS::IsAbsolute(c_str());
 	}
 };
diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx
index 9e0fa5a..084b7c3 100644
--- a/src/fs/Path.hxx
+++ b/src/fs/Path.hxx
@@ -29,6 +29,8 @@
 #include <assert.h>
 #include <string.h>
 
+class AllocatedPath;
+
 /**
  * A path name in the native file system character set.
  *
@@ -129,6 +131,22 @@ public:
 	std::string ToUTF8() const;
 
 	/**
+	 * Determine the "base" file name.
+	 * The return value points inside this object.
+	 */
+	gcc_pure
+	Path GetBase() const {
+		return FromFS(PathTraitsFS::GetBase(value));
+	}
+
+	/**
+	 * Gets directory name of this path.
+	 * Returns a "nulled" instance on error.
+	 */
+	gcc_pure
+	AllocatedPath GetDirectoryName() const;
+
+	/**
 	 * Determine the relative part of the given path to this
 	 * object, not including the directory separator.  Returns an
 	 * empty string if the given path equals this object or
@@ -140,7 +158,7 @@ public:
 	}
 
 	gcc_pure
-	bool IsAbsolute() {
+	bool IsAbsolute() const {
 		return PathTraitsFS::IsAbsolute(c_str());
 	}
 };
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/fs/Path2.cxx
similarity index 71%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/fs/Path2.cxx
index 5eb41db..966e34d 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/fs/Path2.cxx
@@ -17,22 +17,12 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#include "config.h"
+#include "Path.hxx"
+#include "AllocatedPath.hxx"
 
-extern "C" {
-#include <libavutil/dict.h>
+AllocatedPath
+Path::GetDirectoryName() const
+{
+	return AllocatedPath::FromFS(PathTraitsFS::GetParent(c_str()));
 }
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
-
-void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
-
-#endif
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/Buffer.hxx
similarity index 53%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/Buffer.hxx
index 5eb41db..50a702f 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/Buffer.hxx
@@ -17,22 +17,56 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#ifndef MPD_FFMPEG_BUFFER_HXX
+#define MPD_FFMPEG_BUFFER_HXX
 
 extern "C" {
-#include <libavutil/dict.h>
+#include <libavutil/mem.h>
+
+#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 18, 0)
+#define HAVE_AV_FAST_MALLOC
+#else
+#include <libavcodec/avcodec.h>
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0)
+#define HAVE_AV_FAST_MALLOC
+#endif
+#endif
 }
 
+#include <stddef.h>
+
 /* suppress the ffmpeg compatibility macro */
 #ifdef SampleFormat
 #undef SampleFormat
 #endif
 
-struct tag_handler;
+class FfmpegBuffer {
+	void *data;
+	unsigned size;
+
+public:
+	FfmpegBuffer():data(nullptr), size(0) {}
+
+	~FfmpegBuffer() {
+		av_free(data);
+	}
+
+	void *Get(size_t min_size) {
+#ifdef HAVE_AV_FAST_MALLOC
+		av_fast_malloc(&data, &size, min_size);
+#else
+		void *new_data = av_fast_realloc(data, &size, min_size);
+		if (new_data == nullptr)
+			return AVERROR(ENOMEM);
+		data = new_data;
+#endif
+		return data;
+	}
 
-void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+	template<typename T>
+	T *GetT(size_t n) {
+		return (T *)Get(n * sizeof(T));
+	}
+};
 
 #endif
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/Init.cxx
similarity index 72%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/Init.cxx
index 5eb41db..24f4ab2 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/Init.cxx
@@ -17,22 +17,22 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "Init.hxx"
+#include "LogCallback.hxx"
 
 extern "C" {
-#include <libavutil/dict.h>
+#include <libavformat/avformat.h>
 }
 
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
-
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+FfmpegInit()
+{
+	av_log_set_callback(FfmpegLogCallback);
+
+	av_register_all();
+}
 
-#endif
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/Init.hxx
similarity index 71%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/Init.hxx
index 5eb41db..bcc4805 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/Init.hxx
@@ -17,22 +17,10 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
-
-extern "C" {
-#include <libavutil/dict.h>
-}
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
+#ifndef MPD_FFMPEG_INIT_HXX
+#define MPD_FFMPEG_INIT_HXX
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+FfmpegInit();
 
 #endif
diff --git a/src/lib/ffmpeg/LogCallback.cxx b/src/lib/ffmpeg/LogCallback.cxx
new file mode 100644
index 0000000..799ba2f
--- /dev/null
+++ b/src/lib/ffmpeg/LogCallback.cxx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "LogCallback.hxx"
+#include "Domain.hxx"
+#include "LogV.hxx"
+#include "util/Domain.hxx"
+
+extern "C" {
+#include <libavutil/log.h>
+}
+
+#include <stdio.h>
+
+gcc_const
+static LogLevel
+FfmpegImportLogLevel(int level)
+{
+	if (level <= AV_LOG_FATAL)
+		return LogLevel::ERROR;
+
+	if (level <= AV_LOG_WARNING)
+		return LogLevel::WARNING;
+
+	if (level <= AV_LOG_INFO)
+		return LogLevel::INFO;
+
+	return LogLevel::DEBUG;
+}
+
+void
+FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl)
+{
+	const AVClass * cls = nullptr;
+
+	if (ptr != nullptr)
+		cls = *(const AVClass *const*)ptr;
+
+	if (cls != nullptr) {
+		char domain[64];
+		snprintf(domain, sizeof(domain), "%s/%s",
+			 ffmpeg_domain.GetName(), cls->item_name(ptr));
+		const Domain d(domain);
+		LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl);
+	}
+}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/LogCallback.hxx
similarity index 72%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/LogCallback.hxx
index 5eb41db..cb4b2cc 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/LogCallback.hxx
@@ -17,22 +17,14 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#ifndef MPD_FFMPEG_LOG_CALLBACK_HXX
+#define MPD_FFMPEG_LOG_CALLBACK_HXX
 
-extern "C" {
-#include <libavutil/dict.h>
-}
+#include "check.h"
 
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
+#include <stdarg.h>
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+FfmpegLogCallback(void *ptr, int level, const char *fmt, va_list vl);
 
 #endif
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/LogError.cxx
similarity index 65%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/LogError.cxx
index 5eb41db..da761f3 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/LogError.cxx
@@ -17,22 +17,29 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#include "config.h"
+#include "LogError.hxx"
+#include "Domain.hxx"
+#include "Log.hxx"
+
+#include <cstdint> /* needed due to libavutil bug */
 
 extern "C" {
-#include <libavutil/dict.h>
+#include <libavutil/error.h>
 }
 
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
-
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+LogFfmpegError(int errnum)
+{
+	char msg[256];
+	av_strerror(errnum, msg, sizeof(msg));
+	LogError(ffmpeg_domain, msg);
+}
 
-#endif
+void
+LogFfmpegError(int errnum, const char *prefix)
+{
+	char msg[256];
+	av_strerror(errnum, msg, sizeof(msg));
+	FormatError(ffmpeg_domain, "%s: %s", prefix, msg);
+}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/lib/ffmpeg/LogError.hxx
similarity index 72%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/lib/ffmpeg/LogError.hxx
index 5eb41db..ccafc6f 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/lib/ffmpeg/LogError.hxx
@@ -17,22 +17,13 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#ifndef MPD_FFMPEG_LOG_ERROR_HXX
+#define MPD_FFMPEG_LOG_ERROR_HXX
 
-extern "C" {
-#include <libavutil/dict.h>
-}
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
+void
+LogFfmpegError(int errnum);
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+LogFfmpegError(int errnum, const char *prefix);
 
 #endif
diff --git a/src/lib/ffmpeg/Time.hxx b/src/lib/ffmpeg/Time.hxx
new file mode 100644
index 0000000..9325434
--- /dev/null
+++ b/src/lib/ffmpeg/Time.hxx
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_TIME_HXX
+#define MPD_FFMPEG_TIME_HXX
+
+#include "Chrono.hxx"
+#include "Compiler.h"
+
+extern "C" {
+#include <libavutil/avutil.h>
+#include <libavutil/mathematics.h>
+}
+
+#include <assert.h>
+#include <stdint.h>
+
+/* suppress the ffmpeg compatibility macro */
+#ifdef SampleFormat
+#undef SampleFormat
+#endif
+
+gcc_const
+static inline double
+FfmpegTimeToDouble(int64_t t, const AVRational time_base)
+{
+	assert(t != (int64_t)AV_NOPTS_VALUE);
+
+	return (double)av_rescale_q(t, time_base, (AVRational){1, 1024})
+		/ (double)1024;
+}
+
+template<typename Ratio>
+static inline constexpr AVRational
+RatioToAVRational()
+{
+	return { Ratio::num, Ratio::den };
+}
+
+/**
+ * Convert a FFmpeg time stamp to a #SongTime.
+ */
+gcc_const
+static inline SongTime
+FromFfmpegTime(int64_t t, const AVRational time_base)
+{
+	assert(t != (int64_t)AV_NOPTS_VALUE);
+
+	return SongTime::FromMS(av_rescale_q(t, time_base,
+					     (AVRational){1, 1000}));
+}
+
+/**
+ * Convert a FFmpeg time stamp to a #SignedSongTime.
+ */
+gcc_const
+static inline SignedSongTime
+FromFfmpegTimeChecked(int64_t t, const AVRational time_base)
+{
+	return t != (int64_t)AV_NOPTS_VALUE
+		? SignedSongTime(FromFfmpegTime(t, time_base))
+		: SignedSongTime::Negative();
+}
+
+/**
+ * Convert a #SongTime to a FFmpeg time stamp with the given base.
+ */
+gcc_const
+static inline int64_t
+ToFfmpegTime(SongTime t, const AVRational time_base)
+{
+	return av_rescale_q(t.count(),
+			    RatioToAVRational<SongTime::period>(),
+			    time_base);
+}
+
+/**
+ * Replace #AV_NOPTS_VALUE with the given fallback.
+ */
+static constexpr int64_t
+FfmpegTimestampFallback(int64_t t, int64_t fallback)
+{
+	return gcc_likely(t != int64_t(AV_NOPTS_VALUE))
+		? t
+		: fallback;
+}
+
+#endif
diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx
index 6d50cce..2164b1d 100644
--- a/src/lib/nfs/Manager.cxx
+++ b/src/lib/nfs/Manager.cxx
@@ -59,6 +59,18 @@ NfsManager::Compare::operator()(const ManagedConnection &a,
 	return result < 0;
 }
 
+inline bool
+NfsManager::Compare::operator()(const ManagedConnection &a,
+				const ManagedConnection &b) const
+{
+	int result = strcmp(a.GetServer(), b.GetServer());
+	if (result != 0)
+		return result < 0;
+
+	result = strcmp(a.GetExportName(), b.GetExportName());
+	return result < 0;
+}
+
 NfsManager::~NfsManager()
 {
 	assert(GetEventLoop().IsInside());
diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx
index 130c81a..80acbdf 100644
--- a/src/lib/nfs/Manager.hxx
+++ b/src/lib/nfs/Manager.hxx
@@ -64,6 +64,10 @@ class NfsManager final : IdleMonitor {
 		gcc_pure
 		bool operator()(const ManagedConnection &a,
 				const LookupKey b) const;
+
+		gcc_pure
+		bool operator()(const ManagedConnection &a,
+				const ManagedConnection &b) const;
 	};
 
 	/**
diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx
index 406be8d..b0456f5 100644
--- a/src/output/plugins/ShoutOutputPlugin.cxx
+++ b/src/output/plugins/ShoutOutputPlugin.cxx
@@ -164,7 +164,9 @@ ShoutOutput::Configure(const config_param &param, Error &error)
 		}
 	}
 
-	const char *encoding = param.GetBlockValue("encoding", "ogg");
+	const char *encoding = param.GetBlockValue("encoder", nullptr);
+	if (encoding == nullptr)
+		encoding = param.GetBlockValue("encoding", "vorbis");
 	const auto encoder_plugin = shout_encoder_plugin_get(encoding);
 	if (encoder_plugin == nullptr) {
 		error.Format(config_domain,
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/pcm/Interleave.cxx
similarity index 50%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/pcm/Interleave.cxx
index 5eb41db..8f2b11b 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/pcm/Interleave.cxx
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
  * http://www.musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,22 +17,31 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#include "config.h"
+#include "Interleave.hxx"
 
-extern "C" {
-#include <libavutil/dict.h>
-}
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
+#include <stdint.h>
+#include <string.h>
 
-struct tag_handler;
+static void
+GenericPcmInterleave(uint8_t *dest, ConstBuffer<const uint8_t *> src,
+		     size_t n_frames, size_t sample_size)
+{
+	for (size_t frame = 0; frame < n_frames; ++frame) {
+		for (size_t channel = 0; channel < src.size; ++channel) {
+			memcpy(dest, src[channel] + frame * sample_size,
+			       sample_size);
+			dest += sample_size;
+		}
+	}
+}
 
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
-
-#endif
+PcmInterleave(void *dest, ConstBuffer<const void *> src,
+	      size_t n_frames, size_t sample_size)
+{
+	GenericPcmInterleave((uint8_t *)dest,
+			     ConstBuffer<const uint8_t *>((const uint8_t *const*)src.data,
+							  src.size),
+			     n_frames, sample_size);
+}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/pcm/Interleave.hxx
similarity index 66%
copy from src/decoder/plugins/FfmpegMetaData.hxx
copy to src/pcm/Interleave.hxx
index 5eb41db..c8acbb3 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/pcm/Interleave.hxx
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
  * http://www.musicpd.org
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,22 +17,17 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_FFMPEG_METADATA_HXX
-#define MPD_FFMPEG_METADATA_HXX
+#ifndef MPD_PCM_INTERLEAVE_HXX
+#define MPD_PCM_INTERLEAVE_HXX
 
-extern "C" {
-#include <libavutil/dict.h>
-}
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-struct tag_handler;
+#include "check.h"
+#include "util/ConstBuffer.hxx"
 
+/**
+ * Interleave planar PCM samples from #src to #dest.
+ */
 void
-ffmpeg_scan_dictionary(AVDictionary *dict,
-		       const tag_handler *handler, void *handler_ctx);
+PcmInterleave(void *dest, ConstBuffer<const void *> src,
+	      size_t n_frames, size_t sample_size);
 
 #endif
diff --git a/src/util/ScopeExit.hxx b/src/util/ScopeExit.hxx
new file mode 100644
index 0000000..0ec65cd
--- /dev/null
+++ b/src/util/ScopeExit.hxx
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Max Kellermann <max at duempel.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SCOPE_EXIT_HXX
+#define SCOPE_EXIT_HXX
+
+#include "Compiler.h"
+
+#include <utility>
+
+/**
+ * Internal class.  Do not use directly.
+ */
+template<typename F>
+class ScopeExitGuard : F {
+	bool enabled = true;
+
+public:
+	explicit ScopeExitGuard(F &&f):F(std::forward<F>(f)) {}
+
+	ScopeExitGuard(ScopeExitGuard &&src)
+		:F(std::move(src)) {
+		src.enabled = false;
+	}
+
+	~ScopeExitGuard() {
+		if (enabled)
+			F::operator()();
+	}
+
+	ScopeExitGuard(const ScopeExitGuard &) = delete;
+	ScopeExitGuard &operator=(const ScopeExitGuard &) = delete;
+};
+
+/**
+ * Internal class.  Do not use directly.
+ */
+struct ScopeExitTag {
+	/* this operator is a trick so we don't need to close
+	   parantheses at the end of the expression AtScopeExit()
+	   call */
+	template<typename F>
+	ScopeExitGuard<F> operator+(F &&f) {
+		return ScopeExitGuard<F>(std::forward<F>(f));
+	}
+};
+
+#define ScopeExitCat(a, b) a ## b
+#define ScopeExitName(line) ScopeExitCat(at_scope_exit_, line)
+
+/**
+ * Call the block after this macro at the end of the current scope.
+ * Parameters are lambda captures.
+ *
+ * This is exception-safe, however the given code block must not throw
+ * exceptions.
+ *
+ * This attempts to be a better boost/scope_exit.hpp, without all of
+ * Boost's compile-time and runtime bloat.
+ */
+#define AtScopeExit(...) auto ScopeExitName(__LINE__) = ScopeExitTag() + [__VA_ARGS__]()
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mpd/pkg-mpd.git



More information about the Pkg-mpd-commits mailing list