summaryrefslogtreecommitdiff
path: root/gst/typefind
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.net>2012-11-11 16:33:32 +0000
committerTim-Philipp Müller <tim@centricular.net>2012-11-11 20:08:52 +0000
commit61f04f1460922482cd28e8d22bead8e90dd53431 (patch)
treecdf58b67db8a65df16475e39aa896402f011224c /gst/typefind
parentbccb3feebf303ea51cb6bfa4ee74bc1fb43a6eda (diff)
typefinding: improve AAC LOAS typefinding
Make AAC LOAS typefinding a bit more reliable; don't report a LIKELY probability already after just two sync points, but scan for a few more consecutive frames and determine probability based on how many we found. Fixes mis-detection of wavpack file. https://bugzilla.gnome.org/show_bug.cgi?id=687674
Diffstat (limited to 'gst/typefind')
-rw-r--r--gst/typefind/gsttypefindfunctions.c141
1 files changed, 108 insertions, 33 deletions
diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c
index 8b84dca22..0b749812f 100644
--- a/gst/typefind/gsttypefindfunctions.c
+++ b/gst/typefind/gsttypefindfunctions.c
@@ -845,6 +845,90 @@ flac_type_find (GstTypeFind * tf, gpointer unused)
#endif
}
+/* TODO: we could probably make a generic function for this.. */
+static gint
+aac_type_find_scan_loas_frames_ep (GstTypeFind * tf, DataScanCtx * scan_ctx,
+ gint max_frames)
+{
+ DataScanCtx c = *scan_ctx;
+ guint16 snc;
+ guint len;
+ gint count = 0;
+
+ do {
+ if (!data_scan_ctx_ensure_data (tf, &c, 5))
+ break;
+
+ /* EPAudioSyncStream */
+ len = ((c.data[2] & 0x0f) << 9) | (c.data[3] << 1) |
+ ((c.data[4] & 0x80) >> 7);
+
+ if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) {
+ GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len);
+ break;
+ }
+
+ /* check length of frame */
+ snc = GST_READ_UINT16_BE (c.data + len);
+ if (snc != 0x4de1) {
+ GST_DEBUG ("No sync found at 0x%" G_GINT64_MODIFIER "x", c.offset + len);
+ break;
+ }
+
+ ++count;
+
+ GST_DEBUG ("Found LOAS syncword #%d at offset 0x%" G_GINT64_MODIFIER "x, "
+ "framelen %u", count, c.offset, len);
+
+ data_scan_ctx_advance (tf, &c, len);
+ } while (count < max_frames && (c.offset - scan_ctx->offset) < 64 * 1024);
+
+ GST_DEBUG ("found %d consecutive frames", count);
+ return count;
+}
+
+static gint
+aac_type_find_scan_loas_frames (GstTypeFind * tf, DataScanCtx * scan_ctx,
+ gint max_frames)
+{
+ DataScanCtx c = *scan_ctx;
+ guint16 snc;
+ guint len;
+ gint count = 0;
+
+ do {
+ if (!data_scan_ctx_ensure_data (tf, &c, 3))
+ break;
+
+ /* AudioSyncStream */
+ len = ((c.data[1] & 0x1f) << 8) | c.data[2];
+ /* add size of sync stream header */
+ len += 3;
+
+ if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len)) {
+ GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len);
+ break;
+ }
+
+ /* check length of frame */
+ snc = GST_READ_UINT16_BE (c.data + len);
+ if ((snc & 0xffe0) != 0x56e0) {
+ GST_DEBUG ("No sync found at 0x%" G_GINT64_MODIFIER "x", c.offset + len);
+ break;
+ }
+
+ ++count;
+
+ GST_DEBUG ("Found LOAS syncword #%d at offset 0x%" G_GINT64_MODIFIER "x, "
+ "framelen %u", count, c.offset, len);
+
+ data_scan_ctx_advance (tf, &c, len);
+ } while (count < max_frames && (c.offset - scan_ctx->offset) < 64 * 1024);
+
+ GST_DEBUG ("found %d consecutive frames", count);
+ return count;
+}
+
/*** audio/mpeg version 2, 4 ***/
static GstStaticCaps aac_caps = GST_STATIC_CAPS ("audio/mpeg, "
@@ -854,8 +938,10 @@ static GstStaticCaps aac_caps = GST_STATIC_CAPS ("audio/mpeg, "
static void
aac_type_find (GstTypeFind * tf, gpointer unused)
{
- /* LUT to convert the AudioObjectType from the ADTS header to a string */
DataScanCtx c = { 0, NULL, 0 };
+ GstTypeFindProbability best_probability = GST_TYPE_FIND_NONE;
+ GstCaps *best_caps = NULL;
+ guint best_count = 0;
while (c.offset < AAC_AMOUNT) {
guint snc, len;
@@ -941,45 +1027,29 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
}
GST_DEBUG ("No next frame found... (should have been at 0x%x)", len);
- } else if (G_UNLIKELY (((snc & 0xffe0) == 0x56e0) || (snc == 0x4de1))) {
- /* LOAS frame */
-
- GST_DEBUG ("Found one LOAS syncword at offset 0x%" G_GINT64_MODIFIER
- "x, tracing next...", c.offset);
-
- /* check length of frame for each type of detectable LOAS streams */
- if (snc == 0x4de1) {
- /* EPAudioSyncStream */
- len = ((c.data[2] & 0x0f) << 9) | (c.data[3] << 1) |
- ((c.data[4] & 0x80) >> 7);
- /* add size of EP sync stream header */
- len += 7;
- } else {
- /* AudioSyncStream */
- len = ((c.data[1] & 0x1f) << 8) | c.data[2];
- /* add size of sync stream header */
- len += 3;
- }
+ } else if (G_UNLIKELY ((snc & 0xffe0) == 0x56e0 || snc == 0x4de1)) {
+ gint count;
- if (len == 0 || !data_scan_ctx_ensure_data (tf, &c, len + 2)) {
- GST_DEBUG ("Wrong sync or next frame not within reach, len=%u", len);
- goto next;
- }
+ /* LOAS frame */
+ GST_INFO ("Possible LOAS syncword at offset 0x%" G_GINT64_MODIFIER
+ "x, scanning for more frames...", c.offset);
- /* check if there's a second LOAS frame */
- snc = GST_READ_UINT16_BE (c.data + len);
- if (((snc & 0xffe0) == 0x56e0) || (snc == 0x4de1)) {
- GST_DEBUG ("Found second LOAS syncword at offset 0x%"
- G_GINT64_MODIFIER "x, framelen %u", c.offset, len);
+ if (snc == 0x4de1)
+ count = aac_type_find_scan_loas_frames_ep (tf, &c, 20);
+ else
+ count = aac_type_find_scan_loas_frames (tf, &c, 20);
- gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY, "audio/mpeg",
+ if (count >= 3 && count > best_count) {
+ gst_caps_unref (best_caps);
+ best_caps = gst_caps_new_simple ("audio/mpeg",
"framed", G_TYPE_BOOLEAN, FALSE,
"mpegversion", G_TYPE_INT, 4,
"stream-format", G_TYPE_STRING, "loas", NULL);
- break;
+ best_count = count;
+ best_probability = GST_TYPE_FIND_POSSIBLE - 10 + count * 3;
+ if (best_probability >= GST_TYPE_FIND_LIKELY)
+ break;
}
-
- GST_DEBUG ("No next frame found... (should have been at 0x%x)", len);
} else if (!memcmp (c.data, "ADIF", 4)) {
/* ADIF header */
gst_type_find_suggest_simple (tf, GST_TYPE_FIND_LIKELY, "audio/mpeg",
@@ -992,6 +1062,11 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
data_scan_ctx_advance (tf, &c, 1);
}
+
+ if (best_probability > GST_TYPE_FIND_NONE) {
+ gst_type_find_suggest (tf, best_probability, best_caps);
+ gst_caps_unref (best_caps);
+ }
}
/*** audio/mpeg version 1 ***/