Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mpd for openSUSE:Factory checked in 
at 2021-09-01 21:37:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mpd (Old)
 and      /work/SRC/openSUSE:Factory/.mpd.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mpd"

Wed Sep  1 21:37:07 2021 rev:34 rq:915422 version:0.22.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/mpd/mpd.changes  2021-08-18 08:57:00.878897109 
+0200
+++ /work/SRC/openSUSE:Factory/.mpd.new.1899/mpd.changes        2021-09-01 
21:37:29.368899168 +0200
@@ -1,0 +2,11 @@
+Wed Sep  1 07:24:21 UTC 2021 - ???????? ???????????? <[email protected]>
+
+- Updated to 0.22.11
+  * https://github.com/MusicPlayerDaemon/MPD/blob/v0.22.11/NEWS
+  * protocol: fix "albumart" crash.
+  * filter: ffmpeg:
+    * pass "channel_layout" instead of "channels" to buffersrc
+    * fix "av_buffersink_get_frame() failed: Resource temporarily unavailable"
+    * support double-precision samples (by converting to single precision)
+
+-------------------------------------------------------------------

Old:
----
  mpd-0.22.10.tar.xz
  mpd-0.22.10.tar.xz.sig

New:
----
  mpd-0.22.11.tar.xz
  mpd-0.22.11.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mpd.spec ++++++
--- /var/tmp/diff_new_pack.3sLbma/_old  2021-09-01 21:37:29.872899775 +0200
+++ /var/tmp/diff_new_pack.3sLbma/_new  2021-09-01 21:37:29.876899779 +0200
@@ -20,7 +20,7 @@
 %bcond_with    faad
 %bcond_without mpd_iso9660
 Name:           mpd
-Version:        0.22.10
+Version:        0.22.11
 Release:        0
 Summary:        Music Player Daemon
 License:        GPL-2.0-or-later

++++++ mpd-0.22.10.tar.xz -> mpd-0.22.11.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/NEWS new/mpd-0.22.11/NEWS
--- old/mpd-0.22.10/NEWS        2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/NEWS        2021-08-24 22:15:22.000000000 +0200
@@ -1,3 +1,14 @@
+ver 0.22.11 (2021/08/24)
+* protocol
+  - fix "albumart" crash
+* filter
+  - ffmpeg: pass "channel_layout" instead of "channels" to buffersrc
+  - ffmpeg: fix "av_buffersink_get_frame() failed: Resource temporarily 
unavailable"
+  - ffmpeg: support double-precision samples (by converting to single 
precision)
+* Android
+  - build with NDK r23
+  - playlist_directory defaults to 
"/sdcard/Android/data/org.musicpd/files/playlists"
+
 ver 0.22.10 (2021/08/06)
 * protocol
   - support "albumart" for virtual tracks in CUE sheets
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/android/AndroidManifest.xml 
new/mpd-0.22.11/android/AndroidManifest.xml
--- old/mpd-0.22.10/android/AndroidManifest.xml 2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/android/AndroidManifest.xml 2021-08-24 22:15:22.000000000 
+0200
@@ -2,8 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android";
           package="org.musicpd"
           android:installLocation="auto"
-          android:versionCode="58"
-          android:versionName="0.22.10">
+          android:versionCode="59"
+          android:versionName="0.22.11">
 
   <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/android/build.py 
new/mpd-0.22.11/android/build.py
--- old/mpd-0.22.10/android/build.py    2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/android/build.py    2021-08-24 22:15:22.000000000 +0200
@@ -24,15 +24,13 @@
     'armeabi-v7a': {
         'arch': 'arm-linux-androideabi',
         'ndk_arch': 'arm',
-        'toolchain_arch': 'arm-linux-androideabi',
         'llvm_triple': 'armv7-linux-androideabi',
-        'cflags': '-fpic -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp',
+        'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
     },
 
     'arm64-v8a': {
         'arch': 'aarch64-linux-android',
         'ndk_arch': 'arm64',
-        'toolchain_arch': 'aarch64-linux-android',
         'llvm_triple': 'aarch64-linux-android',
         'cflags': '-fpic',
     },
@@ -40,7 +38,6 @@
     'x86': {
         'arch': 'i686-linux-android',
         'ndk_arch': 'x86',
-        'toolchain_arch': 'x86',
         'llvm_triple': 'i686-linux-android',
         'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
     },
