diff --git a/gst-libs/gst/pbutils/codec-utils.c b/gst-libs/gst/pbutils/codec-utils.c index 8a2f6c30b2..a8b14fe563 100644 --- a/gst-libs/gst/pbutils/codec-utils.c +++ b/gst-libs/gst/pbutils/codec-utils.c @@ -38,6 +38,7 @@ #include "pbutils.h" #include +#include #include #include @@ -107,6 +108,83 @@ gst_codec_utils_aac_get_index_from_sample_rate (guint rate) return -1; } +static gboolean +gst_codec_utils_aac_get_audio_object_type (GstBitReader * br, + guint8 * audio_object_type) +{ + guint8 aot; + + if (!gst_bit_reader_get_bits_uint8 (br, &aot, 5)) + return FALSE; + + if (aot == 31) { + if (!gst_bit_reader_get_bits_uint8 (br, &aot, 6)) + return FALSE; + aot += 32; + } + + *audio_object_type = aot; + + return TRUE; +} + +static gboolean +gst_codec_utils_aac_get_audio_sample_rate (GstBitReader * br, + guint * sample_rate) +{ + guint8 sampling_freq_index; + guint32 sampling_rate; + + if (!gst_bit_reader_get_bits_uint8 (br, &sampling_freq_index, 4)) + return FALSE; + + if (sampling_freq_index == 0xf) { + if (!gst_bit_reader_get_bits_uint32 (br, &sampling_rate, 24)) + return FALSE; + } else { + sampling_rate = + gst_codec_utils_aac_get_sample_rate_from_index (sampling_freq_index); + if (!sampling_rate) + return FALSE; + } + + *sample_rate = sampling_rate; + + return TRUE; +} + +static gboolean +gst_codec_utils_aac_get_audio_object_type_full (GstBitReader * br, + guint8 * audio_object_type, guint8 * channel_config, guint * sample_rate) +{ + guint8 aot, channels; + guint rate; + + if (!gst_codec_utils_aac_get_audio_object_type (br, &aot)) + return FALSE; + + if (!gst_codec_utils_aac_get_audio_sample_rate (br, &rate)) + return FALSE; + + if (!gst_bit_reader_get_bits_uint8 (br, &channels, 4)) + return FALSE; + + /* 5 indicates SBR extension (i.e. HE-AAC) */ + /* 29 indicates PS extension */ + if (aot == 5 || aot == 29) { + if (!gst_codec_utils_aac_get_audio_sample_rate (br, &rate)) + return FALSE; + if (!gst_codec_utils_aac_get_audio_object_type (br, &aot)) + return FALSE; + } + + *audio_object_type = aot; + *sample_rate = rate; + *channel_config = channels; + + return TRUE; +} + /** * gst_codec_utils_aac_get_sample_rate: * @audio_config: (array length=len): a pointer to the AudioSpecificConfig @@ -124,13 +202,17 @@ gst_codec_utils_aac_get_index_from_sample_rate (guint rate) guint gst_codec_utils_aac_get_sample_rate (const guint8 * audio_config, guint len) { - guint rate_index; + guint sample_rate = 0; + guint8 audio_object_type = 0, channel_config = 0; + GstBitReader br = GST_BIT_READER_INIT (audio_config, len); if (len < 2) return 0; - rate_index = ((audio_config[0] & 0x7) << 1) | ((audio_config[1] & 0x80) >> 7); - return gst_codec_utils_aac_get_sample_rate_from_index (rate_index); + gst_codec_utils_aac_get_audio_object_type_full (&br, &audio_object_type, + &channel_config, &sample_rate); + + return sample_rate; } /** @@ -171,10 +253,8 @@ gst_codec_utils_aac_get_channels (const guint8 * audio_config, guint len) * @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. - * - * > HE-AAC support has not yet been implemented. + * normally determined using the AudioObjectType field which is in the first + * 5 bits of @audio_config * * Returns: The profile as a const string and %NULL if the profile could not be * determined. @@ -182,29 +262,40 @@ gst_codec_utils_aac_get_channels (const guint8 * audio_config, guint len) const gchar * gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len) { - guint profile; + const gchar *profile = NULL; + guint sample_rate; + guint8 audio_object_type, channel_config; + GstBitReader br = GST_BIT_READER_INIT (audio_config, len); if (len < 1) return NULL; GST_MEMDUMP ("audio config", audio_config, len); - profile = audio_config[0] >> 3; - switch (profile) { + if (!gst_codec_utils_aac_get_audio_object_type_full (&br, &audio_object_type, + &channel_config, &sample_rate)) { + return NULL; + } + + switch (audio_object_type) { case 1: - return "main"; + profile = "main"; + break; case 2: - return "lc"; + profile = "lc"; + break; case 3: - return "ssr"; + profile = "ssr"; + break; case 4: - return "ltp"; + profile = "ltp"; + break; default: + GST_DEBUG ("Invalid profile idx: %u", audio_object_type); break; } - GST_DEBUG ("Invalid profile idx: %u", profile); - return NULL; + return profile; } /** @@ -221,21 +312,21 @@ gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len) * The @audio_config parameter follows the following format, starting from the * most significant bit of the first byte: * - * * Bit 0:4 contains the AudioObjectType + * * Bit 0:4 contains the AudioObjectType (if this is 0x5, then the + * real AudioObjectType is carried after the rate and channel data) * * Bit 5:8 contains the sample frequency index (if this is 0xf, then the * next 24 bits define the actual sample frequency, and subsequent * fields are appropriately shifted). * * Bit 9:12 contains the channel configuration * - * > HE-AAC support has not yet been implemented. - * * Returns: The level as a const string and %NULL if the level could not be * determined. */ const gchar * gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) { - int profile, sr_idx, channel_config, rate; + guint8 audio_object_type = 0xFF, channel_config = 0xFF; + guint rate; /* Number of single channel elements, channel pair elements, low frequency * elements, independently switched coupling channel elements, and * dependently switched coupling channel elements. @@ -247,8 +338,9 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) int num_channels; /* Processor and RAM Complexity Units (calculated and "reference" for single * channel) */ - int pcu, rcu, pcu_ref, rcu_ref; + int pcu = -1, rcu = -1, pcu_ref, rcu_ref; int ret = -1; + GstBitReader br = GST_BIT_READER_INIT (audio_config, len); g_return_val_if_fail (audio_config != NULL, NULL); @@ -257,14 +349,10 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) GST_MEMDUMP ("audio config", audio_config, len); - profile = audio_config[0] >> 3; - /* FIXME: add support for sr_idx = 0xf */ - sr_idx = ((audio_config[0] & 0x7) << 1) | ((audio_config[1] & 0x80) >> 7); - rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx); - channel_config = (audio_config[1] & 0x7f) >> 3; - - if (rate == 0) + if (!gst_codec_utils_aac_get_audio_object_type_full (&br, &audio_object_type, + &channel_config, &rate)) { return NULL; + } switch (channel_config) { case 0: @@ -322,7 +410,7 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) return NULL; } - switch (profile) { + switch (audio_object_type) { case 0: /* NULL */ GST_WARNING ("profile 0 is not a valid profile"); return NULL; @@ -362,7 +450,7 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) num_channels = num_sce + (2 * num_cpe) + num_lfe; - if (profile == 2) { + if (audio_object_type == 2) { /* AAC LC => return the level as per the 'AAC Profile' */ if (num_channels <= 2 && rate <= 24000 && pcu <= 3 && rcu <= 5) ret = 1; @@ -391,8 +479,8 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len) if (ret == -1) { GST_WARNING ("couldn't determine level: profile=%u, rate=%u, " - "channel_config=%u, pcu=%d,rcu=%d", profile, rate, channel_config, pcu, - rcu); + "channel_config=%u, pcu=%d,rcu=%d", audio_object_type, rate, + channel_config, pcu, rcu); return NULL; } else { return digit_to_string (ret); diff --git a/tests/check/libs/pbutils.c b/tests/check/libs/pbutils.c index 856b71e048..ac5aeb5f6e 100644 --- a/tests/check/libs/pbutils.c +++ b/tests/check/libs/pbutils.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -803,6 +804,69 @@ GST_START_TEST (test_pb_utils_versions) GST_END_TEST; +GST_START_TEST (test_pb_utils_aac_get_profile) +{ + const guint8 aac_config[] = { 0x11, 0x90, 0x56, 0xE5, 0x00 }; + const guint8 aac_config_sre[] = { 0x17, 0x80, 0x91, 0xA2, 0x82, 0x00 }; + const guint8 heaac_config[] = { 0x2B, 0x11, 0x88, 0x00, 0x06, 0x01, 0x02 }; + const gchar *profile, *level; + guint sample_rate; + GstBitWriter *wr; + guint8 *buf; + guint buf_len; + + profile = gst_codec_utils_aac_get_profile (aac_config, sizeof (aac_config)); + fail_unless (profile != NULL); + fail_unless_equals_string (profile, "lc"); + + level = gst_codec_utils_aac_get_level (aac_config, sizeof (aac_config)); + fail_unless_equals_string (level, "2"); + + sample_rate = + gst_codec_utils_aac_get_sample_rate (aac_config, sizeof (aac_config)); + fail_unless_equals_int (sample_rate, 48000); + + sample_rate = + gst_codec_utils_aac_get_sample_rate (aac_config_sre, + sizeof (aac_config_sre)); + fail_unless_equals_int (sample_rate, 0x12345); + + profile = + gst_codec_utils_aac_get_profile (heaac_config, sizeof (heaac_config)); + fail_unless (profile != NULL); + fail_unless_equals_string (profile, "lc"); + + level = gst_codec_utils_aac_get_level (heaac_config, sizeof (heaac_config)); + fail_unless_equals_string (level, "2"); + + sample_rate = + gst_codec_utils_aac_get_sample_rate (heaac_config, sizeof (heaac_config)); + fail_unless_equals_int (sample_rate, 48000); + + wr = gst_bit_writer_new (); + fail_if (wr == NULL); + gst_bit_writer_put_bits_uint8 (wr, 5, 5); /* object_type = 5 (SBR) */ + gst_bit_writer_put_bits_uint8 (wr, 3, 4); /* freq_index = 3 (48KHz) */ + gst_bit_writer_put_bits_uint8 (wr, 2, 4); /* channel_config = 2 (L&R) */ + gst_bit_writer_put_bits_uint8 (wr, 0x0f, 4); /* freq_index extension */ + gst_bit_writer_put_bits_uint32 (wr, 87654, 24); /* freq */ + gst_bit_writer_put_bits_uint8 (wr, 2, 5); /* object_type = 2 (LC) */ + + buf = gst_bit_writer_get_data (wr); + buf_len = gst_bit_writer_get_size (wr); + profile = gst_codec_utils_aac_get_profile (buf, buf_len); + fail_unless (profile != NULL); + fail_unless_equals_string (profile, "lc"); + level = gst_codec_utils_aac_get_level (buf, buf_len); + fail_unless (level != NULL); + fail_unless_equals_string (level, "5"); + sample_rate = gst_codec_utils_aac_get_sample_rate (buf, buf_len); + fail_unless_equals_int (sample_rate, 87654); + gst_bit_writer_free (wr); +} + +GST_END_TEST; + static Suite * libgstpbutils_suite (void) { @@ -817,6 +881,7 @@ libgstpbutils_suite (void) tcase_add_test (tc_chain, test_pb_utils_install_plugins); tcase_add_test (tc_chain, test_pb_utils_installer_details); tcase_add_test (tc_chain, test_pb_utils_versions); + tcase_add_test (tc_chain, test_pb_utils_aac_get_profile); return s; }