[vlc-commits] [Git][videolan/vlc][master] 5 commits: packetizer: mpeg4: move audio configs parsing to header

Steve Lhomme (@robUx4) gitlab at videolan.org
Sat Nov 30 15:54:45 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
50a4eb3d by François Cartegnie at 2024-11-30T15:29:53+00:00
packetizer: mpeg4: move audio configs parsing to header

- - - - -
00ee14f0 by François Cartegnie at 2024-11-30T15:29:53+00:00
packetizer: mpeg4: fix mapping entries for HEVC/VVC

- - - - -
767b772e by François Cartegnie at 2024-11-30T15:29:53+00:00
packetizer: mpeg4: move and rewrite as mpeg4systems.h

- - - - -
34295781 by François Cartegnie at 2024-11-30T15:29:53+00:00
access: rtp: inline few helpers to clear warnings

- - - - -
a40fbd1f by François Cartegnie at 2024-11-30T15:29:53+00:00
access: rtp: add support for MPEG-4 payloads

- - - - -


11 changed files:

- modules/access/rtp/Makefile.am
- modules/access/rtp/h26x.h
- + modules/access/rtp/mpeg4.c
- modules/codec/faad.c
- modules/demux/Makefile.am
- modules/demux/adaptive/tools/FormatNamespace.cpp
- modules/demux/mp4/essetup.c
- − modules/demux/mp4/mpeg4.h
- modules/packetizer/mpeg4audio.c
- modules/packetizer/mpeg4audio.h
- + modules/packetizer/mpeg4systems.h


Changes:

=====================================
modules/access/rtp/Makefile.am
=====================================
@@ -38,6 +38,7 @@ rtpparsedir = $(accessdir)/rtp
 rtpparse_LTLIBRARIES = \
 	librtp_ac3_plugin.la \
 	librtp_mpeg12_plugin.la \
+	librtp_mpeg4_plugin.la \
 	librtp_pcm_plugin.la \
 	librtp_raw_plugin.la \
 	librtp_h264_plugin.la \
@@ -48,6 +49,8 @@ rtpparse_LTLIBRARIES = \
 librtp_ac3_plugin_la_SOURCES = access/rtp/ac3.c
 librtp_mpeg12_plugin_la_SOURCES = access/rtp/mpeg12.c
 
+librtp_mpeg4_plugin_la_SOURCES = access/rtp/mpeg4.c
+
 librtp_pcm_plugin_la_SOURCES = access/rtp/pcm.c
 librtp_pcm_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/access/rtp
 


=====================================
modules/access/rtp/h26x.h
=====================================
@@ -101,7 +101,7 @@ static void h26x_add_xps(void *priv, uint8_t *xps, size_t xpssz)
     *ppp_append = &((**ppp_append)->p_next);
 }
 
-static block_t * h26x_fillextradata (const char *psz)
+static inline block_t * h26x_fillextradata (const char *psz)
 {
     block_t *xps = NULL;
     block_t **pxps = &xps;
@@ -148,7 +148,7 @@ static void h26x_output(struct rtp_h26x_sys *sys,
     }
 }
 
-static void h26x_output_blocks(struct rtp_h26x_sys *sys, bool b_annexb)
+static inline void h26x_output_blocks(struct rtp_h26x_sys *sys, bool b_annexb)
 {
     if(!sys->p_packets)
         return;


=====================================
modules/access/rtp/mpeg4.c
=====================================
@@ -0,0 +1,391 @@
+/**
+ * @file mpeg4.c
+ */
+/*****************************************************************************
+ * Copyright (C) 2024 VideoLabs, VLC authors and VideoLAN
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "h26x.h"
+#include "fmtp.h"
+#include "../../packetizer/mpeg4audio.h"
+#include "../../packetizer/mpeg4systems.h"
+
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_bits.h>
+
+struct mpeg4_pt_opaque
+{
+    // RFC 3640
+    uint8_t streamType;
+    uint8_t sizeLength;
+    uint8_t indexLength;
+    uint8_t indexDeltaLength;
+    uint8_t constantSize;
+    uint8_t CTSDeltaLength;
+    uint8_t DTSDeltaLength;
+    uint8_t randomAccessIndication;
+    uint8_t auxiliaryDataSizeLength;
+    // RFC 6416
+    uint8_t object_id;
+    // unsigned profile_level_id;
+    block_t *config;
+    vlc_object_t *obj;
+};
+
+static void *rtp_mpeg4_init(struct vlc_rtp_pt *pt, es_format_t *fmt)
+{
+    struct mpeg4_pt_opaque *opaque = pt->opaque;
+    block_t *config = opaque->config;
+    enum es_format_category_e es_cat = fmt->i_cat;
+    struct rtp_h26x_sys *sys = malloc(sizeof(*sys));
+    if(!sys)
+        return NULL;
+    rtp_h26x_init(sys);
+
+    sys->p_packetizer = demux_PacketizerNew(opaque->obj, fmt, "rtp packetizer");
+    if(!sys->p_packetizer)
+    {
+        free(sys);
+        return NULL;
+    }
+
+    sys->es = vlc_rtp_pt_request_es(pt, &sys->p_packetizer->fmt_out);
+    if(config && es_cat == VIDEO_ES)
+        sys->xps = block_Duplicate(config);
+
+    return sys;
+}
+
+static void *rtp_mpeg4v_init(struct vlc_rtp_pt *pt)
+{
+    es_format_t fmt;
+    es_format_Init (&fmt, VIDEO_ES, VLC_CODEC_MP4V);
+    fmt.b_packetized = false;
+    return rtp_mpeg4_init(pt, &fmt);
+}
+
+static vlc_fourcc_t audioObjectTypeToCodec(uint8_t objectType)
+{
+    switch(objectType)
+    {
+    case MPEG4_AOT_AAC_MAIN:
+    case MPEG4_AOT_AAC_LC:
+    case MPEG4_AOT_AAC_SSR:
+    case MPEG4_AOT_AAC_LTP:
+    case MPEG4_AOT_AAC_SBR:
+    case MPEG4_AOT_AAC_SC:
+    case MPEG4_AOT_SSC:
+    case MPEG4_AOT_AAC_PS:
+    case MPEG4_AOT_ER_AAC_LC:
+    case MPEG4_AOT_ER_AAC_LTP:
+    case MPEG4_AOT_ER_AAC_SC:
+    case MPEG4_AOT_ER_BSAC:
+    case MPEG4_AOT_ER_AAC_LD:
+    case MPEG4_AOT_ER_AAC_ELD:
+        return VLC_CODEC_MP4A;
+    case MPEG4_AOT_CELP:
+    case MPEG4_AOT_ER_CELP:
+        return VLC_CODEC_QCELP;
+    default:
+        return 0;
+    }
+}
+
+static void *rtp_mpeg4a_init(struct vlc_rtp_pt *pt)
+{
+    struct mpeg4_pt_opaque *opaque = pt->opaque;
+    es_format_t fmt;
+    es_format_Init(&fmt, AUDIO_ES, 0);
+    fmt.b_packetized = false;
+
+    if(!opaque->sizeLength && !opaque->constantSize) // RFC 6416 is MP4A-LATM
+    {
+        fmt.i_codec = audioObjectTypeToCodec(opaque->object_id);
+        fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M');
+    }
+    else // RFC 3640 MPEG4-GENERIC
+    {
+        const block_t *config = opaque->config;
+        if(config)
+        {
+            bs_t bs;
+            bs_init(&bs, config->p_buffer, config->i_buffer);
+            MPEG4_asc_t cfg = {0};
+            if(MPEG4_read_AudioSpecificConfig(&bs, &cfg, false) == VLC_SUCCESS)
+            {
+                fmt.i_codec = audioObjectTypeToCodec(cfg.i_object_type);
+                fmt.audio.i_rate = cfg.i_samplerate;
+            }
+            else fmt.i_codec = VLC_CODEC_MP4A;
+        }
+        else
+        {
+            fmt.i_codec = VLC_CODEC_MP4A;
+        }
+    }
+
+    return rtp_mpeg4_init(pt, &fmt);
+}
+
+static void rtp_mpeg4_destroy(struct vlc_rtp_pt *pt, void *data)
+{
+    VLC_UNUSED(pt);
+    struct rtp_h26x_sys *sys = data;
+    if(sys)
+    {
+        if(sys->p_packetizer)
+            demux_PacketizerDestroy(sys->p_packetizer);
+        vlc_rtp_es_destroy(sys->es);
+        rtp_h26x_clear(sys);
+        free(sys);
+    }
+}
+
+static void rtp_mpeg4_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
+                             const struct vlc_rtp_pktinfo *restrict info)
+{
+    struct mpeg4_pt_opaque *opaque = pt->opaque;
+    struct rtp_h26x_sys *sys = data;
+
+    if(opaque->sizeLength && block->i_buffer > 2)
+    {
+        uint32_t auIndex = (uint32_t) -1;
+
+        uint16_t auHeadersLength = GetWBE(block->p_buffer);
+        size_t data_section_offset = 2 + (auHeadersLength + 7) / 8;
+        if(data_section_offset + 2 >= block->i_buffer)
+            goto drop;
+
+        /* AUX header parsing */
+        if(opaque->auxiliaryDataSizeLength)
+        {
+            const uint8_t *auxheader_data = &block->p_buffer[data_section_offset];
+            size_t auxheader_data_size = block->i_buffer - data_section_offset;
+            bs_t bs;
+            bs_init(&bs, auxheader_data, auxheader_data_size);
+            uint32_t auxSize = bs_read(&bs, opaque->auxiliaryDataSizeLength);
+            data_section_offset += (auxheader_data_size + auxSize + 7) / 8;
+            if(data_section_offset >= block->i_buffer)
+                goto drop;
+        }
+
+        const uint8_t *data_section = &block->p_buffer[data_section_offset];
+        size_t data_section_size = block->i_buffer - data_section_offset;
+
+        /* AU header parsing */
+        bs_t bs;
+        bs_init(&bs, &block->p_buffer[2], block->i_buffer - 2);
+
+        while(auHeadersLength >= 8)
+        {
+            /* Get values from current AU header */
+            size_t pos = bs_pos(&bs);
+            uint32_t auSize = opaque->constantSize
+                            ? opaque->constantSize
+                            : bs_read(&bs, opaque->sizeLength);
+            if(opaque->indexLength)
+            {
+                uint32_t auDeltaIndex = 0;
+                if(auIndex == (uint32_t) -1)
+                    auIndex = bs_read(&bs, opaque->indexLength);
+                else
+                    auDeltaIndex = bs_read(&bs, opaque->indexDeltaLength);
+                VLC_UNUSED(auDeltaIndex); // for when we'll reorder
+            }
+
+            uint32_t CTSDelta = 0, DTSDelta = 0, RAPFlag = 0;
+            if(opaque->CTSDeltaLength && bs_read(&bs, 1))
+                CTSDelta = bs_read(&bs, opaque->CTSDeltaLength);
+
+            if(opaque->DTSDeltaLength && bs_read(&bs, 1))
+                DTSDelta = bs_read(&bs, opaque->DTSDeltaLength);
+
+            if(opaque->randomAccessIndication)
+                RAPFlag = bs_read(&bs, 1);
+
+            if(data_section_size < auSize)
+                goto drop;
+
+            /* Extract AU payload data using the current AU header */
+            block_t *au = block_Alloc(auSize);
+            if(au)
+            {
+                memcpy(au->p_buffer, data_section, auSize);
+                if(CTSDelta)
+                    block->i_pts += vlc_tick_from_samples(CTSDelta, pt->frequency);
+                if(DTSDelta)
+                    block->i_dts = block->i_pts - vlc_tick_from_samples(DTSDelta, pt->frequency);
+                if(RAPFlag)
+                    block->i_flags |= BLOCK_FLAG_TYPE_I;
+                h26x_output(sys, au, block->i_pts, true, info->m);
+            }
+            data_section += auSize;
+            data_section_size -= auSize;
+
+            if(bs_eof(&bs) || bs_error(&bs))
+                break;
+            auHeadersLength -= bs_pos(&bs) - pos;
+        }
+    }
+    else
+    {
+        h26x_output(sys, block, block->i_pts, true, info->m);
+        return;
+    }
+
+drop:
+    block_Release(block);
+}
+
+static void rtp_mpeg4_release(struct vlc_rtp_pt *pt)
+{
+    struct mpeg4_pt_opaque *opaque = pt->opaque;
+    if(opaque->config)
+        block_Release(opaque->config);
+    free(opaque);
+}
+
+static const struct vlc_rtp_pt_operations rtp_mpeg4v_ops = {
+    rtp_mpeg4_release, rtp_mpeg4v_init, rtp_mpeg4_destroy, rtp_mpeg4_decode,
+};
+
+static const struct vlc_rtp_pt_operations rtp_mpeg4a_ops = {
+    rtp_mpeg4_release, rtp_mpeg4a_init, rtp_mpeg4_destroy, rtp_mpeg4_decode,
+};
+
+static char hex_to_dec(char c)
+{
+    if (c >= '0' && c <= '9')
+        return c - '0';
+    if (c >= 'A' && c <= 'F')
+        return  c - 'A' + 10;
+    if (c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    return  0;
+}
+
+static block_t * mpeg4_decode_config(const char *psz, size_t len)
+{
+    len &= ~1U;
+    if(len == 0)
+        return NULL;
+    block_t *config = block_Alloc(len/2);
+    if(config)
+    {
+        config->i_buffer = 0;
+        for(size_t i=0; i<len; i+=2)
+        {
+            uint8_t v = hex_to_dec(psz[i]) << 4;
+            v |= hex_to_dec(psz[i+1]);
+            config->p_buffer[config->i_buffer++] = v;
+        }
+    }
+    return config;
+}
+
+static int rtp_mpeg4_open(vlc_object_t *obj, struct vlc_rtp_pt *pt,
+                          const struct vlc_sdp_pt *desc)
+{
+    VLC_UNUSED(obj);
+    size_t sprop_len;
+    const char *sprop;
+    struct mpeg4_pt_opaque tmpOpaque = {0};
+
+    /* IETF RFC 6416 */
+    if (vlc_ascii_strcasecmp(desc->name, "MP4V-ES") == 0)
+        pt->ops = &rtp_mpeg4v_ops;
+    else if (vlc_ascii_strcasecmp(desc->name, "MP4A-LATM") == 0)
+        pt->ops = &rtp_mpeg4a_ops;
+    /* IETF RFC 3640 */
+    else if (vlc_ascii_strcasecmp(desc->name, "MPEG4-GENERIC") == 0)
+    {
+        sprop = vlc_sdp_fmtp_get_str(desc, "streamType", &sprop_len);
+        if (sprop && sprop_len)
+        {
+            tmpOpaque.streamType = strtod(sprop, NULL);
+            if(tmpOpaque.streamType == MPEG4_ST_VISUAL_STREAM)
+                pt->ops = &rtp_mpeg4v_ops;
+            else if(tmpOpaque.streamType == MPEG4_ST_AUDIO_STREAM)
+                pt->ops = &rtp_mpeg4a_ops;
+            else
+                return VLC_ENOTSUP;
+        }
+        /* FFmpeg does not set the streamType accordingly */
+        else pt->ops = &rtp_mpeg4a_ops;
+
+        /* Get variables for our AU header */
+        vlc_sdp_fmtp_get(desc, "sizeLength", &tmpOpaque.sizeLength);
+        if (tmpOpaque.sizeLength)
+        {
+            vlc_sdp_fmtp_get(desc, "indexLength", &tmpOpaque.indexLength);
+            vlc_sdp_fmtp_get(desc, "indexDeltaLength", &tmpOpaque.indexDeltaLength);
+        }
+        else
+        {
+            vlc_sdp_fmtp_get(desc, "constantSize", &tmpOpaque.constantSize);
+        }
+
+        vlc_sdp_fmtp_get(desc, "CTSDeltaLength", &tmpOpaque.CTSDeltaLength);
+        vlc_sdp_fmtp_get(desc, "DTSDeltaLength", &tmpOpaque.DTSDeltaLength);
+        vlc_sdp_fmtp_get(desc, "randomAccessIndication", &tmpOpaque.randomAccessIndication);
+        vlc_sdp_fmtp_get(desc, "auxiliaryDataSizeLength", &tmpOpaque.auxiliaryDataSizeLength);
+
+        // if(!tmpOpaque.constantSize && !tmpOpaque.sizeLength)
+        //     return VLC_EINVAL;
+    }
+    else
+        return VLC_ENOTSUP;
+
+    struct mpeg4_pt_opaque *opaque = calloc(1, sizeof(*opaque));
+    if(!opaque)
+        return VLC_ENOMEM;
+    pt->opaque = opaque;
+
+    *opaque = tmpOpaque;
+    opaque->obj = obj;
+
+    // vlc_sdp_fmtp_get(desc, "profile-level-id", &opaque->profile_level_id);
+    vlc_sdp_fmtp_get(desc, "object", &opaque->object_id);
+
+    /*
+     * Video:
+     *  - RFC 3640: Not defined (generic)
+     *  - RFC 6416: MPEG-4 Visual configuration
+     * Audio:
+     *  - RFC 3640: AudioSpecificConfig() element
+     *  - RFC 6416: StreamMuxConfig() element
+     */
+    sprop = vlc_sdp_fmtp_get_str(desc, "config", &sprop_len);
+    if (sprop && sprop_len)
+        opaque->config = mpeg4_decode_config(sprop, sprop_len);
+
+    return VLC_SUCCESS;
+}
+
+vlc_module_begin()
+    set_shortname(N_("RTP MPEG-4"))
+    set_description(N_("RTP MPEG-4 Visual and Audio payload parser"))
+    set_subcategory(SUBCAT_INPUT_DEMUX)
+    set_rtp_parser_callback(rtp_mpeg4_open)
+    add_shortcut("video/MP4V-ES", "audio/MP4A-LATM", "video/MPEG4-GENERIC", "audio/MPEG4-GENERIC")
+    vlc_module_end()


=====================================
modules/codec/faad.c
=====================================
@@ -157,7 +157,7 @@ static int Open( vlc_object_t *p_this )
         p_dec->fmt_out.audio.i_rate = i_rate;
         p_dec->fmt_out.audio.i_channels = i_channels;
         p_dec->fmt_out.audio.i_physical_channels
-            = mpeg4_asc_channelsbyindex[i_channels];
+            = MPEG4_asc_channelsbyindex[i_channels];
         date_Init( &p_sys->date, i_rate, 1 );
     }
     else