@@ -48,7 +45,6 @@
     'x86_64': {
         'arch': 'x86_64-linux-android',
         'ndk_arch': 'x86_64',
-        'toolchain_arch': 'x86_64',
         'llvm_triple': 'x86_64-linux-android',
         'cflags': '-fPIC -m64',
     },
@@ -84,37 +80,28 @@
         ndk_arch = abi_info['ndk_arch']
         android_api_level = '21'
 
-        # select the NDK compiler
-        gcc_version = '4.9'
-
         install_prefix = os.path.join(arch_path, 'root')
 
         self.arch = arch
         self.install_prefix = install_prefix
-        self.toolchain_arch = abi_info['toolchain_arch']
 
-        toolchain_path = os.path.join(ndk_path, 'toolchains', 
self.toolchain_arch + '-' + gcc_version, 'prebuilt', build_arch)
         llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', 
build_arch)
         llvm_triple = abi_info['llvm_triple'] + android_api_level
 
         common_flags = '-Os -g'
         common_flags += ' ' + abi_info['cflags']
 
-        toolchain_bin = os.path.join(toolchain_path, 'bin')
         llvm_bin = os.path.join(llvm_path, 'bin')
         self.cc = os.path.join(llvm_bin, 'clang')
         self.cxx = os.path.join(llvm_bin, 'clang++')
-        common_flags += ' -target ' + llvm_triple + ' -gcc-toolchain ' + 
toolchain_path
+        common_flags += ' -target ' + llvm_triple
 
         common_flags += ' -fvisibility=hidden -fdata-sections 
-ffunction-sections'
 
-        # required flags from 
https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md#additional-required-arguments
-        common_flags += ' -fno-addrsig'
-
-        self.ar = os.path.join(toolchain_bin, arch + '-ar')
-        self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
-        self.nm = os.path.join(toolchain_bin, arch + '-nm')
-        self.strip = os.path.join(toolchain_bin, arch + '-strip')
+        self.ar = os.path.join(llvm_bin, 'llvm-ar')
+        self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
+        self.nm = os.path.join(llvm_bin, 'llvm-nm')
+        self.strip = os.path.join(llvm_bin, 'llvm-strip')
 
         self.cflags = common_flags
         self.cxxflags = common_flags
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/doc/conf.py new/mpd-0.22.11/doc/conf.py
--- old/mpd-0.22.10/doc/conf.py 2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/doc/conf.py 2021-08-24 22:15:22.000000000 +0200
@@ -38,7 +38,7 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.22.10'
+version = '0.22.11'
 # The full version, including alpha/beta/rc tags.
 release = version
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/doc/user.rst new/mpd-0.22.11/doc/user.rst
--- old/mpd-0.22.10/doc/user.rst        2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/doc/user.rst        2021-08-24 22:15:22.000000000 +0200
@@ -176,7 +176,7 @@
 You need:
 
 * Android SDK
