1
0
mirror of https://git.ffmpeg.org/ffmpeg.git synced 2026-10-24 02:09:03 +03:00

swresample: keep integer samples if channels are only copied

With a matrix, samples of more than 16 bits are mixed in floating
point, which takes the lowest bits of s32. A matrix that only copies
channels computes nothing, so select the internal format like without
a matrix. Layouts that differ in the order of their channels or in
unused ones get such a matrix.

The matrix is built before the format is selected for this. The limit
for its coefficients no longer looks at the selected format. For
mixing that is an integer format only if the output has one or if it
was set, which is what the limit looks at now.

s64 still goes through double, the matrix has no functions for it.

Bump the micro version, as this and the previous commits change which
custom layouts can be used.

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
This commit is contained in:
Kacper Michajłow
2026-09-27 16:05:52 +02:00
parent c7ad544c1f
commit 09f879b074
5 changed files with 66 additions and 18 deletions

View File

@@ -697,7 +697,8 @@ av_cold static int auto_matrix(SwrContext *s)
if (s->rematrix_maxval > 0) {
maxval = s->rematrix_maxval;
} else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT
|| av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) {
|| (s->user_int_sample_fmt != AV_SAMPLE_FMT_NONE &&
av_get_packed_sample_fmt(s->user_int_sample_fmt) < AV_SAMPLE_FMT_FLT)) {
maxval = 1.0;
} else
maxval = INT_MAX;
@@ -709,13 +710,12 @@ av_cold static int auto_matrix(SwrContext *s)
s->matrix[1] - s->matrix[0], s->matrix_encoding, s);
}
av_cold int swri_rematrix_init(SwrContext *s){
av_cold int swri_rematrix_build(SwrContext *s)
{
int i, j;
int nb_in = s->used_ch_layout.nb_channels;
int nb_out = s->out.ch_count;
s->mix_any_f = NULL;
if (!s->rematrix_custom) {
int r = auto_matrix(s);
if (r)
@@ -735,6 +735,34 @@ av_cold int swri_rematrix_init(SwrContext *s){
av_log(s, AV_LOG_DEBUG, "\n");
}
}
/* a channel that is one channel of the input, or silent, is not mixed */
for (i = 0; i < nb_out; i++) {
int sources = 0;
for (j = 0; j < nb_in; j++) {
if (s->matrix[i][j] == 0.0)
continue;
if (s->matrix[i][j] != 1.0 || sources++)
return 1;
}
}
return 0;
}
av_cold int swri_rematrix_init(SwrContext *s){
int i, j;
int nb_in = s->used_ch_layout.nb_channels;
int nb_out = s->out.ch_count;
s->mix_any_f = NULL;
/* a matrix that is applied was built by swri_rematrix_build() */
if (!s->rematrix) {
int r = auto_matrix(s);
if (r)
return r;
}
if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){
int maxsum = 0;
s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int));

View File

@@ -154,7 +154,7 @@ av_cold void swr_close(SwrContext *s){
}
av_cold int swr_init(struct SwrContext *s){
int ret;
int ret, mixing;
char l1[1024], l2[1024];
clear_context(s);
@@ -232,6 +232,24 @@ av_cold int swr_init(struct SwrContext *s){
s->rematrix_volume!=1.0 ||
s->rematrix_custom;
av_channel_layout_describe(&s->out_ch_layout, l2, sizeof(l2));
av_channel_layout_describe(&s->in_ch_layout, l1, sizeof(l1));
if (( s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC
|| s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) && s->used_ch_layout.nb_channels != s->out.ch_count && !s->rematrix_custom) {
av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s "
"but there is not enough information to do it\n", l1, l2);
return AVERROR(EINVAL);
}
/* a matrix that only copies channels leaves the samples as they are,
* so the format in between is selected like without a matrix */
mixing = 0;
if (s->rematrix) {
mixing = swri_rematrix_build(s);
if (mixing < 0)
return mixing;
}
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
@@ -247,13 +265,13 @@ av_cold int swr_init(struct SwrContext *s){
+av_get_bytes_per_sample(s->out_sample_fmt) <= 3 ) {
s->int_sample_fmt= AV_SAMPLE_FMT_S16P;
}else if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2
&& !s->rematrix
&& !mixing
&& s->out_sample_rate==s->in_sample_rate
&& !(s->flags & SWR_FLAG_RESAMPLE)){
s->int_sample_fmt= AV_SAMPLE_FMT_S16P;
}else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P
&& av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P
&& !s->rematrix
&& !mixing
&& s->out_sample_rate == s->in_sample_rate
&& !(s->flags & SWR_FLAG_RESAMPLE)
&& s->engine != SWR_ENGINE_SOXR){
@@ -328,22 +346,12 @@ av_cold int swr_init(struct SwrContext *s){
goto fail;
}
av_channel_layout_describe(&s->out_ch_layout, l2, sizeof(l2));
av_channel_layout_describe(&s->in_ch_layout, l1, sizeof(l1));
if (s->in_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC && s->used_ch_layout.nb_channels != s->in_ch_layout.nb_channels) {
av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_layout.nb_channels);
ret = AVERROR(EINVAL);
goto fail;
}
if (( s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC
|| s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) && s->used_ch_layout.nb_channels != s->out.ch_count && !s->rematrix_custom) {
av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s "
"but there is not enough information to do it\n", l1, l2);
ret = AVERROR(EINVAL);
goto fail;
}
av_assert0(s->used_ch_layout.nb_channels);
av_assert0(s->out.ch_count);
s->resample_first= RSC*s->out.ch_count/s->used_ch_layout.nb_channels - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0;