@@ -328,7 +328,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
         p_dec->fmt_out.audio.i_rate = i_rate;
         p_dec->fmt_out.audio.i_channels = i_channels;
         p_dec->fmt_out.audio.i_physical_channels
-            = mpeg4_asc_channelsbyindex[i_channels];
+            = MPEG4_asc_channelsbyindex[i_channels];
         date_Init( &p_sys->date, i_rate, 1 );
     }
 
@@ -399,7 +399,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
                     p_dec->fmt_out.audio.i_rate = i_rate;
                     p_dec->fmt_out.audio.i_channels = i_channels;
                     p_dec->fmt_out.audio.i_physical_channels
-                        = mpeg4_asc_channelsbyindex[i_channels];
+                        = MPEG4_asc_channelsbyindex[i_channels];
                     date_Init( &p_sys->date, i_rate, 1 );
                 }
             }


=====================================
modules/demux/Makefile.am
=====================================
@@ -231,10 +231,10 @@ libmp4_plugin_la_SOURCES = demux/mp4/mp4.c demux/mp4/mp4.h \
                            demux/mp4/qt_palette.h \
                            demux/mp4/essetup.c \
                            demux/mp4/meta.c demux/mp4/meta.h \
-                           demux/mp4/mpeg4.h \
                            demux/mp4/coreaudio.h \
                            demux/av1_unpack.h \
                            demux/asf/asfpacket.c demux/asf/asfpacket.h \
+			   packetizer/mpeg4systems.h \
                            packetizer/iso_color_tables.h \
                            meta_engine/ID3Genres.h
 libmp4_plugin_la_LIBADD = libvlc_mp4.la


=====================================
modules/demux/adaptive/tools/FormatNamespace.cpp
=====================================
@@ -22,7 +22,7 @@
 #endif
 
 #include "FormatNamespace.hpp"
-#include "../../mp4/mpeg4.h"
+#include "../../../packetizer/mpeg4systems.h"
 #include "../../../packetizer/mpeg4audio.h"
 #include "../tools/Helper.h"
 
