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

Git pushed a commit to branch master
in repository ffmpeg.

commit b130b306f4d07acd5efabe9a9d92f6b471df019e
Author:     Kacper Michajłow <[email protected]>
AuthorDate: Tue Aug 11 12:14:55 2026 +0200
Commit:     Kacper Michajłow <[email protected]>
CommitDate: Sun Sep 6 00:48:25 2026 +0200

    avcodec/wavpack: use libswresample for the PCM output
    
    Unpack DSD frames into an interleaved scratch buffer and convert to
    the default AV_SAMPLE_FMT_FLTP output with libswresample instead of
    the in-place local dsd2pcm conversion.
    
    The SwrContext carries the DSD to PCM filter state across frames and
    replaces the DSDContext array as the RefStruct-shared state for frame
    threading.
    
    If libswresample is disabled, the PCM output is not offered and the
    decoder outputs only AV_SAMPLE_FMT_DSD. The per-channel slice
    threading of the float conversion is gone, the conversion now runs in
    a single swr_convert() call.
    
    Signed-off-by: Kacper Michajłow <[email protected]>
---
 libavcodec/wavpack.c   | 165 +++++++++++++++++++++++++++++++------------------
 tests/fate/wavpack.mak |   2 +-
 2 files changed, 107 insertions(+), 60 deletions(-)

diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 6435291cc7..d6864e11d4 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -20,6 +20,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "config.h"
+
 #include "libavutil/channel_layout.h"
 #include "libavutil/mem.h"
 
@@ -35,6 +37,10 @@
 #include "wavpack.h"
 #include "dsd.h"
 