-* `Android NDK r22 <https://developer.android.com/ndk/downloads>`_
+* `Android NDK r23 <https://developer.android.com/ndk/downloads>`_
 * `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
   <https://ninja-build.org/>`__
 * cmake
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/meson.build new/mpd-0.22.11/meson.build
--- old/mpd-0.22.10/meson.build 2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/meson.build 2021-08-24 22:15:22.000000000 +0200
@@ -1,7 +1,7 @@
 project(
   'mpd',
   ['c', 'cpp'],
-  version: '0.22.10',
+  version: '0.22.11',
   meson_version: '>= 0.49.0',
   default_options: [
     'c_std=c11',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/python/build/openssl.py 
new/mpd-0.22.11/python/build/openssl.py
--- old/mpd-0.22.10/python/build/openssl.py     2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/python/build/openssl.py     2021-08-24 22:15:22.000000000 
+0200
@@ -48,7 +48,6 @@
         }
 
         openssl_arch = openssl_archs[toolchain.arch]
-        cross_compile_prefix = toolchain.toolchain_arch + '-'
 
         subprocess.check_call(['./Configure',
                                'no-shared',
@@ -57,7 +56,6 @@
                                'no-tests',
                                'no-asm', # "asm" causes build failures on 
Windows
                                openssl_arch,
-                               '--cross-compile-prefix=' + 
cross_compile_prefix,
                                '--prefix=' + toolchain.install_prefix],
                               cwd=src, env=toolchain.env)
         MakeProject.build(self, toolchain, src)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/Main.cxx new/mpd-0.22.11/src/Main.cxx
--- old/mpd-0.22.10/src/Main.cxx        2021-08-06 18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/Main.cxx        2021-08-24 22:15:22.000000000 +0200
@@ -157,7 +157,17 @@
 static void
 glue_mapper_init(const ConfigData &config)
 {
-       mapper_init(config.GetPath(ConfigOption::PLAYLIST_DIR));
+       auto playlist_directory = config.GetPath(ConfigOption::PLAYLIST_DIR);
+
+#ifdef ANDROID
+       /* if there is no explicit configuration, store playlists in
+          "/sdcard/Android/data/org.musicpd/files/playlists" */
+       if (playlist_directory.IsNull())
+               playlist_directory = 
context->GetExternalFilesDir(Java::GetEnv(),
+                                                                 "playlists");
+#endif
+
+       mapper_init(std::move(playlist_directory));
 }
 
 #ifdef ENABLE_DATABASE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/android/Context.cxx 
new/mpd-0.22.11/src/android/Context.cxx
--- old/mpd-0.22.10/src/android/Context.cxx     2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/src/android/Context.cxx     2021-08-24 22:15:22.000000000 
+0200
@@ -27,6 +27,25 @@
 #include "AudioManager.hxx"
 
 AllocatedPath
+Context::GetExternalFilesDir(JNIEnv *env, const char *_type) noexcept
+{
+       assert(_type != nullptr);
+
+       Java::Class cls{env, env->GetObjectClass(Get())};
+       jmethodID method = env->GetMethodID(cls, "getExternalFilesDir",
+                                           
"(Ljava/lang/String;)Ljava/io/File;");
+       assert(method);
+
+       Java::String type{env, _type};
+
+       jobject file = env->CallObjectMethod(Get(), method, type.Get());
+       if (Java::DiscardException(env) || file == nullptr)
+               return nullptr;
+
+       return Java::File::ToAbsolutePath(env, file);
+}
+
+AllocatedPath
 Context::GetCacheDir(JNIEnv *env) const noexcept
 {
        assert(env != nullptr);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/android/Context.hxx 
new/mpd-0.22.11/src/android/Context.hxx
--- old/mpd-0.22.10/src/android/Context.hxx     2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/src/android/Context.hxx     2021-08-24 22:15:22.000000000 
+0200
@@ -30,10 +30,14 @@
        Context(JNIEnv *env, jobject obj) noexcept
                :Java::GlobalObject(env, obj) {}
 
-       gcc_pure
+       [[gnu::pure]]
+       AllocatedPath GetExternalFilesDir(JNIEnv *env,
+                                         const char *type) noexcept;
+
+       [[gnu::pure]]
        AllocatedPath GetCacheDir(JNIEnv *env) const noexcept;
 
-       gcc_pure
+       [[gnu::pure]]
        AudioManager *GetAudioManager(JNIEnv *env) noexcept;
 };
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/android/Environment.hxx 
new/mpd-0.22.11/src/android/Environment.hxx
--- old/mpd-0.22.10/src/android/Environment.hxx 2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/src/android/Environment.hxx 2021-08-24 22:15:22.000000000 
+0200
@@ -33,10 +33,10 @@
        /**
         * Determine the mount point of the external SD card.
         */
-       gcc_pure
+       [[gnu::pure]]
        AllocatedPath getExternalStorageDirectory() noexcept;
 
-       gcc_pure
+       [[gnu::pure]]
        AllocatedPath getExternalStoragePublicDirectory(const char *type) 
noexcept;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/command/FileCommands.cxx 
new/mpd-0.22.11/src/command/FileCommands.cxx
--- old/mpd-0.22.10/src/command/FileCommands.cxx        2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/command/FileCommands.cxx        2021-08-24 
22:15:22.000000000 +0200
@@ -267,6 +267,9 @@
 
        AtScopeExit(db, song) { db->ReturnSong(song); };
 
+       if (song->real_uri == nullptr)
+               return directory_uri;
+
        const char *real_uri = song->real_uri;
 
        /* this is a simplification which is just enough for CUE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/filter/plugins/FfmpegFilter.cxx 
new/mpd-0.22.11/src/filter/plugins/FfmpegFilter.cxx
--- old/mpd-0.22.10/src/filter/plugins/FfmpegFilter.cxx 2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/filter/plugins/FfmpegFilter.cxx 2021-08-24 
22:15:22.000000000 +0200
@@ -32,12 +32,12 @@
 FfmpegFilter::FfmpegFilter(const AudioFormat &in_audio_format,
                           const AudioFormat &_out_audio_format,
                           Ffmpeg::FilterGraph &&_graph,
-                          Ffmpeg::FilterContext &&_buffer_src,
-                          Ffmpeg::FilterContext &&_buffer_sink) noexcept
+                          AVFilterContext &_buffer_src,
+                          AVFilterContext &_buffer_sink) noexcept
        :Filter(_out_audio_format),
         graph(std::move(_graph)),
-        buffer_src(std::move(_buffer_src)),
-        buffer_sink(std::move(_buffer_sink)),
+        buffer_src(_buffer_src),
+        buffer_sink(_buffer_sink),
         in_format(Ffmpeg::ToFfmpegSampleFormat(in_audio_format.format)),
         in_sample_rate(in_audio_format.sample_rate),
         in_channels(in_audio_format.channels),
@@ -61,7 +61,7 @@
 
        memcpy(frame.GetData(0), src.data, src.size);
 
-       int err = av_buffersrc_add_frame(buffer_src.get(), frame.get());
+       int err = av_buffersrc_add_frame(&buffer_src, frame.get());
        if (err < 0)
                throw MakeFfmpegError(err, "av_buffersrc_write_frame() failed");
 
@@ -69,7 +69,7 @@
 
        frame.Unref();
 
-       err = av_buffersink_get_frame(buffer_sink.get(), frame.get());
+       err = av_buffersink_get_frame(&buffer_sink, frame.get());
        if (err < 0) {
                if (err == AVERROR(EAGAIN) || err == AVERROR_EOF)
                        return nullptr;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/filter/plugins/FfmpegFilter.hxx 
new/mpd-0.22.11/src/filter/plugins/FfmpegFilter.hxx
--- old/mpd-0.22.10/src/filter/plugins/FfmpegFilter.hxx 2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/filter/plugins/FfmpegFilter.hxx 2021-08-24 
22:15:22.000000000 +0200
@@ -30,7 +30,7 @@
  */
 class FfmpegFilter final : public Filter {
        Ffmpeg::FilterGraph graph;
-       Ffmpeg::FilterContext buffer_src, buffer_sink;
+       AVFilterContext &buffer_src, &buffer_sink;
        Ffmpeg::Frame frame;
 
        FfmpegBuffer interleave_buffer;
@@ -51,8 +51,8 @@
        FfmpegFilter(const AudioFormat &in_audio_format,
                     const AudioFormat &_out_audio_format,
                     Ffmpeg::FilterGraph &&_graph,
-                    Ffmpeg::FilterContext &&_buffer_src,
-                    Ffmpeg::FilterContext &&_buffer_sink) noexcept;
+                    AVFilterContext &_buffer_src,
+                    AVFilterContext &_buffer_sink) noexcept;
 
        /* virtual methods from class Filter */
        ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/mpd-0.22.10/src/filter/plugins/FfmpegFilterPlugin.cxx 
new/mpd-0.22.11/src/filter/plugins/FfmpegFilterPlugin.cxx
--- old/mpd-0.22.10/src/filter/plugins/FfmpegFilterPlugin.cxx   2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/filter/plugins/FfmpegFilterPlugin.cxx   2021-08-24 
22:15:22.000000000 +0200
@@ -37,39 +37,79 @@
        std::unique_ptr<Filter> Open(AudioFormat &af) override;
 };
 
