pbutils: add AAC profile detection to codec utils

This moves AAC profile detection to pbutils, and uses this in
typefindfunctions. This will also be used in qtdemux.

https://bugzilla.gnome.org/show_bug.cgi?id=617314

API: gst_codec_utils_aac_get_profile()
API: codec_utils_aac_caps_set_level_and_profile()
This commit is contained in:
Arun Raghavan 2010-04-30 15:12:04 +05:30 committed by Tim-Philipp Müller
parent c77f88cac6
commit 0cf81938a1
4 changed files with 97 additions and 26 deletions

View file

@ -34,6 +34,12 @@
#include "pbutils.h"
#define GST_SIMPLE_CAPS_HAS_NAME(caps,name) \
gst_structure_has_name(gst_caps_get_structure((caps),0),(name))
#define GST_SIMPLE_CAPS_HAS_FIELD(caps,field) \
gst_structure_has_field(gst_caps_get_structure((caps),0),(field))
/**
* gst_codec_utils_aac_get_sample_rate_from_index:
* @sr_idx: Sample rate index as from the AudioSpecificConfig (MPEG-4
@ -58,6 +64,50 @@ gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx)
return 0;
}
/**
* gst_codec_utils_aac_get_profile:
* @audio_config: a pointer to the AudioSpecificConfig as specified in the
* Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
* below for a more details).
* @len: Length of @audio_config in bytes
*
* Returns the profile of the given AAC stream as a string. The profile is
* determined using the AudioObjectType field which is in the first 5 bits of
* @audio_config.
*
* <note>
* HE-AAC support has not yet been implemented.
* </note>
*
* Returns: The profile as a const string and NULL if the profile could not be
* determined.
*/
const gchar *
gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len)
{
guint profile;
if (len < 1)
return NULL;
profile = audio_config[0] >> 3;
switch (profile) {
case 1:
return "main";
case 2:
return "lc";
case 3:
return "ssr";
case 4:
return "ltp";
default:
break;
}
GST_DEBUG ("Invalid profile idx: %u", profile);
return NULL;
}
/**
* gst_codec_utils_aac_get_level:
* @audio_config: a pointer to the AudioSpecificConfig as specified in the
@ -246,33 +296,55 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len)
}
/**
* gst_codec_utils_aac_caps_set_level:
* @caps: the #GstCaps to which the level is to be added
* gst_codec_utils_aac_caps_set_level_and_profile:
* @caps: the #GstCaps to which level and profile fields are to be added
* @audio_config: a pointer to the AudioSpecificConfig as specified in the
* Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
* below for a more details).
* @len: Length of @audio_config in bytes
*
* Sets the level in @caps if it can be determined from @audio_config. See
* #gst_codec_utils_aac_get_level() for more details on the parameters.
* Sets the level and profile on @caps if it can be determined from
* @audio_config. See #gst_codec_utils_aac_get_level() and
* gst_codec_utils_aac_get_profile() for more details on the parameters.
* @caps must be audio/mpeg caps with an "mpegversion" field of either 2 or 4.
* If mpegversion is 4, the <tt>base-profile</tt> field is also set in @caps.
*
* Returns: TRUE if the level could be set, FALSE otherwise.
* Returns: TRUE if the level and profile could be set, FALSE otherwise.
*/
gboolean
gst_codec_utils_aac_caps_set_level (GstCaps * caps,
gst_codec_utils_aac_caps_set_level_and_profile (GstCaps * caps,
const guint8 * audio_config, guint len)
{
const gchar *level;
GstStructure *s;
const gchar *level, *profile;
int mpegversion = 0;
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE);
g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_NAME (caps, "audio/mpeg"), FALSE);
g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_FIELD (caps, "mpegversion"), FALSE);
g_return_val_if_fail (audio_config != NULL, FALSE);
s = gst_caps_get_structure (caps, 0);
gst_structure_get_int (s, "mpegversion", &mpegversion);
g_return_val_if_fail (mpegversion == 2 || mpegversion == 4, FALSE);
level = gst_codec_utils_aac_get_level (audio_config, len);
if (!level)
return FALSE;
if (level != NULL)
gst_structure_set (s, "level", G_TYPE_STRING, level, NULL);
gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
profile = gst_codec_utils_aac_get_profile (audio_config, len);
return TRUE;
if (profile != NULL) {
if (mpegversion == 4) {
gst_structure_set (s, "base-profile", G_TYPE_STRING, profile,
"profile", G_TYPE_STRING, profile, NULL);
} else {
gst_structure_set (s, "profile", G_TYPE_STRING, profile, NULL);
}
}
return (level != NULL && profile != NULL);
}

