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

avcodec/dca_core: export downmix matrix coefficients

$ ./ffmpeg -downmix stereo -i $fate-suite/dts/dcadec-suite/core_51_24_48_768_1.dtshd -y native.wav

Before:
$ ./ffmpeg -i $fate-suite/dts/dcadec-suite/core_51_24_48_768_1.dtshd -af aresample,aformat=channel_layouts=stereo -y swr.wav
[...]
[Parsed_aresample_0] [SWR] Using fltp internally between filters
[Parsed_aresample_0] [SWR] Matrix coefficients:
[Parsed_aresample_0] [SWR] FL: FL:0.414214 FR:0.000000 FC:0.292893 LFE:0.000000 SL:0.292893 SR:0.000000
[Parsed_aresample_0] [SWR] FR: FL:0.000000 FR:0.414214 FC:0.292893 LFE:0.000000 SL:0.000000 SR:0.292893
[Parsed_aresample_0] ch:6 chl:5.1(side) fmt:fltp r:48000Hz -> ch:2 chl:stereo fmt:s16 r:48000Hz
[...]

$ tests/tiny_psnr.exe native.wav swr.wav s16
stddev:18907.06 PSNR: 10.80 MAXDIFF:51590 bytes:     8192/     8192

After:
$ ./ffmpeg -i $fate-suite/dts/dcadec-suite/core_51_24_48_768_1.dtshd -af aresample,aformat=channel_layouts=stereo -y swr.wav
[...]
[Parsed_aresample_0] [SWR] Using fltp internally between filters
[Parsed_aresample_0] [SWR] Custom matrix coefficients:
[Parsed_aresample_0] [SWR] FL: FL:-0.100006 FR:0.000000 FC:0.000000 LFE:0.000000 SL:-0.707092 SR:0.000000
[Parsed_aresample_0] [SWR] FR: FL:0.000000 FR:-0.100006 FC:0.000000 LFE:0.000000 SL:0.000000 SR:-0.707092
[Parsed_aresample_0] ch:6 chl:5.1(side) fmt:fltp r:48000Hz -> ch:2 chl:stereo fmt:s16 r:48000Hz
[...]

$ tests/tiny_psnr.exe native.wav swr.wav
stddev:    0.02 PSNR:129.44 MAXDIFF:    1 bytes:     8192/     8192

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2026-06-04 14:51:57 -03:00
parent e1e6ebb065
commit 57708daf61
4 changed files with 87 additions and 11 deletions

View File

@@ -2384,6 +2384,17 @@ int ff_dca_core_filter_frame(DCACoreDecoder *s, AVFrame *frame)
else
avctx->bit_rate = 0;
if (s->request_mask == s->ch_mask && s->prim_dmix_embedded &&
!s->sumdiff_front && !s->sumdiff_surround &&
!(s->ext_audio_mask & (DCA_CSS_XXCH | DCA_CSS_XCH | DCA_EXSS_XXCH)) &&
s->audio_mode >= DCA_AMODE_2F2R && (s->prim_dmix_type == DCA_DMIX_TYPE_LoRo ||
s->prim_dmix_type == DCA_DMIX_TYPE_LtRt)) {
ret = ff_dca_export_downmix_matrix(avctx, frame, s->prim_dmix_type, s->ch_mask,
s->prim_dmix_coeff);
if (ret < 0)
return ret;
}
if (s->audio_mode == DCA_AMODE_STEREO_TOTAL || (s->request_mask != s->ch_mask &&
s->prim_dmix_type == DCA_DMIX_TYPE_LtRt))
matrix_encoding = AV_MATRIX_ENCODING_DOLBY;

View File

