gst/typefind/gsttypefindfunctions.c: Refactor mpeg/audio typefinding to make it more maintainable and easier to fine-...

Original commit message from CVS:
* gst/typefind/gsttypefindfunctions.c: (mp3_type_find_at_offset),
(mp3_type_find):
Refactor mpeg/audio typefinding to make it more maintainable
and easier to fine-tune. Make probing into middle of the file
work properly (fixes #333900, also see #152688).
This commit is contained in:
Tim-Philipp Müller 2006-03-09 12:37:59 +00:00
parent 7aff0dfe96
commit 2bd6096768
2 changed files with 189 additions and 136 deletions

View file

@ -1,3 +1,11 @@
2006-03-09 Tim-Philipp Müller <tim at centricular dot net>
* gst/typefind/gsttypefindfunctions.c: (mp3_type_find_at_offset),
(mp3_type_find):
Refactor mpeg/audio typefinding to make it more maintainable
and easier to fine-tune. Make probing into middle of the file
work properly (fixes #333900, also see #152688).
2006-03-09 Tim-Philipp Müller <tim at centricular dot net>
* gst/typefind/gsttypefindfunctions.c:

View file

@ -582,20 +582,17 @@ static GstStaticCaps mp3_caps = GST_STATIC_CAPS ("audio/mpeg, "
#define GST_MP3_TYPEFIND_SYNC_SIZE (2048)
static void
mp3_type_find (GstTypeFind * tf, gpointer unused)
mp3_type_find_at_offset (GstTypeFind * tf, guint64 start_off,
guint * found_layer, GstTypeFindProbability * found_prob)
{
guint64 length = gst_type_find_get_length (tf);
gint try;
guint8 *data = NULL;
guint size;
guint64 skipped;
gint last_free_offset = -1;
gint last_free_framelen = -1;
for (try = 0; try < 2; try++) {
gint last_free_offset = -1, last_free_framelen = -1;
guint64 start_off = (try == 0) ? 0 : length / 2;
if (try != 0 && start_off == 0)
break;
*found_layer = 0;
*found_prob = 0;
size = 0;
skipped = 0;
@ -618,8 +615,8 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
while (found < GST_MP3_TYPEFIND_TRY_HEADERS) {
guint32 head;
guint length;
guint prev_layer = 0, prev_bitrate = 0,
prev_channels = 0, prev_samplerate = 0;
guint prev_layer = 0, prev_bitrate = 0;
guint prev_channels = 0, prev_samplerate = 0;
gboolean free = FALSE;
if (offset + 4 <= skipped + size) {
@ -646,8 +643,9 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
}
GST_LOG ("%d. header at offset %" G_GUINT64_FORMAT
" (0x%X) was not an mp3 header (possibly-free: %s)",
found + 1, offset, (guint) offset, free ? "yes" : "no");
" (0x%" G_GINT64_MODIFIER "x) was not an mp3 header "
"(possibly-free: %s)", found + 1, start_off + offset,
start_off + offset, free ? "yes" : "no");
break;
}
if ((prev_layer && prev_layer != layer) ||
@ -664,8 +662,9 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
prev_samplerate = samplerate;
} else {
found++;
GST_LOG ("found %d. header at offset %" G_GUINT64_FORMAT " (0x%X)",
found, offset, (guint) offset);
GST_LOG ("found %d. header at offset %" G_GUINT64_FORMAT " (0x%"
G_GINT64_MODIFIER "X)", found, start_off + offset,
start_off + offset);
}
offset += length;
}
@ -679,7 +678,9 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
if (probability < GST_TYPE_FIND_MINIMUM)
probability = GST_TYPE_FIND_MINIMUM;
probability /= (try + 1);
if (start_off > 0)
probability /= 2;
GST_INFO
("audio/mpeg calculated %u = %u * %u / %u * (%u - %u) / %u",
probability, GST_TYPE_FIND_MAXIMUM, found,
@ -693,43 +694,87 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
probability = 0;
}
g_assert (probability <= GST_TYPE_FIND_MAXIMUM);
if (probability > 0) {
GstCaps *caps;
g_assert (layer > 0);
caps = gst_caps_copy (MP3_CAPS);
gst_structure_set (gst_caps_get_structure (caps, 0), "layer",
G_TYPE_INT, layer, NULL);
gst_type_find_suggest (tf, probability, caps);
gst_caps_unref (caps);
*found_prob = probability;
if (probability > 0)
*found_layer = layer;
return;
}
goto no_luck;
}
}
data++;
skipped++;
size--;
}
}
static void
mp3_type_find (GstTypeFind * tf, gpointer unused)
{
GstTypeFindProbability prob, mid_prob;
guint8 *data;
guint layer, mid_layer;
guint64 length;
mp3_type_find_at_offset (tf, 0, &layer, &prob);
length = gst_type_find_get_length (tf);
if (length == 0 || length == (guint64) - 1) {
if (prob != 0)
goto suggest;
return;
}
no_luck:
/* if we're pretty certain already, skip the additional check */
if (prob >= GST_TYPE_FIND_LIKELY)
goto suggest;
/* no luck so far, let's see if there's a valid header right at the start */
mp3_type_find_at_offset (tf, length / 2, &mid_layer, &mid_prob);
if (mid_prob > 0) {
if (prob == 0) {
GST_LOG ("detected audio/mpeg only in the middle (p=%u)", mid_prob);
layer = mid_layer;
prob = mid_prob;
goto suggest;
}
if (layer != mid_layer) {
GST_WARNING ("audio/mpeg layer discrepancy: %u vs. %u", layer, mid_layer);
return; /* FIXME: or should we just go with the one in the middle? */
}
/* detected mpeg audio both in middle of the file and at the start */
prob = (prob + mid_prob) / 2;
goto suggest;
}
/* let's see if there's a valid header right at the start */
data = gst_type_find_peek (tf, 0, 4); /* use min. frame size? */
if (data) {
GstCaps *caps;
guint layer;
if (mp3_type_frame_length_from_header (GST_READ_UINT32_BE (data),
if (data && mp3_type_frame_length_from_header (GST_READ_UINT32_BE (data),
&layer, NULL, NULL, NULL, NULL, 0) != 0) {
caps = gst_caps_copy (MP3_CAPS);
if (prob == 0)
prob = GST_TYPE_FIND_POSSIBLE - 10;
else
prob = MAX (GST_TYPE_FIND_POSSIBLE - 10, prob + 10);
}
if (prob > 0)
goto suggest;
return;
suggest:
{
GstCaps *caps;
g_assert (layer > 0);
caps = gst_caps_make_writable (MP3_CAPS);
gst_structure_set (gst_caps_get_structure (caps, 0), "layer",
G_TYPE_INT, layer, NULL);
GST_LOG ("possible mpeg audio layer %u frame at offset 0", layer);
gst_type_find_suggest (tf, GST_TYPE_FIND_POSSIBLE - 10, caps);
gst_type_find_suggest (tf, prob, caps);
gst_caps_unref (caps);
}
return;
}
}