@@ -58,9 +58,9 @@ void FormatNamespace::ParseMPEG4Elements(const std::vector<std::string> &element
         return;
 
     uint8_t objectType = std::stoi(elements.at(0).substr(0,2), nullptr, 16);
-    if(!MPEG4_Codec_By_ObjectType(objectType, nullptr, 0,
-                                  &fmt.i_codec,
-                                  &fmt.i_profile))
+    if(!MPEG4_get_codec_by_ObjectType(objectType, nullptr, 0,
+                                      &fmt.i_codec,
+                                      &fmt.i_profile))
         return;
 
     switch(objectType)


=====================================
modules/demux/mp4/essetup.c
=====================================
@@ -30,7 +30,7 @@
 #include "avci.h"
 #include "../xiph.h"
 #include "../../packetizer/iso_color_tables.h"
-#include "mpeg4.h"
+#include "../../packetizer/mpeg4systems.h"
 #include "qt_palette.h"
 
 #include <vlc_demux.h>
@@ -110,7 +110,7 @@ static void SetupESDS( demux_t *p_demux, const mp4_track_t *p_track,
 
         /* Fallback */
     default:
-        if( MPEG4_Codec_By_ObjectType( p_decconfig->i_objectProfileIndication,
+        if( MPEG4_get_codec_by_ObjectType( p_decconfig->i_objectProfileIndication,
                                        p_decconfig->p_decoder_specific_info,
                                        p_decconfig->i_decoder_specific_info_len,
                                        &p_fmt->i_codec,


=====================================
modules/demux/mp4/mpeg4.h deleted
=====================================
@@ -1,128 +0,0 @@
-/*****************************************************************************
- * mpeg4.h: MPEG4 ISO-14496-1 definitions
- *****************************************************************************
- * Copyright (C) 2001-2019 VLC authors, VideoLAN and VideoLabs
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-#ifndef MP4_MPEG4_H
-#define MP4_MPEG4_H
-
-#include <vlc_codec.h>
-#include "../../packetizer/dts_header.h"
-
-static inline bool MPEG4_Codec_By_ObjectType(uint8_t oti,
-                                              const uint8_t *p_dsi,
-                                              size_t i_dsi,
-                                              vlc_fourcc_t *pi_codec,
-                                              int *pi_profile)
-{
-    /* See 14496-1 and http://mp4ra.org/#/object_types */
-    switch(oti)
-    {
-        case 0x20: /* MPEG4 VIDEO */
-            *pi_codec = VLC_CODEC_MP4V;
-            break;
-        case 0x21: /* H.264 */
-            *pi_codec = VLC_CODEC_H264;
-            break;
-        case 0x22: /* H.265 */
-            *pi_codec = VLC_CODEC_HEVC;
-            break;
-        case 0x23: /* H.266 */
-            *pi_codec = VLC_CODEC_VVC;
-            break;
-        case 0x40:
-        case 0x41:
-            *pi_codec = VLC_CODEC_MP4A;
-            if(i_dsi >= 2 && p_dsi[0] == 0xF8 && (p_dsi[1]&0xE0)== 0x80)
-                *pi_codec = VLC_CODEC_ALS;
-            break;
-        case 0x60:
-        case 0x61:
-        case 0x62:
-        case 0x63:
-        case 0x64:
-        case 0x65: /* MPEG2 video */
-            *pi_codec = VLC_CODEC_MPGV;
-            break;
-            /* Theses are MPEG2-AAC */
-        case 0x66: /* main profile */
-        case 0x67: /* Low complexity profile */
-        case 0x68: /* Scalable Sampling rate profile */
-            *pi_codec = VLC_CODEC_MP4A;
-            break;
-            /* True MPEG 2 audio */
-        case 0x69:
-            *pi_codec = VLC_CODEC_MPGA;
-            break;
-        case 0x6a: /* MPEG1 video */
-            *pi_codec = VLC_CODEC_MPGV;
-            break;
-        case 0x6b: /* MPEG1 audio */
-            *pi_codec = VLC_CODEC_MPGA;
-            break;
-        case 0x6c: /* jpeg */
-            *pi_codec = VLC_CODEC_JPEG;
-            break;
-        case 0x6d: /* png */
-            *pi_codec = VLC_CODEC_PNG;
-            break;
-        case 0x6e: /* jpeg2000 */
-            *pi_codec = VLC_FOURCC('M','J','2','C');
-            break;
-        case 0xa3: /* vc1 */
-            *pi_codec = VLC_CODEC_VC1;
-            break;
-        case 0xa4:
-            *pi_codec = VLC_CODEC_DIRAC;
-            break;
-        case 0xa5:
-            *pi_codec = VLC_CODEC_A52;
-            break;
-        case 0xa6:
-            *pi_codec = VLC_CODEC_EAC3;
-            break;
-        case 0xa9: /* dts */
-            *pi_codec = VLC_CODEC_DTS;
-            break;
-        case 0xaa: /* DTS-HD HRA */
-        case 0xab: /* DTS-HD Master Audio */
-            *pi_profile = PROFILE_DTS_HD;
-            *pi_codec = VLC_CODEC_DTS;
-            break;
-        case 0xac: /* Extension Substream containing only LBR */
-            *pi_profile = PROFILE_DTS_EXPRESS;
-            *pi_codec = VLC_CODEC_DTS;
-            break;
-        case 0xad:
-            *pi_codec = VLC_CODEC_OPUS;
-            break;
-        case 0xB1:
-            *pi_codec = VLC_CODEC_VP9;
-            break;
-        case 0xDD:
-            *pi_codec = VLC_CODEC_VORBIS;
-            break;
-        case 0xE1:
-            *pi_codec = VLC_CODEC_QCELP;
-            break;
-        default:
-            return false;
-    }
-    return true;
-}
-
-#endif


=====================================
modules/packetizer/mpeg4audio.c
=====================================
@@ -57,62 +57,6 @@
 /*****************************************************************************
  * decoder_sys_t : decoder descriptor
  *****************************************************************************/
-typedef struct
-{
-    enum mpeg4_audioObjectType i_object_type;
-    unsigned i_samplerate;
-    uint8_t i_channel_configuration;
-    int8_t i_sbr;          // 0: no sbr, 1: sbr, -1: unknown
-    int8_t i_ps;           // 0: no ps,  1: ps,  -1: unknown
-
-    struct
-    {
-        enum mpeg4_audioObjectType i_object_type;
-        unsigned i_samplerate;
-        uint8_t i_channel_configuration;
-    } extension;
-
-    /* GASpecific */
-    unsigned i_frame_length;   // 1024 or 960
-
-} mpeg4_asc_t;
-
-#define LATM_MAX_EXTRA_SIZE 64
-typedef struct
-{
-    uint8_t i_program;
-    uint8_t i_layer;
-
-    unsigned i_frame_length;         // type 1
-    uint8_t i_frame_length_type;
-    uint8_t i_frame_length_index;   // type 3 4 5 6 7
-
-    mpeg4_asc_t cfg;
-
-    /* Raw configuration */
-    size_t i_extra;
-    uint8_t extra[LATM_MAX_EXTRA_SIZE];
-
-} latm_stream_t;
-
-#define LATM_MAX_LAYER (8)
-#define LATM_MAX_PROGRAM (16)
-typedef struct
-{
-    bool b_same_time_framing;
-    uint8_t i_sub_frames;
-    uint8_t i_programs;
-
-    uint8_t pi_layers[LATM_MAX_PROGRAM];
-
-    uint8_t pi_stream[LATM_MAX_PROGRAM][LATM_MAX_LAYER];
-
-    uint8_t i_streams;
-    latm_stream_t stream[LATM_MAX_PROGRAM*LATM_MAX_LAYER];
-
-    uint32_t i_other_data;
-    int16_t  i_crc;  /* -1 if not set */
-} latm_mux_t;
 
 typedef struct
 {
@@ -140,7 +84,7 @@ typedef struct
 
     /* LOAS */
     bool b_latm_cfg;
-    latm_mux_t latm;
+    MPEG4_streammux_config_t latm;
 
     int i_warnings;
 } decoder_sys_t;
@@ -167,13 +111,6 @@ enum {
     TYPE_LOAS
 };
 
-static const int pi_sample_rates[16] =
-{
-    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-    16000, 12000, 11025, 8000,  7350,  0,     0,     0
-};
-
-
 static int ChannelConfigurationToVLC(uint8_t i_channel)
 {
     if (i_channel == 7)
@@ -187,17 +124,17 @@ static int AOTtoAACProfile(uint8_t i_object_type)
 {
     switch(i_object_type)
     {
-        case AOT_AAC_MAIN:
-        case AOT_AAC_LC:
-        case AOT_AAC_SSR:
-        case AOT_AAC_LTP:
-        case AOT_AAC_SBR:
-        case AOT_AAC_SC:
-        case AOT_ER_AAC_LD:
-        case AOT_AAC_PS:
-        case AOT_ER_AAC_ELD:
+        case MPEG4_AOT_AAC_MAIN:
+        case MPEG4_AOT_AAC_LC:
+        case MPEG4_AOT_AAC_SSR:
+        case MPEG4_AOT_AAC_LTP:
+        case MPEG4_AOT_AAC_SBR:
+        case MPEG4_AOT_AAC_SC:
+        case MPEG4_AOT_ER_AAC_LD:
+        case MPEG4_AOT_AAC_PS:
+        case MPEG4_AOT_ER_AAC_ELD:
             {
-            static_assert(AOT_AAC_MAIN == AAC_PROFILE_MAIN + 1,
+            static_assert(MPEG4_AOT_AAC_MAIN == AAC_PROFILE_MAIN + 1,
                           "invalid profile to object mapping");
             return i_object_type - 1;
             }
@@ -218,8 +155,6 @@ static void ClosePacketizer(vlc_object_t *);
 static block_t *Packetize    (decoder_t *, block_t **);
 static void     Flush( decoder_t * );
 
-static int Mpeg4ReadAudioSpecificConfig(bs_t *s, mpeg4_asc_t *p_cfg, bool);
-
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -299,10 +234,10 @@ static int OpenPacketizer(vlc_object_t *p_this)
 
     if(p_dec->fmt_in->i_extra)
     {
-        mpeg4_asc_t asc;
+        MPEG4_asc_t asc;
         bs_t s;
         bs_init(&s, p_dec->fmt_in->p_extra, p_dec->fmt_in->i_extra);
-        if(Mpeg4ReadAudioSpecificConfig(&s, &asc, true) == VLC_SUCCESS)
+        if(MPEG4_read_AudioSpecificConfig(&s, &asc, true) == VLC_SUCCESS)
         {
             p_dec->fmt_out.audio.i_rate = asc.i_samplerate;
             p_dec->fmt_out.audio.i_frame_length = asc.i_frame_length;
@@ -493,443 +428,6 @@ static int LOASSyncInfo(uint8_t p_header[LOAS_HEADER_SIZE], unsigned int *pi_hea
     return ((p_header[1] & 0x1f) << 8) + p_header[2];
 }
 
-static int Mpeg4GAProgramConfigElement(bs_t *s)
-{
-    /* TODO compute channels count ? */
-    int i_tag = bs_read(s, 4);
-    if (i_tag != 0x05)
-        return -1;
-    bs_skip(s, 2 + 4); // object type + sampling index
-    int i_num_front = bs_read(s, 4);
-    int i_num_side = bs_read(s, 4);
-    int i_num_back = bs_read(s, 4);
-    int i_num_lfe = bs_read(s, 2);
-    int i_num_assoc_data = bs_read(s, 3);
-    int i_num_valid_cc = bs_read(s, 4);
-
-    if (bs_read1(s))
-        bs_skip(s, 4); // mono downmix
-    if (bs_read1(s))
-        bs_skip(s, 4); // stereo downmix
-    if (bs_read1(s))
-        bs_skip(s, 2+1); // matrix downmix + pseudo_surround
-
-    bs_skip(s, i_num_front * (1+4));
-    bs_skip(s, i_num_side * (1+4));
-    bs_skip(s, i_num_back * (1+4));
-    bs_skip(s, i_num_lfe * (4));
-    bs_skip(s, i_num_assoc_data * (4));
-    bs_skip(s, i_num_valid_cc * (5));
-    bs_align(s);
-    int i_comment = bs_read(s, 8);
-    bs_skip(s, i_comment * 8);
-    return 0;
-}
-
-static int Mpeg4GASpecificConfig(mpeg4_asc_t *p_cfg, bs_t *s)
-{
-    p_cfg->i_frame_length = bs_read1(s) ? 960 : 1024;
-    if(p_cfg->i_object_type == AOT_ER_AAC_LD) /* 14496-3 4.5.1.1 */
-        p_cfg->i_frame_length >>= 1;
-    else if(p_cfg->i_object_type == AOT_AAC_SSR)
-        p_cfg->i_frame_length = 256;
-
-    if (bs_read1(s))     // depend on core coder
-        bs_skip(s, 14);   // core coder delay
-
-    int i_extension_flag = bs_read1(s);
-    if (p_cfg->i_channel_configuration == 0)
-        Mpeg4GAProgramConfigElement(s);
-    if (p_cfg->i_object_type == AOT_AAC_SC ||
-        p_cfg->i_object_type == AOT_ER_AAC_SC)
-        bs_skip(s, 3);    // layer
-
-    if (i_extension_flag) {
-        if (p_cfg->i_object_type == AOT_ER_BSAC)
-            bs_skip(s, 5 + 11);   // numOfSubFrame + layer length
-        if (p_cfg->i_object_type == AOT_ER_AAC_LC ||
-            p_cfg->i_object_type == AOT_ER_AAC_LTP ||
-            p_cfg->i_object_type == AOT_ER_AAC_SC ||
-            p_cfg->i_object_type == AOT_ER_AAC_LD)
-            bs_skip(s, 1+1+1);    // ER data : section scale spectral */
-        if (bs_read1(s))     // extension 3
-            fprintf(stderr, "Mpeg4GASpecificConfig: error 1\n");
-    }
-    return 0;
-}
-
-static int Mpeg4ELDSpecificConfig(mpeg4_asc_t *p_cfg, bs_t *s)
-{
-    p_cfg->i_frame_length = bs_read1(s) ? 480 : 512;
-
-    /* ELDSpecificConfig Table 4.180 */
-
-    bs_skip(s, 3);
-    if(bs_read1(s)) /* ldSbrPresentFlag */
-    {
-        bs_skip(s, 2);
-        /* ld_sbr_header(channelConfiguration) Table 4.181 */
-        unsigned numSbrHeader;
-        switch(p_cfg->i_channel_configuration)
-        {
-            case 1: case 2:
-                numSbrHeader = 1;
-                break;
-            case 3:
-                numSbrHeader = 2;
-                break;
-            case 4: case 5: case 6:
-                numSbrHeader = 3;
-                break;
-            case 7:
-                numSbrHeader = 4;
-                break;
-            default:
-                numSbrHeader = 0;
-                break;
-        }
-        for( ; numSbrHeader; numSbrHeader-- )
-        {
-            /* sbr_header() Table 4.63 */
-            bs_read(s, 14);
-            bool header_extra_1 = bs_read1(s);
-            bool header_extra_2 = bs_read1(s);
-            if(header_extra_1)
-                bs_read(s, 5);
-            if(header_extra_2)
-                bs_read(s, 6);
-        }
-    }
-
-    for(unsigned eldExtType = bs_read(s, 4);
-        eldExtType != 0x0 /* ELDEXT_TERM */;
-        eldExtType = bs_read(s, 4))
-    {
-        unsigned eldExtLen = bs_read(s, 4);
-        unsigned eldExtLenAdd = 0;
-        if(eldExtLen == 15)
-        {
-            eldExtLenAdd = bs_read(s, 8);
-            eldExtLen += eldExtLenAdd;
-        }
-        if(eldExtLenAdd == 255)
-            eldExtLen += bs_read(s, 16);
-        /* reserved extensions */
-        for(; eldExtLen; eldExtLen--)
-            bs_skip(s, 8);
-    }
-
-    return 0;
-}
-
-static enum mpeg4_audioObjectType Mpeg4ReadAudioObjectType(bs_t *s)
-{
-    int i_type = bs_read(s, 5);
-    if (i_type == 31)
-        i_type = 32 + bs_read(s, 6);
-    return i_type;
-}
-
-static unsigned Mpeg4ReadAudioSamplerate(bs_t *s)
-{
-    int i_index = bs_read(s, 4);
-    if (i_index != 0x0f)
-        return pi_sample_rates[i_index];
-    return bs_read(s, 24);
-}
-
-static int Mpeg4ReadAudioSpecificConfig(bs_t *s, mpeg4_asc_t *p_cfg, bool b_withext)
-{
-    p_cfg->i_object_type = Mpeg4ReadAudioObjectType(s);
-    p_cfg->i_samplerate = Mpeg4ReadAudioSamplerate(s);
-    p_cfg->i_channel_configuration = bs_read(s, 4);
-
-    p_cfg->i_sbr = -1;
-    p_cfg->i_ps  = -1;
-    p_cfg->extension.i_object_type = 0;
-    p_cfg->extension.i_samplerate = 0;
-    p_cfg->extension.i_channel_configuration = 0;
-    p_cfg->i_frame_length = 0;
-
-    if (p_cfg->i_object_type == AOT_AAC_SBR ||
-        p_cfg->i_object_type == AOT_AAC_PS) {
-        p_cfg->i_sbr = 1;
-        if (p_cfg->i_object_type == AOT_AAC_PS)
-           p_cfg->i_ps = 1;
-        p_cfg->extension.i_object_type = AOT_AAC_SBR;
-        p_cfg->extension.i_samplerate = Mpeg4ReadAudioSamplerate(s);
-
-        p_cfg->i_object_type = Mpeg4ReadAudioObjectType(s);
-        if(p_cfg->i_object_type == AOT_ER_BSAC)
-            p_cfg->extension.i_channel_configuration = bs_read(s, 4);
-    }
-
-    switch(p_cfg->i_object_type)
-    {
-    case AOT_AAC_MAIN:
-    case AOT_AAC_LC:
-    case AOT_AAC_SSR:
-    case AOT_AAC_LTP:
-    case AOT_AAC_SC:
-    case AOT_TWINVQ:
-    case AOT_ER_AAC_LC:
-    case AOT_ER_AAC_LTP:
-    case AOT_ER_AAC_SC:
-    case AOT_ER_TWINVQ:
-    case AOT_ER_BSAC:
-    case AOT_ER_AAC_LD:
-        Mpeg4GASpecificConfig(p_cfg, s);
-        break;
-    case AOT_CELP:
-        // CelpSpecificConfig();
-    case AOT_HVXC:
-        // HvxcSpecificConfig();
-    case AOT_TTSI:
-        // TTSSSpecificConfig();
-    case AOT_MAIN_SYNTHETIC:
-    case AOT_WAVETABLES:
-    case AOT_GENERAL_MIDI:
-    case AOT_ALGORITHMIC:
-        // StructuredAudioSpecificConfig();
-    case AOT_ER_CELP:
-        // ERCelpSpecificConfig();
-    case AOT_ER_HXVC:
-        // ERHvxcSpecificConfig();
-    case AOT_ER_HILN:
-    case AOT_ER_Parametric:
-        // ParametricSpecificConfig();
-    case AOT_SSC:
-        // SSCSpecificConfig();
-    case AOT_LAYER1:
-    case AOT_LAYER2:
-    case AOT_LAYER3:
-        // MPEG_1_2_SpecificConfig();
-    case AOT_DST:
-        // DSTSpecificConfig();
-    case AOT_ALS:
-        // ALSSpecificConfig();
-    case AOT_SLS:
-    case AOT_SLS_NON_CORE:
-        // SLSSpecificConfig();
-    case AOT_ER_AAC_ELD:
-        Mpeg4ELDSpecificConfig(p_cfg, s);
-        break;
-    case AOT_SMR_SIMPLE:
-    case AOT_SMR_MAIN:
-        // SymbolicMusicSpecificConfig();
-    default:
-        // error
-        return VLC_EGENERIC;
-    }
-
-    switch(p_cfg->i_object_type)
-    {
-    case AOT_ER_AAC_LC:
-    case AOT_ER_AAC_LTP:
-    case AOT_ER_AAC_SC:
-    case AOT_ER_TWINVQ:
-    case AOT_ER_BSAC:
-    case AOT_ER_AAC_LD:
-    case AOT_ER_CELP:
-    case AOT_ER_HXVC:
-    case AOT_ER_HILN:
-    case AOT_ER_Parametric:
-    case AOT_ER_AAC_ELD:
-    {
-        int epConfig = bs_read(s, 2);
-        if (epConfig == 2 || epConfig == 3)
-            //ErrorProtectionSpecificConfig();
-        if (epConfig == 3)
-            if (bs_read1(s)) {
-                // TODO : directMapping
-            }
-        break;
-    }
-    default:
-        break;
-    }
-
-    if (b_withext && p_cfg->extension.i_object_type != AOT_AAC_SBR &&
-        !bs_eof(s) && bs_read(s, 11) == 0x2b7)
-    {
-        p_cfg->extension.i_object_type = Mpeg4ReadAudioObjectType(s);
-        if (p_cfg->extension.i_object_type == AOT_AAC_SBR)
-        {
-            p_cfg->i_sbr  = bs_read1(s);
-            if (p_cfg->i_sbr == 1) {
-                p_cfg->extension.i_samplerate = Mpeg4ReadAudioSamplerate(s);
-                if (bs_read(s, 11) == 0x548)
-                   p_cfg->i_ps = bs_read1(s);
-            }
-        }
-        else if (p_cfg->extension.i_object_type == AOT_ER_BSAC)
-        {
-            p_cfg->i_sbr  = bs_read1(s);
-            if(p_cfg->i_sbr)
-                p_cfg->extension.i_samplerate = Mpeg4ReadAudioSamplerate(s);
-            p_cfg->extension.i_channel_configuration = bs_read(s, 4);
-        }
-    }
-
-#if 0
-    static const char *ppsz_otype[] = {
-        "NULL",
-        "AAC Main", "AAC LC", "AAC SSR", "AAC LTP", "SBR", "AAC Scalable",
-        "TwinVQ",
-        "CELP", "HVXC",
-        "Reserved", "Reserved",
-        "TTSI",
-        "Main Synthetic", "Wavetables Synthesis", "General MIDI",
-        "Algorithmic Synthesis and Audio FX",
-        "ER AAC LC",
-        "Reserved",
-        "ER AAC LTP", "ER AAC Scalable", "ER TwinVQ", "ER BSAC", "ER AAC LD",
-        "ER CELP", "ER HVXC", "ER HILN", "ER Parametric",
-        "SSC",
-        "PS", "MPEG Surround", "Escape",
-        "Layer 1", "Layer 2", "Layer 3",
-        "DST", "ALS", "SLS", "SLS non-core", "ELD",
-        "SMR Simple", "SMR Main",
-    };
-
-    fprintf(stderr, "Mpeg4ReadAudioSpecificInfo: t=%s(%d)f=%d c=%d sbr=%d\n",
-            ppsz_otype[p_cfg->i_object_type], p_cfg->i_object_type,
-            p_cfg->i_samplerate, p_cfg->i_channel, p_cfg->i_sbr);
-#endif
-    return bs_error(s) ? VLC_EGENERIC : VLC_SUCCESS;
-}
-
-static uint32_t LatmGetValue(bs_t *s)
-{
-    uint32_t v = 0;
-    for (int i = 1 + bs_read(s, 2); i > 0; i--)
-        v = (v << 8) + bs_read(s, 8);
-    return v;
-}
-
-static size_t AudioSpecificConfigBitsToBytes(bs_t *s, uint32_t i_bits, uint8_t *p_data)
-{
-    size_t i_extra = __MIN((i_bits + 7) / 8, LATM_MAX_EXTRA_SIZE);
-    for (size_t i = 0; i < i_extra; i++) {
-        const uint32_t i_read = __MIN(8, i_bits - 8*i);
-        p_data[i] = bs_read(s, i_read) << (8-i_read);
-    }
-    return i_extra;
-}
-
-static int LatmReadStreamMuxConfiguration(latm_mux_t *m, bs_t *s)
-{
-    int i_mux_version;
-    int i_mux_versionA;
-
-    i_mux_version = bs_read(s, 1);
-    i_mux_versionA = 0;
-    if (i_mux_version)
-        i_mux_versionA = bs_read(s, 1);
-
-    if (i_mux_versionA != 0) /* support only A=0 */
-        return -1;
-
-    memset(m, 0, sizeof(*m));
-
-    if (i_mux_versionA == 0)
-        if (i_mux_version == 1)
-            LatmGetValue(s); /* taraBufferFullness */
-
-    if(bs_eof(s))
-        return -1;
-
-    m->b_same_time_framing = bs_read1(s);
-    m->i_sub_frames = 1 + bs_read(s, 6);
-    m->i_programs = 1 + bs_read(s, 4);
-
-    for (uint8_t i_program = 0; i_program < m->i_programs; i_program++) {
-        if(bs_eof(s))
-            return -1;
-        m->pi_layers[i_program] = 1+bs_read(s, 3);
-
-        for (uint8_t i_layer = 0; i_layer < m->pi_layers[i_program]; i_layer++) {
-            latm_stream_t *st = &m->stream[m->i_streams];
-            bool b_previous_cfg;
-
-            m->pi_stream[i_program][i_layer] = m->i_streams;
-            st->i_program = i_program;
-            st->i_layer = i_layer;
-
-            b_previous_cfg = false;
-            if (i_program != 0 || i_layer != 0)
-                b_previous_cfg = bs_read1(s);
-
-            if (b_previous_cfg) {
-                assert(m->i_streams > 0);
-                st->cfg = m->stream[m->i_streams-1].cfg;
-            } else {
-                uint32_t asc_size = 0;
-                if(i_mux_version > 0)
-                    asc_size = LatmGetValue(s);
-                bs_t asc_bs = *s;
-                Mpeg4ReadAudioSpecificConfig(&asc_bs, &st->cfg, i_mux_version > 0);
-                if (i_mux_version == 0)
-                    asc_size = bs_pos(&asc_bs) - bs_pos(s);
-                asc_bs = *s;
-                st->i_extra = AudioSpecificConfigBitsToBytes(&asc_bs, asc_size, st->extra);
-                bs_skip(s, asc_size);
-            }
-
-            st->i_frame_length_type = bs_read(s, 3);
-            switch(st->i_frame_length_type)
-            {
-            case 0:
-            {
-                bs_skip(s, 8); /* latmBufferFullnes */
-                if (!m->b_same_time_framing)
-                    if (st->cfg.i_object_type == AOT_AAC_SC ||
-                        st->cfg.i_object_type == AOT_CELP ||
-                        st->cfg.i_object_type == AOT_ER_AAC_SC ||
-                        st->cfg.i_object_type == AOT_ER_CELP)
-                        bs_skip(s, 6); /* eFrameOffset */
-                break;
-            }
-            case 1:
-                st->i_frame_length = bs_read(s, 9);
-                break;
-            case 3: case 4: case 5:
-                st->i_frame_length_index = bs_read(s, 6); // celp
-                break;
-            case 6: case 7:
-                st->i_frame_length_index = bs_read(s, 1); // hvxc
-            default:
-                break;
-            }
-            /* Next stream */
-            m->i_streams++;
-        }
-    }
-
-    if(bs_error(s) || bs_eof(s))
-        return -1;
-
-    /* other data */
-    if (bs_read1(s)) {
-        if (i_mux_version == 1)
-            m->i_other_data = LatmGetValue(s);
-        else {
-            int b_continue;
-            do {
-                b_continue = bs_read1(s);
-                m->i_other_data = (m->i_other_data << 8) + bs_read(s, 8);
-            } while (b_continue);
-        }
-    }
-
-    /* crc */
-    m->i_crc = -1;
-    if (bs_read1(s))
-        m->i_crc = bs_read(s, 8);
-
-    return bs_error(s) ? -1 : 0;
-}
-
 static int LOASParse(decoder_t *p_dec, uint8_t *p_buffer, int i_buffer)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -939,9 +437,9 @@ static int LOASParse(decoder_t *p_dec, uint8_t *p_buffer, int i_buffer)
     bs_init(&s, p_buffer, i_buffer);
 
     /* Read the stream mux configuration if present */
-    if (!bs_read1(&s) && !LatmReadStreamMuxConfiguration(&p_sys->latm, &s) &&
+    if (!bs_read1(&s) && !MPEG4_parse_StreamMuxConfig(&s, &p_sys->latm) &&
             p_sys->latm.i_streams > 0) {
-        const latm_stream_t *st = &p_sys->latm.stream[0];
+        const MPEG4_audio_stream_t *st = &p_sys->latm.stream[0];
 
         if(st->cfg.i_samplerate == 0 || st->cfg.i_frame_length == 0 ||
            ChannelConfigurationToVLC(st->cfg.i_channel_configuration) == 0)
@@ -996,12 +494,12 @@ static int LOASParse(decoder_t *p_dec, uint8_t *p_buffer, int i_buffer)
         msg_Err(p_dec, "latm sub frames not yet supported, please send a sample");
 
     for (uint8_t i_sub = 0; i_sub < p_sys->latm.i_sub_frames; i_sub++) {
-        unsigned pi_payload[LATM_MAX_PROGRAM][LATM_MAX_LAYER];
+        unsigned pi_payload[MPEG4_STREAMMUX_MAX_PROGRAM][MPEG4_STREAMMUX_MAX_LAYER];
         if (p_sys->latm.b_same_time_framing) {
             /* Payload length */
             for (uint8_t i_program = 0; i_program < p_sys->latm.i_programs; i_program++) {
                 for (uint8_t i_layer = 0; i_layer < p_sys->latm.pi_layers[i_program]; i_layer++) {
-                    latm_stream_t *st = &p_sys->latm.stream[p_sys->latm.pi_stream[i_program][i_layer]];
+                    MPEG4_audio_stream_t *st = &p_sys->latm.stream[p_sys->latm.pi_stream[i_program][i_layer]];
                     if (st->i_frame_length_type == 0) {
                         unsigned i_payload = 0;
                         for (;;) {
@@ -1055,7 +553,7 @@ static int LOASParse(decoder_t *p_dec, uint8_t *p_buffer, int i_buffer)
 
             for (int i_chunk = 0; i_chunk < i_chunks; i_chunk++) {
                 const int streamIndex = bs_read(&s, 4);
-                latm_stream_t *st = &p_sys->latm.stream[streamIndex];
+                MPEG4_audio_stream_t *st = &p_sys->latm.stream[streamIndex];
                 const int i_program = st->i_program;
                 const int i_layer = st->i_layer;
 


=====================================
modules/packetizer/mpeg4audio.h
=====================================
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * mpeg4audio.h: MPEG 4 audio definitions
+ * mpeg4audio.h: ISO/IEC 14496-3 audio definitions
  *****************************************************************************
- * Copyright (C) 2001-2017 VLC authors and VideoLAN
+ * Copyright (C) 2001-2024 VLC authors, VideoLAN and VideoLabs
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -17,68 +17,71 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
-enum mpeg4_audioObjectType /* ISO/IEC 14496-3:2009 1.5.1 */
+#include <vlc_bits.h>
+
+enum MPEG4_audioObjectType /* ISO/IEC 14496-3:2009 1.5.1 */
 {
-    AOT_AAC_MAIN        = 1,
-    AOT_AAC_LC          = 2,
-    AOT_AAC_SSR         = 3,
-    AOT_AAC_LTP         = 4,
-    AOT_AAC_SBR         = 5,
-    AOT_AAC_SC          = 6,
-    AOT_TWINVQ          = 7,
-    AOT_CELP            = 8,
-    AOT_HVXC            = 9,
-    AOT_RESERVED10      = 10,
-    AOT_RESERVED11      = 11,
-    AOT_TTSI            = 12,
-    AOT_MAIN_SYNTHETIC  = 13,
-    AOT_WAVETABLES      = 14,
-    AOT_GENERAL_MIDI    = 15,
-    AOT_ALGORITHMIC     = 16,
-    AOT_ER_AAC_LC       = 17,
-    AOT_RESERVED18      = 18,
-    AOT_ER_AAC_LTP      = 19,
-    AOT_ER_AAC_SC       = 20,
-    AOT_ER_TWINVQ       = 21,
-    AOT_ER_BSAC         = 22,
-    AOT_ER_AAC_LD       = 23,
-    AOT_ER_CELP         = 24,
-    AOT_ER_HXVC         = 25,
-    AOT_ER_HILN         = 26,
-    AOT_ER_Parametric   = 27,
-    AOT_SSC             = 28,
-    AOT_AAC_PS          = 29,
-    AOT_MPEG_SURROUND   = 30,
-    AOT_ESCAPE          = 31,
-    AOT_LAYER1          = 32,
-    AOT_LAYER2          = 33,
-    AOT_LAYER3          = 34,
-    AOT_DST             = 35,
-    AOT_ALS             = 36,
-    AOT_SLS             = 37,
-    AOT_SLS_NON_CORE    = 38,
-    AOT_ER_AAC_ELD      = 39,
-    AOT_SMR_SIMPLE      = 40,
-    AOT_SMR_MAIN        = 41,
+    MPEG4_AOT_NULL            = 0,
+    MPEG4_AOT_AAC_MAIN        = 1,
+    MPEG4_AOT_AAC_LC          = 2,
+    MPEG4_AOT_AAC_SSR         = 3,
+    MPEG4_AOT_AAC_LTP         = 4,
+    MPEG4_AOT_AAC_SBR         = 5,
+    MPEG4_AOT_AAC_SC          = 6,
+    MPEG4_AOT_TWINVQ          = 7,
+    MPEG4_AOT_CELP            = 8,
+    MPEG4_AOT_HVXC            = 9,
+    MPEG4_AOT_RESERVED10      = 10,
+    MPEG4_AOT_RESERVED11      = 11,
+    MPEG4_AOT_TTSI            = 12,
+    MPEG4_AOT_MAIN_SYNTHETIC  = 13,
+    MPEG4_AOT_WAVETABLES      = 14,
+    MPEG4_AOT_GENERAL_MIDI    = 15,
+    MPEG4_AOT_ALGORITHMIC     = 16,
+    MPEG4_AOT_ER_AAC_LC       = 17,
+    MPEG4_AOT_RESERVED18      = 18,
+    MPEG4_AOT_ER_AAC_LTP      = 19,
+    MPEG4_AOT_ER_AAC_SC       = 20,
+    MPEG4_AOT_ER_TWINVQ       = 21,
+    MPEG4_AOT_ER_BSAC         = 22,
+    MPEG4_AOT_ER_AAC_LD       = 23,
+    MPEG4_AOT_ER_CELP         = 24,
+    MPEG4_AOT_ER_HXVC         = 25,
+    MPEG4_AOT_ER_HILN         = 26,
+    MPEG4_AOT_ER_Parametric   = 27,
+    MPEG4_AOT_SSC             = 28,
+    MPEG4_AOT_AAC_PS          = 29,
+    MPEG4_AOT_MPEG_SURROUND   = 30,
+    MPEG4_AOT_ESCAPE          = 31,
+    MPEG4_AOT_LAYER1          = 32,
+    MPEG4_AOT_LAYER2          = 33,
+    MPEG4_AOT_LAYER3          = 34,
+    MPEG4_AOT_DST             = 35,
+    MPEG4_AOT_ALS             = 36,
+    MPEG4_AOT_SLS             = 37,
+    MPEG4_AOT_SLS_NON_CORE    = 38,
+    MPEG4_AOT_ER_AAC_ELD      = 39,
+    MPEG4_AOT_SMR_SIMPLE      = 40,
+    MPEG4_AOT_SMR_MAIN        = 41,
 };
 
 enum
 {
-    AAC_PROFILE_MAIN = AOT_AAC_MAIN - 1,
+    AAC_PROFILE_MAIN = MPEG4_AOT_AAC_MAIN - 1,
     AAC_PROFILE_LC,
     AAC_PROFILE_SSR,
     AAC_PROFILE_LTP,
     AAC_PROFILE_HE,
-    AAC_PROFILE_LD   = AOT_ER_AAC_LD - 1,
-    AAC_PROFILE_HEv2 = AOT_AAC_PS - 1,
-    AAC_PROFILE_ELD  = AOT_ER_AAC_ELD - 1,
+    AAC_PROFILE_LD   = MPEG4_AOT_ER_AAC_LD - 1,
+    AAC_PROFILE_HEv2 = MPEG4_AOT_AAC_PS - 1,
+    AAC_PROFILE_ELD  = MPEG4_AOT_ER_AAC_ELD - 1,
     /* Similar shift signaling as avcodec, as signaling should have been
        done in ADTS header. Values defaults to MPEG4 */
     AAC_PROFILE_MPEG2_LC = AAC_PROFILE_LC + 128,
     AAC_PROFILE_MPEG2_HE = AAC_PROFILE_HE + 128,
 };
 
-static const uint32_t mpeg4_asc_channelsbyindex[] =
+static const uint32_t MPEG4_asc_channelsbyindex[] =
 {
     [0] = 0, /* Set later */
 
@@ -110,4 +113,505 @@ static const uint32_t mpeg4_asc_channelsbyindex[] =
     [8] = 0,
 };
 
-#define MPEG4_ASC_MAX_INDEXEDPOS ARRAY_SIZE(mpeg4_asc_channelsbyindex)
+#define MPEG4_ASC_MAX_INDEXEDPOS ARRAY_SIZE(MPEG4_asc_channelsbyindex)
+
+typedef struct
+{
+    enum MPEG4_audioObjectType i_object_type;
+    unsigned i_samplerate;
+    uint8_t i_channel_configuration;
+    int8_t i_sbr;          // 0: no sbr, 1: sbr, -1: unknown
+    int8_t i_ps;           // 0: no ps,  1: ps,  -1: unknown
+
+    struct
+    {
+        enum MPEG4_audioObjectType i_object_type;
+        unsigned i_samplerate;
+        uint8_t i_channel_configuration;
+    } extension;
+
+    /* GASpecific */
+    unsigned i_frame_length;   // 1024 or 960
+
+} MPEG4_asc_t;
+
+static inline int MPEG4_read_GAProgramConfigElement(bs_t *s)
+{
+    /* TODO compute channels count ? */
+    int i_tag = bs_read(s, 4);
+    if (i_tag != 0x05)
+        return -1;
+    bs_skip(s, 2 + 4); // object type + sampling index
+    int i_num_front = bs_read(s, 4);
+    int i_num_side = bs_read(s, 4);
+    int i_num_back = bs_read(s, 4);
+    int i_num_lfe = bs_read(s, 2);
+    int i_num_assoc_data = bs_read(s, 3);
+    int i_num_valid_cc = bs_read(s, 4);
+
+    if (bs_read1(s))
+        bs_skip(s, 4); // mono downmix
+    if (bs_read1(s))
+        bs_skip(s, 4); // stereo downmix
+    if (bs_read1(s))
+        bs_skip(s, 2+1); // matrix downmix + pseudo_surround
+
+    bs_skip(s, i_num_front * (1+4));
+    bs_skip(s, i_num_side * (1+4));
+    bs_skip(s, i_num_back * (1+4));
+    bs_skip(s, i_num_lfe * (4));
+    bs_skip(s, i_num_assoc_data * (4));
+    bs_skip(s, i_num_valid_cc * (5));
+    bs_align(s);
+    int i_comment = bs_read(s, 8);
+    bs_skip(s, i_comment * 8);
+    return 0;
+}
+
+static inline int MPEG4_read_GASpecificConfig(MPEG4_asc_t *p_cfg, bs_t *s)
+{
+    p_cfg->i_frame_length = bs_read1(s) ? 960 : 1024;
+    if(p_cfg->i_object_type == MPEG4_AOT_ER_AAC_LD) /* 14496-3 4.5.1.1 */
+        p_cfg->i_frame_length >>= 1;
+    else if(p_cfg->i_object_type == MPEG4_AOT_AAC_SSR)
+        p_cfg->i_frame_length = 256;
+
+    if (bs_read1(s))     // depend on core coder
+        bs_skip(s, 14);   // core coder delay
+
+    int i_extension_flag = bs_read1(s);
+    if (p_cfg->i_channel_configuration == 0)
+        MPEG4_read_GAProgramConfigElement(s);
+    if (p_cfg->i_object_type == MPEG4_AOT_AAC_SC ||
+        p_cfg->i_object_type == MPEG4_AOT_ER_AAC_SC)
+        bs_skip(s, 3);    // layer
+
+    if (i_extension_flag) {
+        if (p_cfg->i_object_type == MPEG4_AOT_ER_BSAC)
+            bs_skip(s, 5 + 11);   // numOfSubFrame + layer length
+        if (p_cfg->i_object_type == MPEG4_AOT_ER_AAC_LC ||
+            p_cfg->i_object_type == MPEG4_AOT_ER_AAC_LTP ||
+            p_cfg->i_object_type == MPEG4_AOT_ER_AAC_SC ||
+            p_cfg->i_object_type == MPEG4_AOT_ER_AAC_LD)
+            bs_skip(s, 1+1+1);    // ER data : section scale spectral */
+        if (bs_read1(s))     // extension 3
+            fprintf(stderr, "MPEG4GASpecificConfig: error 1\n");
+    }
+    return 0;
+}
+
+static inline int MPEG4_read_ELDSpecificConfig(MPEG4_asc_t *p_cfg, bs_t *s)
+{
+    p_cfg->i_frame_length = bs_read1(s) ? 480 : 512;
+
+    /* ELDSpecificConfig Table 4.180 */
+
+    bs_skip(s, 3);
+    if(bs_read1(s)) /* ldSbrPresentFlag */
+    {
+        bs_skip(s, 2);
+        /* ld_sbr_header(channelConfiguration) Table 4.181 */
+        unsigned numSbrHeader;
+        switch(p_cfg->i_channel_configuration)
+        {
+        case 1: case 2:
+            numSbrHeader = 1;
+            break;
+        case 3:
+            numSbrHeader = 2;
+            break;
+        case 4: case 5: case 6:
+            numSbrHeader = 3;
+            break;
+        case 7:
+            numSbrHeader = 4;
+            break;
+        default:
+            numSbrHeader = 0;
+            break;
+        }
+        for( ; numSbrHeader; numSbrHeader-- )
+        {
+            /* sbr_header() Table 4.63 */
+            bs_read(s, 14);
+            bool header_extra_1 = bs_read1(s);
+            bool header_extra_2 = bs_read1(s);
+            if(header_extra_1)
+                bs_read(s, 5);
+            if(header_extra_2)
+                bs_read(s, 6);
+        }
+    }
+
+    for(unsigned eldExtType = bs_read(s, 4);
+         eldExtType != 0x0 /* ELDEXT_TERM */;
+         eldExtType = bs_read(s, 4))
+    {
+        unsigned eldExtLen = bs_read(s, 4);
+        unsigned eldExtLenAdd = 0;
+        if(eldExtLen == 15)
+        {
+            eldExtLenAdd = bs_read(s, 8);
+            eldExtLen += eldExtLenAdd;
+        }
+        if(eldExtLenAdd == 255)
+            eldExtLen += bs_read(s, 16);
+        /* reserved extensions */
+        for(; eldExtLen; eldExtLen--)
+            bs_skip(s, 8);
+    }
+
+    return 0;
+}
+
+static inline enum MPEG4_audioObjectType MPEG4_read_AudioObjectType(bs_t *s)
+{
+    int i_type = bs_read(s, 5);
+    if (i_type == 31)
+        i_type = 32 + bs_read(s, 6);
+    return (enum MPEG4_audioObjectType) i_type;
+}
+
+static const int pi_sample_rates[16] =
+    {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000,  7350,  0,     0,     0
+};
+
+static inline unsigned MPEG4_read_AudioSamplerate(bs_t *s)
+{
+    int i_index = bs_read(s, 4);
+    if (i_index != 0x0f)
+        return pi_sample_rates[i_index];
+    return bs_read(s, 24);
+}
+
+static inline int MPEG4_read_AudioSpecificConfig(bs_t *s, MPEG4_asc_t *p_cfg, bool b_withext)
+{
+    p_cfg->i_object_type = MPEG4_read_AudioObjectType(s);
+    p_cfg->i_samplerate = MPEG4_read_AudioSamplerate(s);
+    p_cfg->i_channel_configuration = bs_read(s, 4);
+
+    p_cfg->i_sbr = -1;
+    p_cfg->i_ps  = -1;
+    p_cfg->extension.i_object_type = MPEG4_AOT_NULL;
+    p_cfg->extension.i_samplerate = 0;
+    p_cfg->extension.i_channel_configuration = 0;
+    p_cfg->i_frame_length = 0;
+
+    if (p_cfg->i_object_type == MPEG4_AOT_AAC_SBR ||
+        p_cfg->i_object_type == MPEG4_AOT_AAC_PS) {
+        p_cfg->i_sbr = 1;
+        if (p_cfg->i_object_type == MPEG4_AOT_AAC_PS)
+            p_cfg->i_ps = 1;
+        p_cfg->extension.i_object_type = MPEG4_AOT_AAC_SBR;
+        p_cfg->extension.i_samplerate = MPEG4_read_AudioSamplerate(s);
+
+        p_cfg->i_object_type = MPEG4_read_AudioObjectType(s);
+        if(p_cfg->i_object_type == MPEG4_AOT_ER_BSAC)
+            p_cfg->extension.i_channel_configuration = bs_read(s, 4);
+    }
+
+    switch(p_cfg->i_object_type)
+    {
+    case MPEG4_AOT_AAC_MAIN:
+    case MPEG4_AOT_AAC_LC:
+    case MPEG4_AOT_AAC_SSR:
+    case MPEG4_AOT_AAC_LTP:
+    case MPEG4_AOT_AAC_SC:
+    case MPEG4_AOT_TWINVQ:
+    case MPEG4_AOT_ER_AAC_LC:
+    case MPEG4_AOT_ER_AAC_LTP:
+    case MPEG4_AOT_ER_AAC_SC:
+    case MPEG4_AOT_ER_TWINVQ:
+    case MPEG4_AOT_ER_BSAC:
+    case MPEG4_AOT_ER_AAC_LD:
+        MPEG4_read_GASpecificConfig(p_cfg, s);
+        break;
+    case MPEG4_AOT_CELP:
+        // CelpSpecificConfig();
+    case MPEG4_AOT_HVXC:
+        // HvxcSpecificConfig();
+    case MPEG4_AOT_TTSI:
+        // TTSSSpecificConfig();
+    case MPEG4_AOT_MAIN_SYNTHETIC:
+    case MPEG4_AOT_WAVETABLES:
+    case MPEG4_AOT_GENERAL_MIDI:
+    case MPEG4_AOT_ALGORITHMIC:
+        // StructuredAudioSpecificConfig();
+    case MPEG4_AOT_ER_CELP:
+        // ERCelpSpecificConfig();
+    case MPEG4_AOT_ER_HXVC:
+        // ERHvxcSpecificConfig();
+    case MPEG4_AOT_ER_HILN:
+    case MPEG4_AOT_ER_Parametric:
+        // ParametricSpecificConfig();
+    case MPEG4_AOT_SSC:
+        // SSCSpecificConfig();
+    case MPEG4_AOT_LAYER1:
+    case MPEG4_AOT_LAYER2:
+    case MPEG4_AOT_LAYER3:
+        // MPEG_1_2_SpecificConfig();
+    case MPEG4_AOT_DST:
+        // DSTSpecificConfig();
+    case MPEG4_AOT_ALS:
+        // ALSSpecificConfig();
+    case MPEG4_AOT_SLS:
+    case MPEG4_AOT_SLS_NON_CORE:
+        // SLSSpecificConfig();
+    case MPEG4_AOT_ER_AAC_ELD:
+        MPEG4_read_ELDSpecificConfig(p_cfg, s);
+        break;
+    case MPEG4_AOT_SMR_SIMPLE:
+    case MPEG4_AOT_SMR_MAIN:
+        // SymbolicMusicSpecificConfig();
+    default:
+        // error
+        return VLC_EGENERIC;
+    }
+
+    switch(p_cfg->i_object_type)
+    {
+    case MPEG4_AOT_ER_AAC_LC:
+    case MPEG4_AOT_ER_AAC_LTP:
+    case MPEG4_AOT_ER_AAC_SC:
+    case MPEG4_AOT_ER_TWINVQ:
+    case MPEG4_AOT_ER_BSAC:
+    case MPEG4_AOT_ER_AAC_LD:
+    case MPEG4_AOT_ER_CELP:
+    case MPEG4_AOT_ER_HXVC:
+    case MPEG4_AOT_ER_HILN:
+    case MPEG4_AOT_ER_Parametric:
+    case MPEG4_AOT_ER_AAC_ELD:
+    {
+        int epConfig = bs_read(s, 2);
+        if (epConfig == 2 || epConfig == 3)
+            //ErrorProtectionSpecificConfig();
+            if (epConfig == 3)
+                if (bs_read1(s)) {
+                    // TODO : directMapping
+                }
+        break;
+    }
+    default:
+        break;
+    }
+
+    if (b_withext && p_cfg->extension.i_object_type != MPEG4_AOT_AAC_SBR &&
+        !bs_eof(s) && bs_read(s, 11) == 0x2b7)
+    {
+        p_cfg->extension.i_object_type = MPEG4_read_AudioObjectType(s);
+        if (p_cfg->extension.i_object_type == MPEG4_AOT_AAC_SBR)
+        {
+            p_cfg->i_sbr  = bs_read1(s);
+            if (p_cfg->i_sbr == 1) {
+                p_cfg->extension.i_samplerate = MPEG4_read_AudioSamplerate(s);
+                if (bs_read(s, 11) == 0x548)
+                    p_cfg->i_ps = bs_read1(s);
+            }
+        }
+        else if (p_cfg->extension.i_object_type == MPEG4_AOT_ER_BSAC)
+        {
+            p_cfg->i_sbr  = bs_read1(s);
+            if(p_cfg->i_sbr)
+                p_cfg->extension.i_samplerate = MPEG4_read_AudioSamplerate(s);
+            p_cfg->extension.i_channel_configuration = bs_read(s, 4);
+        }
+    }
+
+#if 0
+    static const char *ppsz_otype[] = {
+        "NULL",
+        "AAC Main", "AAC LC", "AAC SSR", "AAC LTP", "SBR", "AAC Scalable",
+        "TwinVQ",
+        "CELP", "HVXC",
+        "Reserved", "Reserved",
+        "TTSI",
+        "Main Synthetic", "Wavetables Synthesis", "General MIDI",
+        "Algorithmic Synthesis and Audio FX",
+        "ER AAC LC",
+        "Reserved",
+        "ER AAC LTP", "ER AAC Scalable", "ER TwinVQ", "ER BSAC", "ER AAC LD",
+        "ER CELP", "ER HVXC", "ER HILN", "ER Parametric",
+        "SSC",
+        "PS", "MPEG Surround", "Escape",
+        "Layer 1", "Layer 2", "Layer 3",
+        "DST", "ALS", "SLS", "SLS non-core", "ELD",
+        "SMR Simple", "SMR Main",
+    };
+
+    fprintf(stderr, "MPEG4ReadAudioSpecificInfo: t=%s(%d)f=%d c=%d sbr=%d\n",
+            ppsz_otype[p_cfg->i_object_type], p_cfg->i_object_type,
+            p_cfg->i_samplerate, p_cfg->i_channel, p_cfg->i_sbr);
+#endif
+    return bs_error(s) ? VLC_EGENERIC : VLC_SUCCESS;
+}
+
+#define MPEG4_STREAM_MAX_EXTRADATA 64
+typedef struct
+{
+    uint8_t i_program;
+    uint8_t i_layer;
+
+    unsigned i_frame_length;         // type 1
+    uint8_t i_frame_length_type;
+    uint8_t i_frame_length_index;   // type 3 4 5 6 7
+
+    MPEG4_asc_t cfg;
+
+    /* Raw configuration */
+    size_t i_extra;
+    uint8_t extra[MPEG4_STREAM_MAX_EXTRADATA];
+
+} MPEG4_audio_stream_t;
+
+#define MPEG4_STREAMMUX_MAX_LAYER   8
+#define MPEG4_STREAMMUX_MAX_PROGRAM 16
+typedef struct
+{
+    bool b_same_time_framing;
+    uint8_t i_sub_frames;
+    uint8_t i_programs;
+
+    uint8_t pi_layers[MPEG4_STREAMMUX_MAX_PROGRAM];
+
+    uint8_t pi_stream[MPEG4_STREAMMUX_MAX_PROGRAM][MPEG4_STREAMMUX_MAX_LAYER];
+
+    uint8_t i_streams;
+    MPEG4_audio_stream_t stream[MPEG4_STREAMMUX_MAX_PROGRAM*MPEG4_STREAMMUX_MAX_LAYER];
+
+    uint32_t i_other_data;
+    int16_t  i_crc;  /* -1 if not set */
+} MPEG4_streammux_config_t;
+
+static inline uint32_t MPEG4_LatmGetValue(bs_t *s)
+{
+    uint32_t v = 0;
+    for (int i = 1 + bs_read(s, 2); i > 0; i--)
+        v = (v << 8) + bs_read(s, 8);
+    return v;
+}
+
+static inline size_t AudioSpecificConfigBitsToBytes(bs_t *s, uint32_t i_bits, uint8_t *p_data)
+{
+    size_t i_extra = __MIN((i_bits + 7) / 8, MPEG4_STREAM_MAX_EXTRADATA);
+    for (size_t i = 0; i < i_extra; i++) {
+        const uint32_t i_read = __MIN(8, i_bits - 8*i);
+        p_data[i] = bs_read(s, i_read) << (8-i_read);
+    }
+    return i_extra;
+}
+
+static inline int MPEG4_parse_StreamMuxConfig(bs_t *s, MPEG4_streammux_config_t *m)
+{
+    int i_mux_version;
+    int i_mux_versionA;
+
+    i_mux_version = bs_read(s, 1);
+    i_mux_versionA = 0;
+    if (i_mux_version)
+        i_mux_versionA = bs_read(s, 1);
+
+    if (i_mux_versionA != 0) /* support only A=0 */
+        return -1;
+
+    memset(m, 0, sizeof(*m));
+
+    if (i_mux_versionA == 0)
+        if (i_mux_version == 1)
+            MPEG4_LatmGetValue(s); /* taraBufferFullness */
+
+    if(bs_eof(s))
+        return -1;
+
+    m->b_same_time_framing = bs_read1(s);
+    m->i_sub_frames = 1 + bs_read(s, 6);
+    m->i_programs = 1 + bs_read(s, 4);
+
+    for (uint8_t i_program = 0; i_program < m->i_programs; i_program++) {
+        if(bs_eof(s))
+            return -1;
+        m->pi_layers[i_program] = 1+bs_read(s, 3);
+
+        for (uint8_t i_layer = 0; i_layer < m->pi_layers[i_program]; i_layer++) {
+            MPEG4_audio_stream_t *st = &m->stream[m->i_streams];
+            bool b_previous_cfg;
+
+            m->pi_stream[i_program][i_layer] = m->i_streams;
+            st->i_program = i_program;
+            st->i_layer = i_layer;
+
+            b_previous_cfg = false;
+            if (i_program != 0 || i_layer != 0)
+                b_previous_cfg = bs_read1(s);
+
+            if (b_previous_cfg) {
+                assert(m->i_streams > 0);
+                st->cfg = m->stream[m->i_streams-1].cfg;
+            } else {
+                uint32_t asc_size = 0;
+                if(i_mux_version > 0)
+                    asc_size = MPEG4_LatmGetValue(s);
+                bs_t asc_bs = *s;
+                MPEG4_read_AudioSpecificConfig(&asc_bs, &st->cfg, i_mux_version > 0);
+                if (i_mux_version == 0)
+                    asc_size = bs_pos(&asc_bs) - bs_pos(s);
+                asc_bs = *s;
+                st->i_extra = AudioSpecificConfigBitsToBytes(&asc_bs, asc_size, st->extra);
+                bs_skip(s, asc_size);
+            }
+
+            st->i_frame_length_type = bs_read(s, 3);
+            switch(st->i_frame_length_type)
+            {
+            case 0:
+            {
+                bs_skip(s, 8); /* latmBufferFullnes */
+                if (!m->b_same_time_framing)
+                    if (st->cfg.i_object_type == MPEG4_AOT_AAC_SC ||
+                        st->cfg.i_object_type == MPEG4_AOT_CELP ||
+                        st->cfg.i_object_type == MPEG4_AOT_ER_AAC_SC ||
+                        st->cfg.i_object_type == MPEG4_AOT_ER_CELP)
+                        bs_skip(s, 6); /* eFrameOffset */
+                break;
+            }
+            case 1:
+                st->i_frame_length = bs_read(s, 9);
+                break;
+            case 3: case 4: case 5:
+                st->i_frame_length_index = bs_read(s, 6); // celp
+                break;
+            case 6: case 7:
+                st->i_frame_length_index = bs_read(s, 1); // hvxc
+            default:
+                break;
+            }
+            /* Next stream */
+            m->i_streams++;
+        }
+    }
+
+    if(bs_error(s) || bs_eof(s))
+        return -1;
+
+    /* other data */
+    if (bs_read1(s)) {
+        if (i_mux_version == 1)
+            m->i_other_data = MPEG4_LatmGetValue(s);
+        else {
+            int b_continue;
+            do {
+                b_continue = bs_read1(s);
+                m->i_other_data = (m->i_other_data << 8) + bs_read(s, 8);
+            } while (b_continue);
+        }
+    }
+
+    /* crc */
+    m->i_crc = -1;
+    if (bs_read1(s))
+        m->i_crc = bs_read(s, 8);
+
+    return bs_error(s) ? -1 : 0;
+}
+


=====================================
modules/packetizer/mpeg4systems.h
=====================================
@@ -0,0 +1,213 @@
+/*****************************************************************************
+ * mpeg4systems.h: MPEG4 ISO-14496-1 definitions
+ *****************************************************************************
+ * Copyright (C) 2001-2024 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef MP4_MPEG4SYSTEMS_H
+#define MP4_MPEG4SYSTEMS_H
+
+#include <vlc_codec.h>
+#include "dts_header.h"
+
+/* See 14496-1 and http://mp4ra.org/#/object_types */
+
+enum MPEG4_objectTypeIndication
+{
+    MPEG4_OT_FORBIDDEN                              = 0x00,
+    MPEG4_OT_SYSTEMS_14496_1                        = 0x01,
+    MPEG4_OT_SYSTEMS_14496_1_BIFS_V2                = 0x02,
+    MPEG4_OT_INTERACTION_STREAM                     = 0x03,
+    MPEG4_OT_EXTENDED_BIFS_CONFIGURATION            = 0x04,
+    MPEG4_OT_AFX                                    = 0x05,
+    MPEG4_OT_FONT_DATA_STREAM                       = 0x06,
+    MPEG4_OT_SYNTHESIZED_TEXTURE_STREAM             = 0x07,
+    MPEG4_OT_STREAMING_TEXT_STREAM                  = 0x08,
+    MPEG4_OT_LASER_STREAM                           = 0x09,
+    MPEG4_OT_SAF_STREAM                             = 0x0A,
+    // RESERVED_FOR_ISO                               0x0B-0x1F
+    MPEG4_OT_VISUAL_ISO_IEC_14496_2                 = 0x20,
+    MPEG4_OT_VISUAL_ISO_IEC_14496_10_H264           = 0x21,
+    MPEG4_OT_ISO_IEC_14496_10_H264_PARAMETER_SETS   = 0x22,
+    MPEG4_OT_VISUAL_ISO_IEC_23008_2_H265            = 0x23,
+    // RESERVED_FOR_ISO                               0x24-0x3F
+    MPEG4_OT_AUDIO_ISO_IEC_14496_3                  = 0x40,
+    // RESERVED_FOR_ISO                               0x41-0x5F
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_SIMPLE_PROFILE  = 0x60,
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_MAIN_PROFILE    = 0x61,
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_SNR_PROFILE     = 0x62,
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_SPATIAL_PROFILE = 0x63,
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_HIGH_PROFILE    = 0x64,
+    MPEG4_OT_VISUAL_ISO_IEC_13818_2_422_PROFILE     = 0x65,
+    MPEG4_OT_AUDIO_ISO_IEC_13818_7_MAIN_PROFILE     = 0x66,
+    MPEG4_OT_AUDIO_ISO_IEC_13818_7_LC_PROFILE       = 0x67,
+    MPEG4_OT_AUDIO_ISO_IEC_13818_7_SSR_PROFILE      = 0x68,
+    MPEG4_OT_AUDIO_ISO_IEC_13818_3                  = 0x69,
+    MPEG4_OT_VISUAL_ISO_IEC_11172_2                 = 0x6A,
+    MPEG4_OT_AUDIO_ISO_IEC_11172_3                  = 0x6B,
+    MPEG4_OT_VISUAL_ISO_IEC_10918_1_JPEG            = 0x6C,
+    MPEG4_OT_PORTABLE_NETWORK_GRAPHICS              = 0x6D,
+    MPEG4_OT_VISUAL_ISO_IEC_15444_1_JPEG2000        = 0x6E,
+    // RESERVED_FOR_ISO                               0x6F-0x9F
+    MPEG4_OT_3GPP2_EVRC_VOICE                       = 0xA0,
+    MPEG4_OT_3GPP2_SMV_VOICE                        = 0xA1,
+    MPEG4_OT_3GPP2_COMPACT_MULTIMEDIA_FORMAT        = 0xA2,
+    MPEG4_OT_SMPTE_VC1_VIDEO                        = 0xA3,
+    MPEG4_OT_DIRAC_VIDEO_CODER                      = 0xA4,
+    MPEG4_OT_DEPRECATED_AC3                         = 0xA5,
+    MPEG4_OT_DEPRECATED_EAC3                        = 0xA6,
+    MPEG4_OT_DRA_AUDIO                              = 0xA7,
+    MPEG4_OT_ITU_G719_AUDIO                         = 0xA8,
+    MPEG4_OT_DTSHD_CORE_SUBSTREAM                   = 0xA9,
+    MPEG4_OT_DTSHD_CORE_SUBSTREAM_PLUS_EXTENSION    = 0xAA,
+    MPEG4_OT_DTSHD_EXTENSION_SUBSTREAM_ONLY_XLL     = 0xAB,
+    MPEG4_OT_DTSHD_EXTENSION_SUBSTREAM_ONLY_LBR     = 0xAC,
+    MPEG4_OT_OPUS_AUDIO                             = 0xAD,
+    MPEG4_OT_DEPRECATED_AC4                         = 0xAE,
+    MPEG4_OT_AURO_CX_D3_AUDIO                       = 0xAF,
+    MPEG4_OT_REALVIDEO_CODEC_11                     = 0xB0,
+    MPEG4_OT_VP9_VIDEO                              = 0xB1,
+    MPEG4_OT_DTSUHD_PROFILE_2                       = 0xB2,
+    MPEG4_OT_DTSUHD_PROFILE_3_OR_HIGHER             = 0xB3,
+    // RESERVED_FOR_REGISTRATION                      0xB4-0xBF
+    // USER_PRIVATE                                   0xC0-0xE0
+    MPEG4_OT_3GPP2_13K_VOICE                        = 0xE1,
+    // USER_PRIVATE                                   0xE2-0xFE
+    MPEG4_OT_NO_OBJECT_TYPE_SPECIFIED               = 0xFF,
+};
+
+enum MPEG4_streamType
+{
+    MPEG4_ST_FORBIDDEN                              = 0x00,
+    MPEG4_ST_OBJECT_DESCRIPTOR_STREAM               = 0X01,
+    MPEG4_ST_CLOCK_REFERENCE_STREAM                 = 0X02,
+    MPEG4_ST_SCENE_DESCRIPTION_STREAM               = 0X03,
+    MPEG4_ST_VISUAL_STREAM                          = 0X04,
+    MPEG4_ST_AUDIO_STREAM                           = 0X05,
+    MPEG4_ST_MPEG7_STREAM                           = 0X06,
+    MPEG4_ST_IPMP_STREAM                            = 0X07,
+    MPEG4_ST_OBJECT_CONTENT_INFO_STREAM             = 0X08,
+    MPEG4_ST_MPEG_J_STREAM                          = 0X09,
+    MPEG4_ST_INTERACTION_STREAM                     = 0X0A,
+    MPEG4_ST_IPMP_TOOL_STREAM                       = 0X0B,
+    MPEG4_ST_FONT_DATA_STREAM                       = 0X0C,
+    MPEG4_ST_STREAMING_TEXT                         = 0X0D,
+    // USER_PRIVATE                                   0x20-0x3F
+};
+
+static inline bool MPEG4_get_codec_by_ObjectType(uint8_t oti,
+                                                 const uint8_t *p_dsi,
+                                                 size_t i_dsi,
+                                                 vlc_fourcc_t *pi_codec,
+                                                 int *pi_profile)
+{
+    switch(oti)
+    {
+    case MPEG4_OT_VISUAL_ISO_IEC_14496_2: /* MPEG4 VIDEO */
+        *pi_codec = VLC_CODEC_MP4V;
+        break;
+    case MPEG4_OT_VISUAL_ISO_IEC_14496_10_H264: /* H.264 */
+        *pi_codec = VLC_CODEC_H264;
+        break;
+    case MPEG4_OT_VISUAL_ISO_IEC_23008_2_H265: /* H.265 */
+        *pi_codec = VLC_CODEC_HEVC;
+        break;
+    case 0x33: /* H.266 */
+        *pi_codec = VLC_CODEC_VVC;
+        break;
+    case MPEG4_OT_AUDIO_ISO_IEC_14496_3:
+    case 0x41:
+        *pi_codec = VLC_CODEC_MP4A;
+        if(i_dsi >= 2 && p_dsi[0] == 0xF8 && (p_dsi[1]&0xE0)== 0x80)
+            *pi_codec = VLC_CODEC_ALS;
+        break;
+         /* MPEG2 video */
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_SIMPLE_PROFILE:
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_MAIN_PROFILE:
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_SNR_PROFILE:
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_SPATIAL_PROFILE:
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_HIGH_PROFILE:
+    case MPEG4_OT_VISUAL_ISO_IEC_13818_2_422_PROFILE:
+        *pi_codec = VLC_CODEC_MPGV;
+        break;
+        /* Theses are MPEG2-AAC */
+    case MPEG4_OT_AUDIO_ISO_IEC_13818_7_MAIN_PROFILE: /* main profile */
+    case MPEG4_OT_AUDIO_ISO_IEC_13818_7_LC_PROFILE: /* Low complexity profile */
+    case MPEG4_OT_AUDIO_ISO_IEC_13818_7_SSR_PROFILE: /* Scalable Sampling rate profile */
+        *pi_codec = VLC_CODEC_MP4A;
+        break;
+        /* True MPEG 2 audio */
+    case MPEG4_OT_AUDIO_ISO_IEC_13818_3:
+        *pi_codec = VLC_CODEC_MPGA;
+        break;
+    case MPEG4_OT_VISUAL_ISO_IEC_11172_2: /* MPEG1 video */
+        *pi_codec = VLC_CODEC_MPGV;
+        break;
+    case MPEG4_OT_AUDIO_ISO_IEC_11172_3: /* MPEG1 audio */
+        *pi_codec = VLC_CODEC_MPGA;
+        break;
+    case MPEG4_OT_VISUAL_ISO_IEC_10918_1_JPEG: /* jpeg */
+        *pi_codec = VLC_CODEC_JPEG;
+        break;
+    case MPEG4_OT_PORTABLE_NETWORK_GRAPHICS: /* png */
+        *pi_codec = VLC_CODEC_PNG;
+        break;
+    case MPEG4_OT_VISUAL_ISO_IEC_15444_1_JPEG2000: /* jpeg2000 */
+        *pi_codec = VLC_FOURCC('M','J','2','C');
+        break;
+    case MPEG4_OT_SMPTE_VC1_VIDEO: /* vc-1 */
+        *pi_codec = VLC_CODEC_VC1;
+        break;
+    case MPEG4_OT_DIRAC_VIDEO_CODER:
+        *pi_codec = VLC_CODEC_DIRAC;
+        break;
+    case MPEG4_OT_DEPRECATED_AC3:
+        *pi_codec = VLC_CODEC_A52;
+        break;
+    case MPEG4_OT_DEPRECATED_EAC3:
+        *pi_codec = VLC_CODEC_EAC3;
+        break;
+    case MPEG4_OT_DTSHD_CORE_SUBSTREAM: /* DTS */
+        *pi_codec = VLC_CODEC_DTS;
+        break;
+    case MPEG4_OT_DTSHD_CORE_SUBSTREAM_PLUS_EXTENSION: /* DTS-HD HRA */
+    case MPEG4_OT_DTSHD_EXTENSION_SUBSTREAM_ONLY_XLL:  /* DTS-HD Master Audio */
+        *pi_profile = PROFILE_DTS_HD;
+        *pi_codec = VLC_CODEC_DTS;
+        break;
+    case MPEG4_OT_DTSHD_EXTENSION_SUBSTREAM_ONLY_LBR:
+        *pi_profile = PROFILE_DTS_EXPRESS;
+        *pi_codec = VLC_CODEC_DTS;
+        break;
+    case MPEG4_OT_OPUS_AUDIO:
+        *pi_codec = VLC_CODEC_OPUS;
+        break;
+    case MPEG4_OT_VP9_VIDEO:
+        *pi_codec = VLC_CODEC_VP9;
+        break;
+    case 0xDD:
+        *pi_codec = VLC_CODEC_VORBIS;
+        break;
+    case MPEG4_OT_3GPP2_13K_VOICE:
+        *pi_codec = VLC_CODEC_QCELP;
+        break;
+    default:
+        return false;
+    }
+    return true;
+}
+
+#endif



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fe8b4bf937ad08d17d69de07ae21e9f326e2bd96...a40fbd1feeb6a3de29ad0440acd21ff71aa782ed

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fe8b4bf937ad08d17d69de07ae21e9f326e2bd96...a40fbd1feeb6a3de29ad0440acd21ff71aa782ed
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list