@@ -21,10 +21,12 @@
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/downmix_info.h"
#include "libavutil/thread.h"
#include "codec_internal.h"
#include "dcadec.h"
#include "dcadata.h"
#include "dcahuff.h"
#include "dca_syncwords.h"
#include "profiles.h"
@@ -32,18 +34,19 @@
#define MIN_PACKET_SIZE 16
#define MAX_PACKET_SIZE 0x104000
static const uint8_t dca2wav_norm[28] = {
2, 0, 1, 9, 10, 3, 8, 4, 5, 9, 10, 6, 7, 12,
13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5,
};
static const uint8_t dca2wav_wide[28] = {
2, 0, 1, 4, 5, 3, 8, 4, 5, 9, 10, 6, 7, 12,
13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5,
};
int ff_dca_set_channel_layout(AVCodecContext *avctx, int *ch_remap, int dca_mask)
{
static const uint8_t dca2wav_norm[28] = {
2, 0, 1, 9, 10, 3, 8, 4, 5, 9, 10, 6, 7, 12,
13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5,
};
static const uint8_t dca2wav_wide[28] = {
2, 0, 1, 4, 5, 3, 8, 4, 5, 9, 10, 6, 7, 12,
13, 14, 3, 6, 7, 11, 12, 14, 16, 15, 17, 8, 4, 5,
};
DCAContext *s = avctx->priv_data;
int dca_ch, wav_ch, nchannels = 0;
@@ -156,6 +159,62 @@ void ff_dca_downmix_to_stereo_float(AVFloatDSPContext *fdsp, float **samples,
}
}
int ff_dca_export_downmix_matrix(AVCodecContext *avctx, AVFrame *frame,
enum DCADownMixType downmix_type,
int output_mask, const int *coeff_l)
{
enum AVDownmixType dmix_type = (downmix_type == DCA_DMIX_TYPE_LoRo) ?
AV_DOWNMIX_TYPE_LORO : AV_DOWNMIX_TYPE_LTRT;
size_t size;
AVDownmixMatrix *dm = av_downmix_matrix_alloc(dmix_type, av_popcount(output_mask), &size);
const int *coeff_r = coeff_l + av_popcount(output_mask);
const double scale = 1.0 / (1 << 15);
AVDownmixCoeff *matrix_l, *matrix_r;
const uint8_t *dca2wav;
if (!dm)
return AVERROR(ENOMEM);
if (output_mask == DCA_SPEAKER_LAYOUT_7POINT0_WIDE ||
output_mask == DCA_SPEAKER_LAYOUT_7POINT1_WIDE)
dca2wav = dca2wav_wide;
else
dca2wav = dca2wav_norm;
matrix_l = av_downmix_matrix_coeff(dm, 0, 0);
matrix_r = av_downmix_matrix_coeff(dm, 1, 0);
for (int i = 0; i <= av_log2(output_mask); i++) {
if (!(output_mask & (1U << i)))
continue;
int idx = av_channel_layout_index_from_channel(&avctx->ch_layout, dca2wav[i]);
av_assert0(idx >= 0);
if (*coeff_l)
matrix_l[idx] = *coeff_l * scale;
if (*coeff_r)
matrix_r[idx] = *coeff_r * scale;
coeff_l++;
coeff_r++;
}
AVBufferRef *buf = av_buffer_create((uint8_t *)dm, size, NULL, NULL, 0);
if (!buf) {
av_free(dm);
return AVERROR(ENOMEM);
}
if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOWNMIX_MATRIX, buf)) {
av_buffer_unref(&buf);
return AVERROR(ENOMEM);
}
return 0;
}
static int dcadec_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{

View File

@@ -80,6 +80,9 @@ void ff_dca_downmix_to_stereo_fixed(DCADSPContext *dcadsp, int32_t **samples,
int *coeff_l, int nsamples, int ch_mask);
void ff_dca_downmix_to_stereo_float(AVFloatDSPContext *fdsp, float **samples,
int *coeff_l, int nsamples, int ch_mask);
int ff_dca_export_downmix_matrix(AVCodecContext *avctx, AVFrame *frame,
enum DCADownMixType downmix_type,
int output_mask, const int *coeff_l);
static inline int ff_dca_check_crc(AVCodecContext *avctx, GetBitContext *s,
int p1, int p2)

View File

@@ -39,10 +39,13 @@ $(foreach N,$(DCADEC_SUITE_LOSSLESS_24),$(eval $(call FATE_DCADEC_LOSSLESS_SUITE
$(foreach N,$(DCADEC_SUITE_LOSSY),$(eval $(call FATE_DCADEC_LOSSY_SUITE,$(N))))
# lossy downmix tests
FATE_DCADEC_LOSSY += fate-dca-core_51_24_48_768_1-dmix_2
FATE_DCADEC_LOSSY += fate-dca-core_51_24_48_768_1-dmix_2 fate-dca-core_51_24_48_768_1-dmix_2_matrix
fate-dca-core_51_24_48_768_1-dmix_2: CMD = ffmpeg -downmix stereo -flags2 skip_manual -i $(TARGET_SAMPLES)/dts/dcadec-suite/core_51_24_48_768_1.dtshd -f f32le -af aresample -
fate-dca-core_51_24_48_768_1-dmix_2: REF = $(SAMPLES)/dts/dcadec-suite/core_51_24_48_768_1-dmix_2.f32
fate-dca-core_51_24_48_768_1-dmix_2_matrix: CMD = ffmpeg -flags2 skip_manual -i $(TARGET_SAMPLES)/dts/dcadec-suite/core_51_24_48_768_1.dtshd -f f32le -af aresample,aformat=channel_layouts=stereo -
fate-dca-core_51_24_48_768_1-dmix_2_matrix: REF = $(SAMPLES)/dts/dcadec-suite/core_51_24_48_768_1-dmix_2.f32
FATE_DCADEC_LOSSY += fate-dca-x96_xxch_71_24_96_3840-dmix_2
fate-dca-x96_xxch_71_24_96_3840-dmix_2: CMD = ffmpeg -downmix stereo -flags2 skip_manual -i $(TARGET_SAMPLES)/dts/dcadec-suite/x96_xxch_71_24_96_3840.dtshd -f f32le -af aresample -
# intentionally uses the dmix_6 reference because the sample does not contain stereo downmix coefficients