View File

@@ -207,6 +207,8 @@ void swri_noise_shaping_int32 (SwrContext *s, AudioData *dsts, const AudioData *
void swri_noise_shaping_float (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
void swri_noise_shaping_double(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
av_warn_unused_result
int swri_rematrix_build(SwrContext *s);
av_warn_unused_result
int swri_rematrix_init(SwrContext *s);
void swri_rematrix_free(SwrContext *s);

View File

@@ -31,7 +31,7 @@
#include "version_major.h"
#define LIBSWRESAMPLE_VERSION_MINOR 3
#define LIBSWRESAMPLE_VERSION_MICRO 100
#define LIBSWRESAMPLE_VERSION_MICRO 101
#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \
LIBSWRESAMPLE_VERSION_MINOR, \

View File

@@ -1106,6 +1106,16 @@ fate-swr-custom-rematrix: REF = 2a14a44deb4ae26e3b474ddbfbc048f8
FATE_SWR += $(FATE_SWR_CUSTOM_REMATRIX-yes)
FATE_SWR_S32_SRC = mod(n*$(1)\,4294967296)/2147483648-1
FATE_SWR_S32_7_1 = $(call FATE_SWR_S32_SRC,1103515245)|$(call FATE_SWR_S32_SRC,22695477)|$(call FATE_SWR_S32_SRC,214013)|$(call FATE_SWR_S32_SRC,1664525)|$(call FATE_SWR_S32_SRC,134775813)|$(call FATE_SWR_S32_SRC,69069)|$(call FATE_SWR_S32_SRC,1812433253)|$(call FATE_SWR_S32_SRC,2654435761)
FATE_SWR_CUSTOM_REORDER-$(call ENCMUX, PCM_S32LE, PCM_S32LE, AEVALSRC_FILTER ARESAMPLE_FILTER AFORMAT_FILTER FILE_PROTOCOL) += fate-swr-custom-reorder
fate-swr-custom-reorder: CMD = md5 -filter_complex "aevalsrc=$(FATE_SWR_S32_7_1):c=7.1:d=0.5,aresample,aformat=f=s32:cl=7.1,aresample,aformat=f=s32:cl=FR+FL+FC+LFE+SL+SR+BL+BR[OUT]" -map [OUT] -f s32le
fate-swr-custom-reorder: CMP = oneline
fate-swr-custom-reorder: REF = 3621f90f05eb313858791b3915b9ca18
FATE_SWR += $(FATE_SWR_CUSTOM_REORDER-yes)
FATE_SWR_22_2_LAYOUTS = 9.1.6 9.1.4 7.2.3 7.1.6 7.1.4 7.1.2 5.1.6 5.1.4 5.1.2 7.1 5.1 stereo mono
FATE_SWR_9_1_6_LAYOUTS = 9.1.4 7.2.3 7.1.6 7.1.4 7.1.2 5.1.6 5.1.4 5.1.2 7.1 5.1 stereo mono
FATE_SWR_9_1_4_LAYOUTS = 7.2.3 7.1.4 7.1.2 5.1.4 5.1.2 7.1 5.1 stereo mono