1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
From c348f01f5e70bd7b540774fe06eb2e2aa204264d Mon Sep 17 00:00:00 2001
From: Sanchayan Maity <sanchayan@asymptotic.io>
Date: Thu, 12 Nov 2020 20:03:11 +0530
Subject: [PATCH 1/7] fdkaac: Add support for LATM
ISO/IEC 14496-3 (MPEG-4 Audio) defines the LATM/LOAS mechanism to transport
streams without using ISO/IEC 14496-1 (MPEG-4 Systems) for audio only
applications. The transport mechanism uses a two-layer approach, namely a
multiplex layer and a synchronization layer. The multiplex layer viz.
(Low-overhead MPEG-4 Audio Transport Multiplex: LATM) manages multiplexing
of several MPEG-4 Audio payloads and their AudioSpecificConfig elements.
LATM might be considered as LOAS without the synchronization layer.
As per the spec, the multiplexed element viz. AudioMuxElement without
synchronization shall only be used for transmission channels where the
underlying transport layer already provides frame synchronization. An
example case is using AAC with bluetooth.
LATM MCP1 encoded data can be payloaded in RTP for sending the AAC
stream via bluetooth.
For details on bitstream, see the Fraunhofer IIS Application Bulletin on
AAC transport formats.
https://www.iis.fraunhofer.de/content/dam/iis/de/doc/ame/wp/FraunhoferIIS_Application-Bulletin_AAC-Transport-Formats.pdf
Note that muxConfigPresent needs to be set at the application layer and
signals whether the configuration is sent within or outside the stream.
This cannot be determined by parsing the bitstream. We introduce two
different stream formats to be able to distinguish between the MCP0 and
MCP1 case, viz. latm-mcp0/1.
---
.../gst-plugins-bad/ext/fdkaac/gstfdkaacdec.c | 17 ++++-
.../gst-plugins-bad/ext/fdkaac/gstfdkaacenc.c | 67 ++++++++++++++++++-
2 files changed, 79 insertions(+), 5 deletions(-)
Index: gst-plugins-bad1.0-contrib/ext/fdkaac/gstfdkaacdec.c
===================================================================
--- gst-plugins-bad1.0-contrib.orig/ext/fdkaac/gstfdkaacdec.c
+++ gst-plugins-bad1.0-contrib/ext/fdkaac/gstfdkaacdec.c
@@ -45,7 +45,11 @@ static GstStaticPadTemplate sink_templat
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/mpeg, "
"mpegversion = (int) {2, 4}, "
- "stream-format = (string) { adts, adif, raw }, " CHANNELS_CAPS_STR)
+ "stream-format = (string) { adts, adif, raw }, "
+ CHANNELS_CAPS_STR "; "
+ "audio/mpeg, "
+ "mpegversion = (int) 4, "
+ "stream-format = (string) { latm-mcp0, latm-mcp1 }, " CHANNELS_CAPS_STR)
);
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
@@ -126,6 +130,10 @@ gst_fdkaacdec_set_format (GstAudioDecode
transport_format = TT_MP4_ADIF;
} else if (strcmp (stream_format, "adts") == 0) {
transport_format = TT_MP4_ADTS;
+ } else if (strcmp (stream_format, "latm-mcp0") == 0) {
+ transport_format = TT_MP4_LATM_MCP0;
+ } else if (strcmp (stream_format, "latm-mcp1") == 0) {
+ transport_format = TT_MP4_LATM_MCP1;
} else {
g_assert_not_reached ();
}
@@ -136,7 +144,12 @@ gst_fdkaacdec_set_format (GstAudioDecode
return FALSE;
}
- if (transport_format == TT_MP4_RAW) {
+ /*
+ * If out of band config data either AudioSpecificConfig or StreamMuxConfig
+ * is applicable with raw or LATM MCP0 respectively, aacDecoder_ConfigRaw
+ * must be called with this data before beginning the decoding process.
+ */
+ if (transport_format == TT_MP4_RAW || transport_format == TT_MP4_LATM_MCP0) {
GstBuffer *codec_data = NULL;
GstMapInfo map;
guint8 *data;
Index: gst-plugins-bad1.0-contrib/ext/fdkaac/gstfdkaacenc.c
===================================================================
--- gst-plugins-bad1.0-contrib.orig/ext/fdkaac/gstfdkaacenc.c
+++ gst-plugins-bad1.0-contrib/ext/fdkaac/gstfdkaacenc.c
@@ -24,6 +24,7 @@
#include "gstfdkaac.h"
#include "gstfdkaacenc.h"
+#include <gst/base/gstbitwriter.h>
#include <gst/pbutils/pbutils.h>
#include <string.h>
@@ -79,7 +80,7 @@ static GstStaticPadTemplate src_template
"mpegversion = (int) 4, "
"rate = (int) { " SAMPLE_RATES " }, "
"channels = (int) {1, 2, 3, 4, 5, 6, 8}, "
- "stream-format = (string) { adts, adif, raw }, "
+ "stream-format = (string) { adts, adif, raw }, latm-mcp0, latm-mcp1 }, "
"profile = (string) { lc, he-aac-v1, he-aac-v2, ld }, "
"framed = (boolean) true")
);
@@ -297,6 +298,7 @@ gst_fdkaacenc_set_format (GstAudioEncode
CHANNEL_MODE channel_mode = MODE_INVALID;
AACENC_InfoStruct enc_info = { 0 };
gint bitrate, signaling_mode;
+ guint8 audio_spec_conf[2] = { 0 };
guint bitrate_mode;
if (self->enc && !self->is_drained) {
@@ -324,6 +326,20 @@ gst_fdkaacenc_set_format (GstAudioEncode
} else if (strcmp (str, "raw") == 0) {
GST_DEBUG_OBJECT (self, "use RAW format for output");
transmux = 0;
+ } else if (strcmp (str, "latm-mcp1") == 0) {
+ /*
+ * Enable TT_MP4_LATM_MCP1. Sets muxConfigPresent = 1. See Section 4.1 of
+ * RFC 3016.
+ */
+ GST_DEBUG_OBJECT (self, "use LATM MCP1 format for output");
+ transmux = 6;
+ } else if (strcmp (str, "latm-mcp0") == 0) {
+ /*
+ * Enable TT_MP4_LATM_MCP0. Sets muxConfigPresent = 0. See Section 4.1 of
+ * RFC 3016.
+ */
+ GST_DEBUG_OBJECT (self, "use LATM MCP0 format for output");
+ transmux = 7;
}
}
@@ -572,12 +588,57 @@ gst_fdkaacenc_set_format (GstAudioEncode
} else if (transmux == 2) {
gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts",
NULL);
+ } else if (transmux == 6 || transmux == 7) {
+ GstBitWriter bw;
+ guint rate = GST_AUDIO_INFO_RATE (info);
+ guint8 channels = GST_AUDIO_INFO_CHANNELS (info);
+ GstBuffer *codec_data;
+
+ /*
+ * Craft a AudioSpecificConfig manually to be used for setting level and
+ * profile later as when LATM_MCP0/1 is enabled enc_info.confBuf won't have
+ * AudioSpecificConfig but StreamMuxConfig. Since gst_codec_utils expects
+ * an AudioSpecificConfig to retrieve aot, rate and channel config
+ * information, it will fail. We pass this manually constructed
+ * AudioSpecificConfig when LATM is requested.
+ */
+ gst_bit_writer_init_with_data (&bw, audio_spec_conf,
+ sizeof (audio_spec_conf), FALSE);
+ gst_bit_writer_put_bits_uint8 (&bw, 2 /* AOT_AAC_LC */ , 5);
+ gst_bit_writer_put_bits_uint8 (&bw,
+ gst_codec_utils_aac_get_index_from_sample_rate (rate), 4);
+ gst_bit_writer_put_bits_uint8 (&bw, channels, 4);
+
+ codec_data =
+ gst_buffer_new_wrapped (g_memdup (enc_info.confBuf, enc_info.confSize),
+ enc_info.confSize);
+ /*
+ * For MCP0 the config is out of band, so set codec_data to
+ * StreamMuxConfig. For MCP1, the config is in band and need not be send
+ * via any out of band means like codec_data.
+ */
+ if (transmux == 6)
+ gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING,
+ "latm-mcp1", NULL);
+ else
+ gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER, codec_data,
+ "stream-format", G_TYPE_STRING, "latm-mcp0", NULL);
+ gst_buffer_unref (codec_data);
} else {
g_assert_not_reached ();
}
- gst_codec_utils_aac_caps_set_level_and_profile (src_caps, enc_info.confBuf,
- enc_info.confSize);
+ if (transmux != 6 && transmux != 7)
+ gst_codec_utils_aac_caps_set_level_and_profile (src_caps,
+ enc_info.confBuf, enc_info.confSize);
+ else
+ /*
+ * For LATM, confBuf is StreamMuxConfig and not AudioSpecificConfig.
+ * In this case, pass in the manually constructed AudioSpecificConfig
+ * buffer above.
+ */
+ gst_codec_utils_aac_caps_set_level_and_profile (src_caps, audio_spec_conf,
+ sizeof (audio_spec_conf));
/* The above only parses the "base" profile, which is always going to be LC.
* Set actual profile. */
|