+/**
+ * Fallback for PreparedFfmpegFilter::Open() just in case the filter's
+ * native output format could not be determined.
+ *
+ * TODO: improve the MPD filter API to allow returning the output
+ * format later, and eliminate this kludge
+ */
+static auto
+OpenWithAformat(const char *graph_string, AudioFormat &in_audio_format)
+{
+       Ffmpeg::FilterGraph graph;
+
+       auto &buffer_src =
+               Ffmpeg::MakeAudioBufferSource(in_audio_format, *graph);
+
+       auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph);
+
+       AudioFormat out_audio_format = in_audio_format;
+       auto &aformat = Ffmpeg::MakeAformat(out_audio_format, *graph);
+
+       int error = avfilter_link(&aformat, 0, &buffer_sink, 0);
+       if (error < 0)
+               throw MakeFfmpegError(error, "avfilter_link() failed");
+
+       graph.ParseSingleInOut(graph_string, aformat, buffer_src);
+       graph.CheckAndConfigure();
+
+       return std::make_unique<FfmpegFilter>(in_audio_format,
+                                             out_audio_format,
+                                             std::move(graph),
+                                             buffer_src,
+                                             buffer_sink);
+}
+
 std::unique_ptr<Filter>
 PreparedFfmpegFilter::Open(AudioFormat &in_audio_format)
 {
        Ffmpeg::FilterGraph graph;
 
-       auto buffer_src =
-               Ffmpeg::FilterContext::MakeAudioBufferSource(in_audio_format,
-                                                            *graph);
-
-       auto buffer_sink = Ffmpeg::FilterContext::MakeAudioBufferSink(*graph);
-
-       Ffmpeg::FilterInOut io_sink("out", *buffer_sink);
-       Ffmpeg::FilterInOut io_src("in", *buffer_src);
-       auto io = graph.Parse(graph_string, std::move(io_sink),
-                             std::move(io_src));
+       auto &buffer_src =
+               Ffmpeg::MakeAudioBufferSource(in_audio_format, *graph);
 
-       if (io.first.get() != nullptr)
-               throw std::runtime_error("FFmpeg filter has an open input");
+       auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph);
 
