This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 72b81d5b64c13e36ea9a87f8e096616a20944098 Author: Kacper Michajłow <[email protected]> AuthorDate: Tue Aug 11 11:24:49 2026 +0200 Commit: Kacper Michajłow <[email protected]> CommitDate: Sun Sep 6 00:48:24 2026 +0200 swresample: support AV_SAMPLE_FMT_DSD input Convert DSD to PCM with the same 96-tap symmetric lowpass filter the libavcodec DSD decoders use. The implementation is copied from libavcodec/dsd.c, minus the LSBF table variants, since AV_SAMPLE_FMT_DSD is defined as MSBF. The libavcodec copy will be removed in future commits as decoders are transitioned to SWR. The conversion is stateful (per-channel filter history), so the audio conversion functions gain a per-channel state argument. DSD silence is the 0x69 bit pattern instead of the 0x80 used for PCM. Only a direct DSD to float conversion function is provided. For format pairs without a direct conversion function (e.g. DSD to s16 with equal rates), swr_init() now falls back from the full_convert shortcut to the generic two-stage path instead of failing, and reports unsupported conversions with a proper error message instead of ENOMEM. Signed-off-by: Kacper Michajłow <[email protected]> --- libswresample/Makefile | 3 +- libswresample/audioconvert.c | 18 +++++++++-- libswresample/audioconvert.h | 4 ++- libavcodec/dsd.c => libswresample/dsd2pcm.c | 46 +++++++++++++---------------- libavcodec/dsd.h => libswresample/dsd2pcm.h | 33 ++++++++++++--------- {libavcodec => libswresample}/reverse.c | 0 libswresample/swresample.c | 36 +++++++++++++++++----- libswresample/version.h | 2 +- tests/ref/fate/source | 1 + 9 files changed, 92 insertions(+), 51 deletions(-) diff --git a/libswresample/Makefile b/libswresample/Makefile index 8149de069f..f5125e29b1 100644 --- a/libswresample/Makefile +++ b/libswresample/Makefile @@ -7,6 +7,7 @@ HEADERS = swresample.h \ version_major.h \ OBJS = audioconvert.o \ + dsd2pcm.o \ dither.o \ options.o \ rematrix.o \ @@ -19,7 +20,7 @@ OBJS = audioconvert.o \ OBJS-$(CONFIG_LIBSOXR) += soxr_resample.o # Objects duplicated from other libraries for shared builds -SHLIBOBJS += log2_tab.o +SHLIBOBJS += log2_tab.o reverse.o # Windows resource file SHLIBOBJS-$(HAVE_GNU_WINDRES) += swresampleres.o diff --git a/libswresample/audioconvert.c b/libswresample/audioconvert.c index f8bac98ca5..2085385cce 100644 --- a/libswresample/audioconvert.c +++ b/libswresample/audioconvert.c @@ -36,7 +36,7 @@ //FIXME rounding ? #define CONV_FUNC(ofmt, otype, ifmt, expr)\ -static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ +static void CONV_FUNC_NAME(ofmt, ifmt)(DSDContext *st, uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ {\ uint8_t *end2 = end - 3*os;\ while(po < end2){\ @@ -87,6 +87,12 @@ CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(* CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double*)pi * (UINT64_C(1)<<63))) CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) +CONV_FUNC(AV_SAMPLE_FMT_DSD, uint8_t, AV_SAMPLE_FMT_DSD, *(const uint8_t*)pi) + +static void CONV_FUNC_NAME(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DSD)(DSDContext *st, uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end) +{ + swri_dsd2pcm_translate(st, (end - po) / os, pi, is, (float *)po, os / sizeof(float)); +} #define FMT_PAIR_FUNC(out, in) [(out) + AV_SAMPLE_FMT_NB*(in)] = CONV_FUNC_NAME(out, in) @@ -127,6 +133,8 @@ static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAM FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DSD), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DSD, AV_SAMPLE_FMT_DSD), }; static void cpy1(uint8_t **dst, const uint8_t **src, int len){ @@ -166,6 +174,12 @@ AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, ctx->ch_map = ch_map; if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence)); + if (in_fmt == AV_SAMPLE_FMT_DSD) { + swri_dsd2pcm_init(); + memset(ctx->silence, 0x69, sizeof(ctx->silence)); + for (int ch = 0; ch < FF_ARRAY_ELEMS(ctx->dsd_state); ch++) + memset(ctx->dsd_state[ch].buf, 0x69, sizeof(ctx->dsd_state[ch].buf)); + } if(out_fmt == in_fmt && !ch_map) { switch(av_get_bytes_per_sample(in_fmt)){ @@ -245,7 +259,7 @@ int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len if(!po) continue; end = po + os * len; - ctx->conv_f(po+off*os, pi+off*is, is, os, end); + ctx->conv_f(&ctx->dsd_state[ch], po+off*os, pi+off*is, is, os, end); } return 0; } diff --git a/libswresample/audioconvert.h b/libswresample/audioconvert.h index bb143a876d..0dd43866be 100644 --- a/libswresample/audioconvert.h +++ b/libswresample/audioconvert.h @@ -30,9 +30,10 @@ #include "swresample_internal.h" +#include "dsd2pcm.h" -typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); +typedef void (conv_func_type)(DSDContext *st, uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len); typedef struct AudioConvert { @@ -43,6 +44,7 @@ typedef struct AudioConvert { simd_func_type *simd_f; const int *ch_map; uint8_t silence[8]; ///< silence input sample + DSDContext dsd_state[SWR_CH_MAX]; ///< per-channel state for DSD input }AudioConvert; /** diff --git a/libavcodec/dsd.c b/libswresample/dsd2pcm.c similarity index 74% copy from libavcodec/dsd.c copy to libswresample/dsd2pcm.c index 1093c5e2dd..bfc99e942e 100644 --- a/libavcodec/dsd.c +++ b/libswresample/dsd2pcm.c @@ -1,5 +1,5 @@ /* - * Direct Stream Digital (DSD) decoder + * DSD to PCM conversion * based on BSD licensed dsd2pcm by Sebastian Gesemann * Copyright (c) 2009, 2011 Sebastian Gesemann. All rights reserved. * Copyright (c) 2014 Peter Ross @@ -25,9 +25,9 @@ #include "libavutil/attributes.h" #include "libavutil/reverse.h" #include "libavutil/thread.h" -#include "dsd.h" +#include "dsd2pcm.h" -#define CTABLES ((HTAPS + 7) / 8) /** number of "8 MACs" lookup tables */ +#define DSD_CTABLES ((DSD_HTAPS + 7) / 8) /** number of "8 MACs" lookup tables */ /* * Properties of this 96-tap lowpass filter when applied on a signal @@ -49,7 +49,7 @@ /** * The 2nd half (48 coeffs) of a 96-tap symmetric lowpass filter */ -static const double htaps[HTAPS] = { +static const double htaps[DSD_HTAPS] = { 0.09950731974056658, 0.09562845727714668, 0.08819647126516944, 0.07782552527068175, 0.06534876523171299, 0.05172629311427257, 0.0379429484910187, 0.02490921351762261, 0.0133774746265897, @@ -68,42 +68,38 @@ static const double htaps[HTAPS] = { 3.423230509967409e-07, 1.244182214744588e-07, 3.130441005359396e-08 }; -static double ctables_lsbf[CTABLES][256]; -static double ctables_msbf[CTABLES][256]; +static double ctables[DSD_CTABLES][256]; -static av_cold void dsd_ctables_tableinit(void) +static av_cold void dsd2pcm_ctables_tableinit(void) { int t, e, m, sign; - double acc[CTABLES]; + double acc[DSD_CTABLES]; for (e = 0; e < 256; ++e) { memset(acc, 0, sizeof(acc)); for (m = 0; m < 8; ++m) { sign = (((e >> (7 - m)) & 1) * 2 - 1); - for (t = 0; t < CTABLES; ++t) + for (t = 0; t < DSD_CTABLES; ++t) acc[t] += sign * htaps[t * 8 + m]; } - for (t = 0; t < CTABLES; ++t) { - ctables_msbf[CTABLES - 1 - t][e] = acc[t]; - ctables_lsbf[CTABLES - 1 - t][ff_reverse[e]] = acc[t]; - } + for (t = 0; t < DSD_CTABLES; ++t) + ctables[DSD_CTABLES - 1 - t][e] = acc[t]; } } -av_cold void ff_init_dsd_data(void) +av_cold void swri_dsd2pcm_init(void) { static AVOnce init_static_once = AV_ONCE_INIT; - ff_thread_once(&init_static_once, dsd_ctables_tableinit); + ff_thread_once(&init_static_once, dsd2pcm_ctables_tableinit); } -void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf, - const uint8_t *src, ptrdiff_t src_stride, - float *dst, ptrdiff_t dst_stride) +void swri_dsd2pcm_translate(DSDContext *s, size_t samples, + const uint8_t *src, ptrdiff_t src_stride, + float *dst, ptrdiff_t dst_stride) { - uint8_t buf[FIFOSIZE]; + uint8_t buf[DSD_FIFOSIZE]; unsigned pos, i; uint8_t* p; double sum; - const double (*const ctables)[256] = lsbf ? ctables_lsbf : ctables_msbf; pos = s->pos; @@ -113,20 +109,20 @@ void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf, buf[pos] = *src; src += src_stride; - p = buf + ((pos - CTABLES) & FIFOMASK); + p = buf + ((pos - DSD_CTABLES) & DSD_FIFOMASK); *p = ff_reverse[*p]; sum = 0.0; - for (i = 0; i < CTABLES; i++) { - uint8_t a = buf[(pos - i) & FIFOMASK]; - uint8_t b = buf[(pos - (CTABLES*2 - 1) + i) & FIFOMASK]; + for (i = 0; i < DSD_CTABLES; i++) { + uint8_t a = buf[(pos - i) & DSD_FIFOMASK]; + uint8_t b = buf[(pos - (DSD_CTABLES*2 - 1) + i) & DSD_FIFOMASK]; sum += ctables[i][a] + ctables[i][b]; } *dst = (float)sum; dst += dst_stride; - pos = (pos + 1) & FIFOMASK; + pos = (pos + 1) & DSD_FIFOMASK; } s->pos = pos; diff --git a/libavcodec/dsd.h b/libswresample/dsd2pcm.h similarity index 57% copy from libavcodec/dsd.h copy to libswresample/dsd2pcm.h index 74da74fccc..ca00dcee77 100644 --- a/libavcodec/dsd.h +++ b/libswresample/dsd2pcm.h @@ -1,5 +1,5 @@ /* - * Direct Stream Digital (DSD) decoder + * DSD to PCM conversion * based on BSD licensed dsd2pcm by Sebastian Gesemann * Copyright (c) 2009, 2011 Sebastian Gesemann. All rights reserved. * Copyright (c) 2014 Peter Ross @@ -21,31 +21,36 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_DSD_H -#define AVCODEC_DSD_H +#ifndef SWRESAMPLE_DSD2PCM_H +#define SWRESAMPLE_DSD2PCM_H #include <stddef.h> #include <stdint.h> -#define HTAPS 48 /** number of FIR constants */ -#define FIFOSIZE 16 /** must be a power of two */ -#define FIFOMASK (FIFOSIZE - 1) /** bit mask for FIFO offsets */ +#define DSD_HTAPS 48 /** number of FIR constants */ +#define DSD_FIFOSIZE 16 /** must be a power of two */ +#define DSD_FIFOMASK (DSD_FIFOSIZE - 1) /** bit mask for FIFO offsets */ -#if FIFOSIZE * 8 < HTAPS * 2 -#error "FIFOSIZE too small" +#if DSD_FIFOSIZE * 8 < DSD_HTAPS * 2 +#error "DSD_FIFOSIZE too small" #endif /** * Per-channel buffer */ typedef struct DSDContext { - uint8_t buf[FIFOSIZE]; + uint8_t buf[DSD_FIFOSIZE]; unsigned pos; } DSDContext; -void ff_init_dsd_data(void); +void swri_dsd2pcm_init(void); -void ff_dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf, - const uint8_t *src, ptrdiff_t src_stride, - float *dst, ptrdiff_t dst_stride); -#endif /* AVCODEC_DSD_H */ +/** + * Convert one channel of MSB-first DSD data (one byte = 8 samples) to + * float PCM at 1/8th of the DSD bit rate. Strides are in elements. + */ +void swri_dsd2pcm_translate(DSDContext *s, size_t samples, + const uint8_t *src, ptrdiff_t src_stride, + float *dst, ptrdiff_t dst_stride); + +#endif /* SWRESAMPLE_DSD2PCM_H */ diff --git a/libavcodec/reverse.c b/libswresample/reverse.c similarity index 100% copy from libavcodec/reverse.c copy to libswresample/reverse.c diff --git a/libswresample/swresample.c b/libswresample/swresample.c index d777efd802..3fa2f3bf6c 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -177,6 +177,14 @@ av_cold int swr_init(struct SwrContext *s){ return AVERROR(EINVAL); } + if (s->out_sample_fmt == AV_SAMPLE_FMT_DSD && + !(s->in_sample_fmt == AV_SAMPLE_FMT_DSD && + s->in_sample_rate == s->out_sample_rate && + !(s->flags & SWR_FLAG_RESAMPLE))) { + av_log(s, AV_LOG_ERROR, "Conversion to DSD is not supported\n"); + return AVERROR(EINVAL); + } + s->out.ch_count = s-> user_out_chlayout.nb_channels; s-> in.ch_count = s-> user_in_chlayout.nb_channels; @@ -225,8 +233,12 @@ av_cold int swr_init(struct SwrContext *s){ s->rematrix_custom; if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){ + // DSD to PCM conversion is done in floating point + if( s->in_sample_fmt == AV_SAMPLE_FMT_DSD + && s->out_sample_fmt != AV_SAMPLE_FMT_DSD) { + s->int_sample_fmt= AV_SAMPLE_FMT_FLTP; // 16bit or less to 16bit or less with the same sample rate - if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 + } else if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 && av_get_bytes_per_sample(s->out_sample_fmt) <= 2 && s->out_sample_rate==s->in_sample_rate) { s->int_sample_fmt= AV_SAMPLE_FMT_S16P; @@ -346,7 +358,10 @@ av_assert0(s->out.ch_count); if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){ s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, s-> in_sample_fmt, s-> in.ch_count, NULL, 0); - return 0; + // fall through to the generic path for conversions that have no + // direct implementation (e.g. DSD input to non-float output) + if (s->full_convert) + return 0; } s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, @@ -355,7 +370,10 @@ av_assert0(s->out.ch_count); s->int_sample_fmt, s->out.ch_count, NULL, 0); if (!s->in_convert || !s->out_convert) { - ret = AVERROR(ENOMEM); + av_log(s, AV_LOG_ERROR, "Cannot convert %s sample format to %s sample format\n", + av_get_sample_fmt_name(!s->in_convert ? s->in_sample_fmt : s->int_sample_fmt), + av_get_sample_fmt_name(!s->in_convert ? s->int_sample_fmt : s->out_sample_fmt)); + ret = AVERROR(EINVAL); goto fail; } @@ -865,10 +883,14 @@ int swr_inject_silence(struct SwrContext *s, int count){ if((ret=swri_realloc_audio(&s->silence, count))<0) return ret; - if(s->silence.planar) for(i=0; i<s->silence.ch_count; i++) { - memset(s->silence.ch[i], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps); - } else - memset(s->silence.ch[0], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps*s->silence.ch_count); + { + int fill = s->silence.fmt == AV_SAMPLE_FMT_DSD ? 0x69 : + s->silence.bps == 1 ? 0x80 : 0; + if(s->silence.planar) for(i=0; i<s->silence.ch_count; i++) { + memset(s->silence.ch[i], fill, count*s->silence.bps); + } else + memset(s->silence.ch[0], fill, count*s->silence.bps*s->silence.ch_count); + } reversefill_audiodata(&s->silence, tmp_arg); av_log(s, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", count); diff --git a/libswresample/version.h b/libswresample/version.h index 057ac4b19e..d1795b5545 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -30,7 +30,7 @@ #include "version_major.h" -#define LIBSWRESAMPLE_VERSION_MINOR 2 +#define LIBSWRESAMPLE_VERSION_MINOR 3 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ diff --git a/tests/ref/fate/source b/tests/ref/fate/source index d5eb31d887..693018fdbc 100644 --- a/tests/ref/fate/source +++ b/tests/ref/fate/source @@ -16,6 +16,7 @@ libavformat/log2_tab.c libavformat/rangecoder_dec.c libavformat/riscv/cpu_common.c libswresample/log2_tab.c +libswresample/reverse.c libswscale/aarch64/ops_entries.c libswscale/log2_tab.c libswscale/riscv/cpu_common.c -- 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]