+#if CONFIG_SWRESAMPLE
+#include "libswresample/swresample.h"
+#endif
+
 /**
  * @file
  * WavPack lossless audio decoder
@@ -109,12 +115,25 @@ typedef struct WavpackContext {
     Modulation modulation;
     int dsd_raw;            ///< output the raw DSD bitstream instead of PCM
 
-    DSDContext *dsdctx; ///< RefStruct reference
+#if CONFIG_SWRESAMPLE
+    struct WvDSDSwr *dsd_swr; ///< RefStruct reference, shared between threads
+    uint8_t *dsd_scratch;   ///< per-thread frame sized raw DSD buffer
+    unsigned dsd_scratch_size;
+#endif
     ThreadProgress *curr_progress, *prev_progress; ///< RefStruct references
     AVRefStructPool *progress_pool; ///< RefStruct reference
     int dsd_channels;
 } WavpackContext;
 
+#if CONFIG_SWRESAMPLE
+typedef struct WvDSDSwr {
+    struct SwrContext *swr;
+} WvDSDSwr;
+#define WV_DSD_SWR(wc) ((wc)->dsd_swr)
+#else
+#define WV_DSD_SWR(wc) (NULL)
+#endif
+
 #define LEVEL_DECAY(a)  (((a) + 0x80) >> 8)
 
 static av_always_inline unsigned get_tail(GetBitContext *gb, unsigned k)
@@ -997,33 +1016,47 @@ static av_cold int wv_alloc_frame_context(WavpackContext 
*c)
     return 0;
 }
 
-static int wv_dsd_reset(WavpackContext *s, int channels)
+#if CONFIG_SWRESAMPLE
+static void wv_dsd_swr_free(AVRefStructOpaque opaque, void *obj)
 {
-    int i;
+    WvDSDSwr *h = obj;
+
+    swr_free(&h->swr);
+}
+#endif
+
+static int wv_dsd_reset(AVCodecContext *avctx, int channels)
+{
+    WavpackContext *s = avctx->priv_data;
 
     s->dsd_channels = 0;
-    av_refstruct_unref(&s->dsdctx);
+#if CONFIG_SWRESAMPLE
+    av_refstruct_unref(&s->dsd_swr);
+#endif
     av_refstruct_unref(&s->curr_progress);
     av_refstruct_unref(&s->prev_progress);
 
     if (!channels)
         return 0;
 
-    if (WV_MAX_CHANNELS > SIZE_MAX / sizeof(*s->dsdctx) &&
-        channels > SIZE_MAX / sizeof(*s->dsdctx))
-        return AVERROR(EINVAL);
-
-    s->dsdctx = av_refstruct_allocz(channels * sizeof(*s->dsdctx));
-    if (!s->dsdctx)
-        return AVERROR(ENOMEM);
-    s->dsd_channels = channels;
-
-    for (i = 0; i < channels; i++)
-        memset(s->dsdctx[i].buf, 0x69, sizeof(s->dsdctx[i].buf));
-
-    ff_init_dsd_data();
+#if CONFIG_SWRESAMPLE
+    {
+        s->dsd_swr = av_refstruct_alloc_ext(sizeof(*s->dsd_swr), 0, NULL,
+                                            wv_dsd_swr_free);
+        if (!s->dsd_swr)
+            return AVERROR(ENOMEM);
 
+        int ret = ff_dsd_to_pcm_init(avctx, &s->dsd_swr->swr);
+        if (ret < 0) {
+            av_refstruct_unref(&s->dsd_swr);
+            return ret;
+        }
+        s->dsd_channels = channels;
+    }
     return 0;
+#else
+    return AVERROR_BUG;
+#endif
 }
 
 #if HAVE_THREADS
@@ -1033,7 +1066,9 @@ static int update_thread_context(AVCodecContext *dst, 
const AVCodecContext *src)
     WavpackContext *fdst = dst->priv_data;
 
     av_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress);
-    av_refstruct_replace(&fdst->dsdctx, fsrc->dsdctx);
+#if CONFIG_SWRESAMPLE
+    av_refstruct_replace(&fdst->dsd_swr, fsrc->dsd_swr);
+#endif
     fdst->dsd_channels = fsrc->dsd_channels;
 
     return 0;
@@ -1066,7 +1101,10 @@ static av_cold int wavpack_decode_init(AVCodecContext 
*avctx)
 
     s->fdec_num = 0;
 
+    s->dsd_raw = 1;
+#if CONFIG_SWRESAMPLE
     s->dsd_raw = avctx->request_sample_fmt == AV_SAMPLE_FMT_DSD;
+#endif
 
 #if HAVE_THREADS
     if (ff_thread_sync_ref(avctx, offsetof(WavpackContext, progress_pool)) == 
FF_THREAD_IS_FIRST_THREAD) {
@@ -1093,7 +1131,10 @@ static av_cold int wavpack_decode_end(AVCodecContext 
*avctx)
     s->fdec_num = 0;
 
     av_refstruct_pool_uninit(&s->progress_pool);
-    wv_dsd_reset(s, 0);
+    wv_dsd_reset(avctx, 0);
+#if CONFIG_SWRESAMPLE
+    av_freep(&s->dsd_scratch);
+#endif
 
     return 0;
 }
@@ -1106,7 +1147,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
     GetByteContext gb;
     enum AVSampleFormat sample_fmt;
     void *samples_l = NULL, *samples_r = NULL;
-    ptrdiff_t stride = 4; // the in-place DSD to PCM conversion reads at this 
stride
+    ptrdiff_t stride = 0;
     int ret;
     int got_terms   = 0, got_weights = 0, got_samples = 0,
         got_entropy = 0, got_pcm     = 0, got_float   = 0, got_hybrid = 0;
@@ -1160,10 +1201,9 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
     s->joint          =   s->frame_flags & WV_JOINT_STEREO;
     s->hybrid         =   s->frame_flags & WV_HYBRID_MODE;
     s->hybrid_bitrate =   s->frame_flags & WV_HYBRID_BITRATE;
-    if (!(s->frame_flags & WV_DSD_DATA)) {
-        s->post_shift = bpp * 8 - orig_bpp + ((s->frame_flags >> 13) & 0x1f);
-        if (s->post_shift < 0 || s->post_shift > 31)
-            return AVERROR_INVALIDDATA;
+    s->post_shift     = bpp * 8 - orig_bpp + ((s->frame_flags >> 13) & 0x1f);
+    if (s->post_shift < 0 || s->post_shift > 31) {
+        return AVERROR_INVALIDDATA;
     }
     s->hybrid_maxclip =  ((1LL << (orig_bpp - 1)) - 1);
     s->hybrid_minclip = ((-1UL << (orig_bpp - 1)));
@@ -1543,22 +1583,28 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
         }
         av_assert1(new_ch_layout.nb_channels <= WV_MAX_CHANNELS);
 
+#if CONFIG_SWRESAMPLE
         /* clear DSD state if stream properties change */