-       if (io.second.get() != nullptr)
-               throw std::runtime_error("FFmpeg filter has an open output");
+       /* if the filter's output format is not supported by MPD, this
+          "aformat" filter is inserted at the end and takes care for
+          the required conversion */
+       auto &aformat = Ffmpeg::MakeAutoAformat(*graph);
 
+       int error = avfilter_link(&aformat, 0, &buffer_sink, 0);
+       if (error < 0)
+               throw MakeFfmpegError(error, "avfilter_link() failed");
+
+       graph.ParseSingleInOut(graph_string, aformat, buffer_src);
        graph.CheckAndConfigure();
 
        const auto out_audio_format =
-               Ffmpeg::DetectFilterOutputFormat(in_audio_format, *buffer_src,
-                                                *buffer_sink);
+               Ffmpeg::DetectFilterOutputFormat(in_audio_format, buffer_src,
+                                                buffer_sink);
+
+       if (!out_audio_format.IsDefined())
+               /* the filter's native output format could not be
+                  determined yet, but we need to know it now; as a
+                  workaround for this MPD API deficiency, try again
+                  with an "aformat" filter which forces a specific
+                  output format */
+               return OpenWithAformat(graph_string, in_audio_format);
 
        return std::make_unique<FfmpegFilter>(in_audio_format,
                                              out_audio_format,
                                              std::move(graph),
-                                             std::move(buffer_src),
-                                             std::move(buffer_sink));
+                                             buffer_src,
+                                             buffer_sink);
 }
 
 static std::unique_ptr<PreparedFilter>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/filter/plugins/HdcdFilterPlugin.cxx 
