#define ADTS_MAX_SIZE 10 /* Should be enough */
#define LOAS_MAX_SIZE 3 /* Should be enough */
+#define ADTS_HEADERS_LENGTH 7UL /* Total byte-length of fixed and variable
+ headers prepended during raw to ADTS
+ conversion */
#define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec)
gst_caps_set_simple (src_caps, "codec_data", GST_TYPE_BUFFER,
codec_data, NULL);
}
+ } else if (aacparse->header_type == DSPAAC_HEADER_NONE) {
+ GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+ "Input is raw, trying ADTS");
+ gst_caps_set_simple (src_caps, "stream-format", G_TYPE_STRING, "adts",
+ NULL);
+ if (gst_caps_can_intersect (src_caps, allowed)) {
+ GST_DEBUG_OBJECT (GST_BASE_PARSE (aacparse)->srcpad,
+ "Caps can intersect, we will prepend ADTS headers");
+ aacparse->output_header_type = DSPAAC_HEADER_ADTS;
+ }
}
}
gst_caps_unref (allowed);
/* arrange for metadata and get out of the way */
gst_aac_parse_set_src_caps (aacparse, caps);
- gst_base_parse_set_passthrough (parse, TRUE);
+ if (aacparse->header_type == aacparse->output_header_type)
+ gst_base_parse_set_passthrough (parse, TRUE);
} else
return FALSE;
return FALSE;
}
+/**
+ * gst_aac_parse_get_audio_profile_object_type
+ * @aacparse: #GstAacParse.
+ *
+ * Gets the MPEG-2 profile or the MPEG-4 object type value corresponding to the
+ * mpegversion and profile of @aacparse's src pad caps, according to the
+ * values defined by table 1.A.11 in ISO/IEC 14496-3.
+ *
+ * Returns: the profile or object type value corresponding to @aacparse's src
+ * pad caps, if such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_profile_object_type (GstAacParse * aacparse)
+{
+ GstCaps *srccaps;
+ GstStructure *srcstruct;
+ const gchar *profile;
+ guint8 ret;
+
+ srccaps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse));
+ srcstruct = gst_caps_get_structure (srccaps, 0);
+ profile = gst_structure_get_string (srcstruct, "profile");
+ if (G_UNLIKELY (profile == NULL)) {
+ gst_caps_unref (srccaps);
+ return G_MAXUINT8;
+ }
+
+ if (g_strcmp0 (profile, "main") == 0) {
+ ret = (guint8) 0U;
+ } else if (g_strcmp0 (profile, "lc") == 0) {
+ ret = (guint8) 1U;
+ } else if (g_strcmp0 (profile, "ssr") == 0) {
+ ret = (guint8) 2U;
+ } else if (g_strcmp0 (profile, "ltp") == 0) {
+ if (G_LIKELY (aacparse->mpegversion == 4))
+ ret = (guint8) 3U;
+ else
+ ret = G_MAXUINT8; /* LTP Object Type allowed only for MPEG-4 */
+ } else {
+ ret = G_MAXUINT8;
+ }
+
+ gst_caps_unref (srccaps);
+ return ret;
+}
+
+/**
+ * gst_aac_parse_get_audio_channel_configuration
+ * @num_channels: number of audio channels.
+ *
+ * Gets the Channel Configuration value, as defined by table 1.19 in ISO/IEC
+ * 14496-3, for a given number of audio channels.
+ *
+ * Returns: the Channel Configuration value corresponding to @num_channels, if
+ * such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_channel_configuration (gint num_channels)
+{
+ if (num_channels >= 1 && num_channels <= 6) /* Mono up to & including 5.1 */
+ return (guint8) num_channels;
+ else if (num_channels == 8) /* 7.1 */
+ return (guint8) 7U;
+ else
+ return G_MAXUINT8;
+}
+
+/**
+ * gst_aac_parse_get_audio_sampling_frequency_index:
+ * @sample_rate: audio sampling rate.
+ *
+ * Gets the Sampling Frequency Index value, as defined by table 1.18 in ISO/IEC
+ * 14496-3, for a given sampling rate.
+ *
+ * Returns: the Sampling Frequency Index value corresponding to @sample_rate,
+ * if such a value exists; otherwise G_MAXUINT8.
+ */
+static guint8
+gst_aac_parse_get_audio_sampling_frequency_index (gint sample_rate)
+{
+ switch (sample_rate) {
+ case 96000:
+ return 0x0U;
+ case 88200:
+ return 0x1U;
+ case 64000:
+ return 0x2U;
+ case 48000:
+ return 0x3U;
+ case 44100:
+ return 0x4U;
+ case 32000:
+ return 0x5U;
+ case 24000:
+ return 0x6U;
+ case 22050:
+ return 0x7U;
+ case 16000:
+ return 0x8U;
+ case 12000:
+ return 0x9U;
+ case 11025:
+ return 0xAU;
+ case 8000:
+ return 0xBU;
+ case 7350:
+ return 0xCU;
+ default:
+ return G_MAXUINT8;
+ }
+}
+
+/**
+ * gst_aac_parse_prepend_adts_headers:
+ * @aacparse: #GstAacParse.
+ * @frame: raw AAC frame to which ADTS headers shall be prepended.
+ *
+ * Prepends ADTS headers to a raw AAC audio frame.
+ *
+ * Returns: TRUE if ADTS headers were successfully prepended; FALSE otherwise.
+ */
+static gboolean
+gst_aac_parse_prepend_adts_headers (GstAacParse * aacparse,
+ GstBaseParseFrame * frame)
+{
+ GstMemory *mem;
+ guint8 *adts_headers;
+ gsize buf_size;
+ gsize frame_size;
+ guint8 id, profile, channel_configuration, sampling_frequency_index;
+
+ id = (aacparse->mpegversion == 4) ? 0x0U : 0x1U;
+ profile = gst_aac_parse_get_audio_profile_object_type (aacparse);
+ if (profile == G_MAXUINT8) {
+ GST_ERROR_OBJECT (aacparse, "Unsupported audio profile or object type");
+ return FALSE;
+ }
+ channel_configuration =
+ gst_aac_parse_get_audio_channel_configuration (aacparse->channels);
+ if (channel_configuration == G_MAXUINT8) {
+ GST_ERROR_OBJECT (aacparse, "Unsupported number of channels");
+ return FALSE;
+ }
+ sampling_frequency_index =
+ gst_aac_parse_get_audio_sampling_frequency_index (aacparse->sample_rate);
+ if (sampling_frequency_index == G_MAXUINT8) {
+ GST_ERROR_OBJECT (aacparse, "Unsupported sampling frequency");
+ return FALSE;
+ }
+
+ frame->out_buffer = gst_buffer_copy (frame->buffer);
+ buf_size = gst_buffer_get_size (frame->out_buffer);
+ frame_size = buf_size + ADTS_HEADERS_LENGTH;
+
+ if (G_UNLIKELY (frame_size >= 0x4000)) {
+ GST_ERROR_OBJECT (aacparse, "Frame size is too big for ADTS");
+ return FALSE;
+ }
+
+ adts_headers = (guint8 *) g_malloc0 (ADTS_HEADERS_LENGTH);
+
+ /* Note: no error correction bits are added to the resulting ADTS frames */
+ adts_headers[0] = 0xFFU;
+ adts_headers[1] = 0xF0U | (id << 3) | 0x1U;
+ adts_headers[2] = (profile << 6) | (sampling_frequency_index << 2) | 0x2U |
+ (channel_configuration & 0x4U);
+ adts_headers[3] = ((channel_configuration & 0x3U) << 6) | 0x30U |
+ (guint8) (frame_size >> 11);
+ adts_headers[4] = (guint8) ((frame_size >> 3) & 0x00FF);
+ adts_headers[5] = (guint8) (((frame_size & 0x0007) << 5) + 0x1FU);
+ adts_headers[6] = 0xFCU;
+
+ mem = gst_memory_new_wrapped (0, adts_headers, ADTS_HEADERS_LENGTH, 0,
+ ADTS_HEADERS_LENGTH, NULL, NULL);
+ gst_buffer_prepend_memory (frame->out_buffer, mem);
+
+ return TRUE;
+}
/**
* gst_aac_parse_check_valid_frame:
}
}
+ if (aacparse->header_type == DSPAAC_HEADER_NONE
+ && aacparse->output_header_type == DSPAAC_HEADER_ADTS) {
+ if (!gst_aac_parse_prepend_adts_headers (aacparse, frame)) {
+ GST_ERROR_OBJECT (aacparse, "Failed to prepend ADTS headers to frame");
+ ret = GST_FLOW_ERROR;
+ }
+ }
+
exit:
gst_buffer_unmap (buffer, &map);