-        if ((wc->dsdctx && !got_dsd) ||
-            !wc->dsd_raw &&
-            got_dsd && (new_ch_layout.nb_channels != wc->dsd_channels ||
-                        av_channel_layout_compare(&new_ch_layout, 
&avctx->ch_layout) ||
-                        new_samplerate != avctx->sample_rate)) {
-            ret = wv_dsd_reset(wc, got_dsd ? new_ch_layout.nb_channels : 0);
+        int reset_dsd = !wc->dsd_raw &&
+            ((wc->dsd_swr && !got_dsd) ||
+             got_dsd && (new_ch_layout.nb_channels != wc->dsd_channels ||
+                         av_channel_layout_compare(&new_ch_layout, 
&avctx->ch_layout) ||
+                         new_samplerate != avctx->sample_rate));
+#endif
+        av_channel_layout_copy(&avctx->ch_layout, &new_ch_layout);
+        avctx->sample_rate         = new_samplerate;
+        avctx->sample_fmt          = sample_fmt;
+        avctx->bits_per_raw_sample = orig_bpp;
+
+#if CONFIG_SWRESAMPLE
+        if (reset_dsd) {
+            ret = wv_dsd_reset(avctx, got_dsd ? new_ch_layout.nb_channels : 0);
             if (ret < 0) {
                 av_log(avctx, AV_LOG_ERROR, "Error reinitializing the DSD 
context\n");
                 return ret;
             }
         }
-        av_channel_layout_copy(&avctx->ch_layout, &new_ch_layout);
-        avctx->sample_rate         = new_samplerate;
-        avctx->sample_fmt          = sample_fmt;
-        avctx->bits_per_raw_sample = orig_bpp;
+#endif
 
         /* get output buffer */
         frame->nb_samples = s->samples;
@@ -1568,7 +1614,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
 
         av_assert1(!!wc->progress_pool == !!(avctx->active_thread_type & 
FF_THREAD_FRAME));
         if (wc->progress_pool) {
-            if (wc->dsdctx) {
+            if (WV_DSD_SWR(wc)) {
                 av_refstruct_unref(&wc->prev_progress);
                 wc->prev_progress = av_refstruct_pool_get(wc->progress_pool);
                 if (!wc->prev_progress)
@@ -1576,7 +1622,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
                 FFSWAP(ThreadProgress*, wc->prev_progress, wc->curr_progress);
                 *new_progress = 1;
             }
-            av_assert1(!!wc->dsdctx == !!wc->curr_progress);
+            av_assert1(!!WV_DSD_SWR(wc) == !!wc->curr_progress);
             ff_thread_finish_setup(avctx);
         }
     }
@@ -1586,9 +1632,18 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
         return ((avctx->err_recognition & AV_EF_EXPLODE) || !wc->ch_offset) ? 
AVERROR_INVALIDDATA : 0;
     }
 
-    if (got_dsd && wc->dsd_raw) {
-        // raw DSD output is interleaved
-        stride    = avctx->ch_layout.nb_channels;
+    if (got_dsd) {
+        // DSD output is interleaved
+        stride = avctx->ch_layout.nb_channels;
+#if CONFIG_SWRESAMPLE
+        if (wc->dsd_swr) {
+            av_fast_malloc(&wc->dsd_scratch, &wc->dsd_scratch_size,
+                           (size_t)s->samples * stride);
+            if (!wc->dsd_scratch)
+                return AVERROR(ENOMEM);
+            samples_l = wc->dsd_scratch + wc->ch_offset;
+        } else
+#endif
         samples_l = frame->data[0] + wc->ch_offset;
         if (s->stereo)
             samples_r = (uint8_t *)samples_l + 1;
@@ -1630,7 +1685,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
             return ret;
 
         if (s->stereo) {
-            if (got_dsd && wc->dsd_raw) {
+            if (got_dsd) {
                 for (int i = 0; i < s->samples; i++)
                     ((uint8_t *)samples_r)[i * stride] =
                         ((const uint8_t *)samples_l)[i * stride];
@@ -1644,21 +1699,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
AVFrame *frame, int block
 
 static av_cold void wavpack_decode_flush(AVCodecContext *avctx)
 {
-    WavpackContext *s = avctx->priv_data;
-
-    wv_dsd_reset(s, 0);
-}
-
-static int dsd_channel(AVCodecContext *avctx, void *frmptr, int jobnr, int 
threadnr)
-{
-    const WavpackContext *s  = avctx->priv_data;
-    AVFrame *frame = frmptr;
-
-    ff_dsd2pcm_translate(&s->dsdctx[jobnr], s->samples, 0,
-        (uint8_t *)frame->extended_data[jobnr], 4,
-        (float *)frame->extended_data[jobnr], 1);
-
-    return 0;
+    wv_dsd_reset(avctx, 0);
 }
 
 static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *frame,
@@ -1670,7 +1711,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
     int frame_size, ret, frame_flags;
     int block = 0, new_progress = 0;
 
-    av_assert1(!s->curr_progress || s->dsdctx);
+    av_assert1(!s->curr_progress || WV_DSD_SWR(s));
 
     if (avpkt->size <= WV_HEADER_SIZE)
         return AVERROR_INVALIDDATA;
@@ -1714,13 +1755,19 @@ static int wavpack_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
         goto error;
     }
 
-    if (s->dsdctx) {
+#if CONFIG_SWRESAMPLE
+    if (s->dsd_swr) {
         if (s->prev_progress)
             ff_thread_progress_await(s->prev_progress, INT_MAX);
-        avctx->execute2(avctx, dsd_channel, frame, NULL, 
avctx->ch_layout.nb_channels);
+        ret = swr_convert(s->dsd_swr->swr, frame->extended_data, s->samples,
+                          (const uint8_t *const []){ s->dsd_scratch },
+                          s->samples);
         if (s->curr_progress)
             ff_thread_progress_report(s->curr_progress, INT_MAX);
+        if (ret != s->samples)
+            return ret < 0 ? ret : AVERROR_BUG;
     }
+#endif
 
     *got_frame_ptr = 1;
 
@@ -1748,6 +1795,6 @@ const FFCodec ff_wavpack_decoder = {
     .flush          = wavpack_decode_flush,
     UPDATE_THREAD_CONTEXT(update_thread_context),
     .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
-                      AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_CHANNEL_CONF,
+                      AV_CODEC_CAP_CHANNEL_CONF,
     .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
 };
diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak
index d4eb345383..1a37fc5365 100644
--- a/tests/fate/wavpack.mak
+++ b/tests/fate/wavpack.mak
@@ -18,7 +18,7 @@ fate-wavpack-lossless-32bit: CMD = md5pipe -i 
$(TARGET_SAMPLES)/wavpack/lossless
 FATE_WAVPACK_F32 += fate-wavpack-lossless-float
 fate-wavpack-lossless-float: CMD = md5pipe -i 
$(TARGET_SAMPLES)/wavpack/lossless/32bit_float-partial.wv -f f32le -af aresample
 
-FATE_WAVPACK_F32 += fate-wavpack-lossless-dsd
+FATE_WAVPACK-$(call FILTERDEMDECENCMUX, ARESAMPLE, WV, WAVPACK, PCM_F32LE, 
PCM_F32LE, MD5_PROTOCOL SWRESAMPLE) += fate-wavpack-lossless-dsd
 fate-wavpack-lossless-dsd: CMD = md5pipe -i 
$(TARGET_SAMPLES)/wavpack/lossless/dsd.wv -f f32le -af aresample
 
 # lossy

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to