[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