[FFmpeg-devel] [PATCH] ffprobe/eac3/mlp/dca: add detection of spatial audio extensions
Marth64
marth64 at proxyid.net
Thu Feb 9 06:41:00 EET 2023
Signed-off-by: Marth64 <marth64 at proxyid.net>
---
Adds detection of spatial/object-based audio extensions in E-AC-3,
TrueHD, and DCA XLL (DTS). This includes Atmos, DTS:X, and IMAX formats.
Please let me know what I could improve, I'm learning still.
Thank you.
doc/ffprobe.xsd | 1 +
fftools/ffprobe.c | 3 +++
libavcodec/ac3dec.c | 1 +
libavcodec/ac3dec.h | 1 +
libavcodec/avcodec.h | 6 ++++++
libavcodec/codec_par.c | 2 ++
libavcodec/codec_par.h | 6 ++++++
libavcodec/dca_syncwords.h | 3 +++
libavcodec/dca_xll.c | 14 ++++++++++++++
libavcodec/eac3dec.c | 11 ++++++++++-
libavcodec/mlpdec.c | 9 +++++++++
11 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
index 0920380108..a01a4359dc 100644
--- a/doc/ffprobe.xsd
+++ b/doc/ffprobe.xsd
@@ -247,6 +247,7 @@
<xsd:attribute name="channel_layout" type="xsd:string"/>
<xsd:attribute name="bits_per_sample" type="xsd:int"/>
<xsd:attribute name="initial_padding" type="xsd:int"/>
+ <xsd:attribute name="spatial_ext" type="xsd:boolean"/>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="r_frame_rate" type="xsd:string" use="required"/>
diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index dfa7ff1b24..7e81088c56 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -3071,6 +3071,9 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id));
print_int("initial_padding", par->initial_padding);
+ if (par->spatial_ext > 0) {
+ print_int("spatial_ext", par->spatial_ext);
+ }
break;
case AVMEDIA_TYPE_SUBTITLE:
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 0b120e6140..009acd9ff6 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -1714,6 +1714,7 @@ skip:
if (!err) {
avctx->sample_rate = s->sample_rate;
avctx->bit_rate = s->bit_rate + s->prev_bit_rate;
+ avctx->spatial_ext = s->eac3_extension_type_a == 1;
}
if (!avctx->sample_rate) {
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index 138b462abb..0829f4b40d 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -102,6 +102,7 @@ typedef struct AC3DecodeContext {
int eac3; ///< indicates if current frame is E-AC-3
int eac3_frame_dependent_found; ///< bitstream has E-AC-3 dependent frame(s)
int eac3_subsbtreamid_found; ///< bitstream has E-AC-3 additional substream(s)
+ int eac3_extension_type_a; ///< bitstream has E-AC-3 extension type A enabled frame(s)
int dolby_surround_mode; ///< dolby surround mode (dsurmod)
int dolby_surround_ex_mode; ///< dolby surround ex mode (dsurexmod)
int dolby_headphone_mode; ///< dolby headphone mode (dheadphonmod)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 755e543fac..8b54a99313 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2104,6 +2104,12 @@ typedef struct AVCodecContext {
* The decoder can then override during decoding as needed.
*/
AVChannelLayout ch_layout;
+
+ /**
+ * Audio only. Whether or not a spatial audio extension is
+ * detected in the stream (object-based surround).
+ */
+ int spatial_ext;
} AVCodecContext;
/**
diff --git a/libavcodec/codec_par.c b/libavcodec/codec_par.c
index abda649aa8..02f6da5059 100644
--- a/libavcodec/codec_par.c
+++ b/libavcodec/codec_par.c
@@ -161,6 +161,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
par->initial_padding = codec->initial_padding;
par->trailing_padding = codec->trailing_padding;
par->seek_preroll = codec->seek_preroll;
+ par->spatial_ext = codec->spatial_ext;
break;
case AVMEDIA_TYPE_SUBTITLE:
par->width = codec->width;
@@ -243,6 +244,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
codec->initial_padding = par->initial_padding;
codec->trailing_padding = par->trailing_padding;
codec->seek_preroll = par->seek_preroll;
+ codec->spatial_ext = par->spatial_ext;
break;
case AVMEDIA_TYPE_SUBTITLE:
codec->width = par->width;
diff --git a/libavcodec/codec_par.h b/libavcodec/codec_par.h
index f51d27c590..287b138b6b 100644
--- a/libavcodec/codec_par.h
+++ b/libavcodec/codec_par.h
@@ -211,6 +211,12 @@ typedef struct AVCodecParameters {
* Audio only. The channel layout and number of channels.
*/
AVChannelLayout ch_layout;
+
+ /**
+ * Audio only. Whether or not a spatial audio extension is
+ * detected in the stream (object-based surround).
+ */
+ int spatial_ext;
} AVCodecParameters;
/**
diff --git a/libavcodec/dca_syncwords.h b/libavcodec/dca_syncwords.h
index 4d2cd5f56d..ccbc38bb38 100644
--- a/libavcodec/dca_syncwords.h
+++ b/libavcodec/dca_syncwords.h
@@ -33,4 +33,7 @@
#define DCA_SYNCWORD_SUBSTREAM_CORE 0x02B09261U
#define DCA_SYNCWORD_REV1AUX 0x9A1105A0U
+#define DCA_SYNCWORD_XLL_X 0x20008
+#define DCA_SYNCWORD_XLL_IMAX (0xF14000D0 >> 1)
+
#endif /* AVCODEC_DCA_SYNCWORDS_H */
diff --git a/libavcodec/dca_xll.c b/libavcodec/dca_xll.c
index fe2c766d98..6b64f907cc 100644
--- a/libavcodec/dca_xll.c
+++ b/libavcodec/dca_xll.c
@@ -1043,6 +1043,7 @@ static int parse_band_data(DCAXllDecoder *s)
static int parse_frame(DCAXllDecoder *s, const uint8_t *data, int size, DCAExssAsset *asset)
{
int ret;
+ int extradata_peek_pos;
if ((ret = init_get_bits8(&s->gb, data, size)) < 0)
return ret;
@@ -1054,10 +1055,23 @@ static int parse_frame(DCAXllDecoder *s, const uint8_t *data, int size, DCAExssA
return ret;
if ((ret = parse_band_data(s)) < 0)
return ret;
+
+ extradata_peek_pos = (get_bits_count(&s->gb) + 31) & ~31;
+ if (s->frame_size * 8 > extradata_peek_pos) {
+ unsigned int extradata_syncword = show_bits(&s->gb, 32);
+
+ if (extradata_syncword == DCA_SYNCWORD_XLL_X) {
+ s->avctx->spatial_ext = 1;
+ } else if ((extradata_syncword >> 1) == DCA_SYNCWORD_XLL_IMAX) {
+ s->avctx->spatial_ext = 1;
+ }
+ }
+
if (ff_dca_seek_bits(&s->gb, s->frame_size * 8)) {
av_log(s->avctx, AV_LOG_ERROR, "Read past end of XLL frame\n");
return AVERROR_INVALIDDATA;
}
+
return ret;
}
diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c
index deca51dd3d..5c71751a0c 100644
--- a/libavcodec/eac3dec.c
+++ b/libavcodec/eac3dec.c
@@ -464,7 +464,16 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
if (get_bits1(gbc)) {
int addbsil = get_bits(gbc, 6);
for (i = 0; i < addbsil + 1; i++) {
- skip_bits(gbc, 8); // skip additional bit stream info
+ if (i == 0) {
+ /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a
+ which can be used to detect Atmos presence */
+ skip_bits(gbc, 7);
+ if (get_bits1(gbc)) {
+ s->eac3_extension_type_a = 1;
+ }
+ } else {
+ skip_bits(gbc, 8); // skip additional bit stream info
+ }
}
}
diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c
index 0ee1f0982c..547e68342e 100644
--- a/libavcodec/mlpdec.c
+++ b/libavcodec/mlpdec.c
@@ -392,6 +392,15 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
m->num_substreams = mh.num_substreams;
m->substream_info = mh.substream_info;
+ /* If there is a 4th substream and the MSB of substream_info is set,
+ * there is a 16-channel spatial presentation (Atmos in TrueHD).
+ */
+ if (m->avctx->codec_id == AV_CODEC_ID_TRUEHD
+ && m->num_substreams == 4
+ && m->substream_info >> 7 == 1) {
+ m->avctx->spatial_ext = 1;
+ }
+
/* limit to decoding 3 substreams, as the 4th is used by Dolby Atmos for non-audio data */
m->max_decoded_substream = FFMIN(m->num_substreams - 1, 2);
--
2.25.1
More information about the ffmpeg-devel
mailing list