new/mpd-0.22.11/src/filter/plugins/HdcdFilterPlugin.cxx
--- old/mpd-0.22.10/src/filter/plugins/HdcdFilterPlugin.cxx     2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/filter/plugins/HdcdFilterPlugin.cxx     2021-08-24 
22:15:22.000000000 +0200
@@ -42,24 +42,13 @@
 {
        Ffmpeg::FilterGraph graph;
 
-       auto buffer_src =
-               Ffmpeg::FilterContext::MakeAudioBufferSource(in_audio_format,
-                                                            *graph);
+       auto &buffer_src =
+               Ffmpeg::MakeAudioBufferSource(in_audio_format,
+                                             *graph);
 
-       auto buffer_sink = Ffmpeg::FilterContext::MakeAudioBufferSink(*graph);
-
-       Ffmpeg::FilterInOut io_sink("out", *buffer_sink);
-       Ffmpeg::FilterInOut io_src("in", *buffer_src);
-
-       auto io = graph.Parse(hdcd_graph, std::move(io_sink),
-                             std::move(io_src));
-
-       if (io.first.get() != nullptr)
-               throw std::runtime_error("FFmpeg filter has an open input");
-
-       if (io.second.get() != nullptr)
-               throw std::runtime_error("FFmpeg filter has an open output");
+       auto &buffer_sink = Ffmpeg::MakeAudioBufferSink(*graph);
 
+       graph.ParseSingleInOut(hdcd_graph, buffer_sink, buffer_src);
        graph.CheckAndConfigure();
 
        auto out_audio_format = in_audio_format;
@@ -69,8 +58,8 @@
        return std::make_unique<FfmpegFilter>(in_audio_format,
                                              out_audio_format,
                                              std::move(graph),
-                                             std::move(buffer_src),
-                                             std::move(buffer_sink));
+                                             buffer_src,
+                                             buffer_sink);
 }
 
 class PreparedHdcdFilter final : public PreparedFilter {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/lib/ffmpeg/ChannelLayout.hxx 
new/mpd-0.22.11/src/lib/ffmpeg/ChannelLayout.hxx
--- old/mpd-0.22.10/src/lib/ffmpeg/ChannelLayout.hxx    1970-01-01 
01:00:00.000000000 +0100
+++ new/mpd-0.22.11/src/lib/ffmpeg/ChannelLayout.hxx    2021-08-24 
22:15:22.000000000 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2003-2021 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_CHANNEL_LAYOUT_HXX
+#define MPD_FFMPEG_CHANNEL_LAYOUT_HXX
+
+extern "C" {
+#include <libavutil/channel_layout.h>
+}
+
+/**
+ * Convert a MPD channel count to a libavutil channel_layout bit mask.
+ */
+static constexpr uint64_t
+ToFfmpegChannelLayout(unsigned channels) noexcept
+{
+       switch (channels) {
+       case 1:
+               return AV_CH_LAYOUT_MONO;
+
+       case 2:
+               return AV_CH_LAYOUT_STEREO;
+
+       case 3:
+               return AV_CH_LAYOUT_SURROUND;
+
+       case 4:
+               // TODO is this AV_CH_LAYOUT_2_2?
+               return AV_CH_LAYOUT_QUAD;
+
+       case 5:
+               // TODO is this AV_CH_LAYOUT_5POINT0_BACK?
+               return AV_CH_LAYOUT_5POINT0;
+
+       case 6:
+               return AV_CH_LAYOUT_5POINT1;
+
+       case 7:
+               return AV_CH_LAYOUT_6POINT1;
+
+       case 8:
+               return AV_CH_LAYOUT_7POINT1;
+
+       default:
+               /* unreachable */
+               return 0;
+       }
+}
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/lib/ffmpeg/DetectFilterFormat.cxx 
new/mpd-0.22.11/src/lib/ffmpeg/DetectFilterFormat.cxx
--- old/mpd-0.22.10/src/lib/ffmpeg/DetectFilterFormat.cxx       2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/lib/ffmpeg/DetectFilterFormat.cxx       2021-08-24 
22:15:22.000000000 +0200
@@ -62,8 +62,14 @@
        frame.Unref();
 
        err = av_buffersink_get_frame(&buffer_sink, frame.get());
-       if (err < 0)
+       if (err < 0) {
+               if (err == AVERROR(EAGAIN))
+                       /* one sample was not enough input data for
+                          the given filter graph */
+                       return AudioFormat::Undefined();
+
                throw MakeFfmpegError(err, "av_buffersink_get_frame() failed");
+       }
 
        const SampleFormat sample_format = 
FromFfmpegSampleFormat(AVSampleFormat(frame->format));
        if (sample_format == SampleFormat::UNDEFINED)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/lib/ffmpeg/DetectFilterFormat.hxx 
new/mpd-0.22.11/src/lib/ffmpeg/DetectFilterFormat.hxx
--- old/mpd-0.22.10/src/lib/ffmpeg/DetectFilterFormat.hxx       2021-08-06 
18:16:59.000000000 +0200
+++ new/mpd-0.22.11/src/lib/ffmpeg/DetectFilterFormat.hxx       2021-08-24 
22:15:22.000000000 +0200
@@ -35,6 +35,9 @@
  * between.
  *
  * This function can throw if the FFmpeg filter fails.
+ *
+ * @return the output format or AudioFormat::Undefined() if it was not
+ * possible to determine the format
  */
 AudioFormat
 DetectFilterOutputFormat(const AudioFormat &in_audio_format,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/lib/ffmpeg/Filter.cxx 
new/mpd-0.22.11/src/lib/ffmpeg/Filter.cxx
--- old/mpd-0.22.10/src/lib/ffmpeg/Filter.cxx   2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/src/lib/ffmpeg/Filter.cxx   2021-08-24 22:15:22.000000000 
+0200
@@ -18,10 +18,13 @@
  */
 
 #include "Filter.hxx"
+#include "ChannelLayout.hxx"
 #include "SampleFormat.hxx"
 #include "pcm/AudioFormat.hxx"
 #include "util/RuntimeError.hxx"
 
+#include <cinttypes>
+
 #include <stdio.h>
 
 namespace Ffmpeg {
@@ -36,9 +39,32 @@
        return *filter;
 }
 
-FilterContext
-FilterContext::MakeAudioBufferSource(AudioFormat &audio_format,
-                                    AVFilterGraph &graph_ctx)
+static AVFilterContext &
+CreateFilter(const AVFilter &filt,
+            const char *name, const char *args, void *opaque,
+            AVFilterGraph &graph_ctx)
+{
+       AVFilterContext *context = nullptr;
+       int err = avfilter_graph_create_filter(&context, &filt,
+                                              name, args, opaque,
+                                              &graph_ctx);
+       if (err < 0)
+               throw MakeFfmpegError(err, "avfilter_graph_create_filter() 
failed");
+
+       return *context;
+}
+
+static AVFilterContext &
+CreateFilter(const AVFilter &filt,
+            const char *name,
+            AVFilterGraph &graph_ctx)
+{
+       return CreateFilter(filt, name, nullptr, nullptr, graph_ctx);
+}
+
+AVFilterContext &
+MakeAudioBufferSource(AudioFormat &audio_format,
+                     AVFilterGraph &graph_ctx)
 {
        AVSampleFormat src_format = ToFfmpegSampleFormat(audio_format.format);
        if (src_format == AV_SAMPLE_FMT_NONE) {
@@ -57,19 +83,72 @@
 
        char abuffer_args[256];
        sprintf(abuffer_args,
-               "sample_rate=%u:sample_fmt=%s:channels=%u:time_base=1/%u",
+               "sample_rate=%u:sample_fmt=%s:channel_layout=0x%" PRIx64 
":time_base=1/%u",
                audio_format.sample_rate,
                av_get_sample_fmt_name(src_format),
-               audio_format.channels,
+               ToFfmpegChannelLayout(audio_format.channels),
                audio_format.sample_rate);
 
-       return {RequireFilterByName("abuffer"), "abuffer", abuffer_args, 
nullptr, graph_ctx};
+       return CreateFilter(RequireFilterByName("abuffer"), "abuffer",
+                           abuffer_args, nullptr, graph_ctx);
+}
+
+AVFilterContext &
+MakeAudioBufferSink(AVFilterGraph &graph_ctx)
+{
+       return CreateFilter(RequireFilterByName("abuffersink"), "abuffersink",
+                           graph_ctx);
+}
+
+AVFilterContext &
+MakeAformat(AudioFormat &audio_format,
+           AVFilterGraph &graph_ctx)
+{
+       AVSampleFormat dest_format = ToFfmpegSampleFormat(audio_format.format);
+       if (dest_format == AV_SAMPLE_FMT_NONE) {
+               switch (audio_format.format) {
+               case SampleFormat::S24_P32:
+                       audio_format.format = SampleFormat::S32;
+                       dest_format = AV_SAMPLE_FMT_S32;
+                       break;
+
+               default:
+                       audio_format.format = SampleFormat::S16;
+                       dest_format = AV_SAMPLE_FMT_S16;
+                       break;
+               }
+       }
+
+       char args[256];
+       sprintf(args,
+               "sample_rates=%u:sample_fmts=%s:channel_layouts=0x%" PRIx64,
+               audio_format.sample_rate,
+               av_get_sample_fmt_name(dest_format),
+               ToFfmpegChannelLayout(audio_format.channels));
+
+       return CreateFilter(RequireFilterByName("aformat"), "aformat",
+                           args, nullptr, graph_ctx);
+}
+
+AVFilterContext &
+MakeAutoAformat(AVFilterGraph &graph_ctx)
+{
+       return CreateFilter(RequireFilterByName("aformat"), "aformat",
+                           "sample_fmts=flt|s32|s16",
+                           nullptr, graph_ctx);
 }
 
-FilterContext
-FilterContext::MakeAudioBufferSink(AVFilterGraph &graph_ctx)
+void
+FilterGraph::ParseSingleInOut(const char *filters, AVFilterContext &in,
+                             AVFilterContext &out)
 {
-       return {RequireFilterByName("abuffersink"), "abuffersink", graph_ctx};
+       auto [inputs, outputs] = Parse(filters, {"out", in}, {"in", out});
+
+       if (inputs.get() != nullptr)
+               throw std::runtime_error("FFmpeg filter has an open input");
+
+       if (outputs.get() != nullptr)
+               throw std::runtime_error("FFmpeg filter has an open output");
 }
 
 } // namespace Ffmpeg
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.22.10/src/lib/ffmpeg/Filter.hxx 
new/mpd-0.22.11/src/lib/ffmpeg/Filter.hxx
--- old/mpd-0.22.10/src/lib/ffmpeg/Filter.hxx   2021-08-06 18:16:59.000000000 
+0200
+++ new/mpd-0.22.11/src/lib/ffmpeg/Filter.hxx   2021-08-24 22:15:22.000000000 
+0200
@@ -77,63 +77,38 @@
        }
 };
 
-class FilterContext {
-       AVFilterContext *context = nullptr;
-
-public:
-       FilterContext() = default;
-
-       FilterContext(const AVFilter &filt,
-                     const char *name, const char *args, void *opaque,
-                     AVFilterGraph &graph_ctx) {
-               int err = avfilter_graph_create_filter(&context, &filt,
-                                                      name, args, opaque,
-                                                      &graph_ctx);
-               if (err < 0)
-                       throw MakeFfmpegError(err, 
"avfilter_graph_create_filter() failed");
-       }
-
-       FilterContext(const AVFilter &filt,
-                     const char *name,
-                     AVFilterGraph &graph_ctx)
-               :FilterContext(filt, name, nullptr, nullptr, graph_ctx) {}
-
-       FilterContext(FilterContext &&src) noexcept
-               :context(std::exchange(src.context, nullptr)) {}
-
-       ~FilterContext() noexcept {
-               if (context != nullptr)
-                       avfilter_free(context);
-       }
-
-       FilterContext &operator=(FilterContext &&src) noexcept {
-               using std::swap;
-               swap(context, src.context);
-               return *this;
-       }
-
-       /**
-        * Create an "abuffer" filter.
-        *
-        * @param the input audio format; may be modified by the
-        * function to ask the caller to do format conversion
-        */
-       static FilterContext MakeAudioBufferSource(AudioFormat &audio_format,
-                                                  AVFilterGraph &graph_ctx);
-
-       /**
-        * Create an "abuffersink" filter.
-        */
-       static FilterContext MakeAudioBufferSink(AVFilterGraph &graph_ctx);
-
-       auto &operator*() noexcept {
-               return *context;
-       }
-
-       auto *get() noexcept {
-               return context;
-       }
-};
+/**
+ * Create an "abuffer" filter.
+ *
+ * @param the input audio format; may be modified by the
+ * function to ask the caller to do format conversion
+ */
+AVFilterContext &
+MakeAudioBufferSource(AudioFormat &audio_format,
+                     AVFilterGraph &graph_ctx);
+
+/**
+ * Create an "abuffersink" filter.
+ */
+AVFilterContext &
+MakeAudioBufferSink(AVFilterGraph &graph_ctx);
+
+/**
+ * Create an "aformat" filter.
+ *
+ * @param the output audio format; may be modified by the function if
+ * the given format is not supported by libavfilter
+ */
+AVFilterContext &
+MakeAformat(AudioFormat &audio_format,
+           AVFilterGraph &graph_ctx);
+
+/**
+ * Create an "aformat" filter which automatically converts the output
+ * to a format supported by MPD.
+ */
+AVFilterContext &
+MakeAutoAformat(AVFilterGraph &graph_ctx);
 
 class FilterGraph {
        AVFilterGraph *graph = nullptr;
@@ -180,6 +155,9 @@
                return std::make_pair(std::move(inputs), std::move(outputs));
        }
 
+       void ParseSingleInOut(const char *filters, AVFilterContext &in,
+                             AVFilterContext &out);
+
        std::pair<FilterInOut, FilterInOut> Parse(const char *filters) {
                AVFilterInOut *inputs, *outputs;
                int err = avfilter_graph_parse2(graph, filters,

Reply via email to