View file

@ -30,12 +30,13 @@ G_BEGIN_DECLS
guint gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx);
const gchar * gst_codec_utils_aac_get_level (const guint8 * audio_config,
guint len);
const gchar * gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len);
gboolean gst_codec_utils_aac_caps_set_level (GstCaps * caps,
const guint8 * audio_config,
guint len);
const gchar * gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len);
gboolean gst_codec_utils_aac_caps_set_level_and_profile (GstCaps * caps,
const guint8 * audio_config,
guint len);
G_END_DECLS

View file

@ -660,7 +660,6 @@ static void
aac_type_find (GstTypeFind * tf, gpointer unused)
{
/* LUT to convert the AudioObjectType from the ADTS header to a string */
static const gchar profile_to_string[][5] = { "main", "lc", "ssr", "ltp" };
DataScanCtx c = { 0, NULL, 0 };
while (c.offset < AAC_AMOUNT) {
@ -693,11 +692,11 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
snc = GST_READ_UINT16_BE (c.data + len);
if ((snc & 0xfff6) == 0xfff0) {
GstCaps *caps;
guint mpegversion, sample_freq_idx, channel_config, profile, rate;
guint mpegversion, sample_freq_idx, channel_config, profile_idx, rate;
guint8 audio_config[2];
mpegversion = (c.data[1] & 0x08) ? 2 : 4;
profile = c.data[2] >> 6;
profile_idx = c.data[2] >> 6;
sample_freq_idx = ((c.data[2] & 0x3c) >> 2);
channel_config = ((c.data[2] & 0x01) << 2) + (c.data[3] >> 6);
@ -713,13 +712,13 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
}
rate = gst_codec_utils_aac_get_sample_rate_from_index (sample_freq_idx);
GST_LOG ("ADTS: profile=%u, rate=%u", profile, rate);
GST_LOG ("ADTS: profile=%u, rate=%u", profile_idx, rate);
/* The ADTS frame header is slightly different from the
* AudioSpecificConfig defined for the MPEG-4 container, so we just
* construct enough of it for getting the level here. */
/* ADTS counts profiles from 0 instead of 1 to save bits */
audio_config[0] = (profile + 1) << 3;
audio_config[0] = (profile_idx + 1) << 3;
audio_config[0] |= (sample_freq_idx >> 1) & 0x7;
audio_config[1] = (sample_freq_idx & 0x1) << 7;
audio_config[1] |= (channel_config & 0xf) << 3;
@ -727,11 +726,9 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
caps = gst_caps_new_simple ("audio/mpeg",
"framed", G_TYPE_BOOLEAN, FALSE,
"mpegversion", G_TYPE_INT, mpegversion,
"stream-type", G_TYPE_STRING, "adts",
"base-profile", G_TYPE_STRING, profile_to_string[profile],
"profile", G_TYPE_STRING, profile_to_string[profile], NULL);
"stream-type", G_TYPE_STRING, "adts", NULL);
gst_codec_utils_aac_caps_set_level (caps, audio_config, 2);
gst_codec_utils_aac_caps_set_level_and_profile (caps, audio_config, 2);
/* add rate and number of channels if we can */
if (channel_config != 0 && channel_config <= 7) {

View file

@ -1,6 +1,7 @@
EXPORTS
gst_codec_utils_aac_caps_set_level
gst_codec_utils_aac_caps_set_level_and_profile
gst_codec_utils_aac_get_level
gst_codec_utils_aac_get_profile
gst_codec_utils_aac_get_sample_rate_from_index
gst_discoverer_audio_info_get_bitrate
gst_discoverer_audio_info_get_channels