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]
