[FFmpeg-devel] [PATCH v2] libavcodec/mpegaudio_parser.c: differentiate MPEG audio dual mono

Scott Theisen scott.the.elm at gmail.com
Fri Dec 13 08:30:04 EET 2024


From: ulmus-scott <scott.the.elm at gmail.com>

Defined in ISO/IEC 11172-3 and ISO/IEC 13818-3 as:
dual channel mode [audio]: A mode, where two audio channels with independent
programme contents (e.g. bilingual) are encoded within one bitstream. The
coding process is the same as for the stereo mode.

There is currently no way to signal that an audio channel is monophonic, i.e.
that channel comprises the entirety of an audio signal, so two front center
channels were chosen since AV_CH_LAYOUT_MONO is represented as a single
front center channel.
---
 libavcodec/audiotoolboxdec.c    |  4 ++--
 libavcodec/mpegaudio_parser.c   | 19 ++++++++++++++++---
 libavcodec/mpegaudiodecheader.c |  4 +++-
 libavcodec/mpegaudiodecheader.h |  2 +-
 tests/ref/fate/pva-demux        |  2 +-
 5 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c
index 08203c5310..667d0f9ad0 100644
--- a/libavcodec/audiotoolboxdec.c
+++ b/libavcodec/audiotoolboxdec.c
@@ -346,10 +346,10 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx,
                 avctx->codec_id == AV_CODEC_ID_MP2 ||
                 avctx->codec_id == AV_CODEC_ID_MP3)) {
         enum AVCodecID codec_id;
-        int bit_rate;
+        int bit_rate, dual_mono;
         if (ff_mpa_decode_header(AV_RB32(pkt->data), &avctx->sample_rate,
                                  &in_format.mChannelsPerFrame, &avctx->frame_size,
-                                 &bit_rate, &codec_id) < 0)
+                                 &bit_rate, &codec_id, &dual_mono) < 0)
             return AVERROR_INVALIDDATA;
         avctx->bit_rate = bit_rate;
         in_format.mSampleRate = avctx->sample_rate;
diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c
index d54366f10a..6711163d03 100644
--- a/libavcodec/mpegaudio_parser.c
+++ b/libavcodec/mpegaudio_parser.c
@@ -65,12 +65,12 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
             }
         }else{
             while(i<buf_size){
-                int ret, sr, channels, bit_rate, frame_size;
+                int ret, sr, channels, bit_rate, frame_size, dual_mono;
                 enum AVCodecID codec_id = avctx->codec_id;
 
                 state= (state<<8) + buf[i++];
 
-                ret = ff_mpa_decode_header(state, &sr, &channels, &frame_size, &bit_rate, &codec_id);
+                ret = ff_mpa_decode_header(state, &sr, &channels, &frame_size, &bit_rate, &codec_id, &dual_mono);
                 if (ret < 4) {
                     if (i > 4)
                         s->header_count = -2;
@@ -85,7 +85,20 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
                     if (s->header_count > header_threshold) {
                         avctx->sample_rate= sr;
                         av_channel_layout_uninit(&avctx->ch_layout);
-                        av_channel_layout_default(&avctx->ch_layout, channels);
+                        if (dual_mono) {
+                            // two independent monophonic audio channels in one bitstream
+                            int ret = av_channel_layout_custom_init(&avctx->ch_layout, 2);
+                            if (ret != 0) {
+                                // parsers can't return error codes
+                                avctx->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
+                                avctx->ch_layout.nb_channels = 2;
+                            } else {
+                                avctx->ch_layout.u.map[0].id = AV_CHAN_FRONT_CENTER;
+                                avctx->ch_layout.u.map[1].id = AV_CHAN_FRONT_CENTER;
+                            }
+                        } else {
+                            av_channel_layout_default(&avctx->ch_layout, channels);
+                        }
                         s1->duration      = frame_size;
                         avctx->codec_id   = codec_id;
                         if (s->no_bitrate || !avctx->bit_rate) {
diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c
index ef63befbf4..5cbfdcb677 100644
--- a/libavcodec/mpegaudiodecheader.c
+++ b/libavcodec/mpegaudiodecheader.c
@@ -117,7 +117,7 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header)
     return 0;
 }
 
-int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id)
+int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id, int *dual_mono)
 {
     MPADecodeHeader s1, *s = &s1;
 
@@ -148,5 +148,7 @@ int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *fr
     *sample_rate = s->sample_rate;
     *channels = s->nb_channels;
     *bit_rate = s->bit_rate;
+    *dual_mono = (s->mode == MPA_DUAL);
+
     return s->frame_size;
 }
diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h
index ed5d1f3b33..e599d287f7 100644
--- a/libavcodec/mpegaudiodecheader.h
+++ b/libavcodec/mpegaudiodecheader.h
@@ -56,7 +56,7 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header);
 /* useful helper to get MPEG audio stream info. Return -1 if error in
    header, otherwise the coded frame size in bytes */
 int ff_mpa_decode_header(uint32_t head, int *sample_rate,
-                         int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id);
+                         int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id, int *dual_mono);
 
 /* fast header check for resync */
 static inline int ff_mpa_check_header(uint32_t header){
diff --git a/tests/ref/fate/pva-demux b/tests/ref/fate/pva-demux
index 5c0e1c1ea0..2749ea9f07 100644
--- a/tests/ref/fate/pva-demux
+++ b/tests/ref/fate/pva-demux
@@ -7,7 +7,7 @@
 #media_type 1: audio
 #codec_id 1: mp2
 #sample_rate 1: 48000
-#channel_layout_name 1: stereo
+#channel_layout_name 1: 2 channels (FC+FC)
 1,          0,          0,     2160,      384, 0x071abcc8
 1,       2160,       2160,     2160,      384, 0x31c9aee0
 1,       4320,       4320,     2160,      384, 0xa50eaa94
-- 
2.43.0



More information about the ffmpeg-devel mailing list