diff --git a/ChangeLog b/ChangeLog index d2ecf69b0e..5d1de3810a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2004-11-07 Ronald S. Bultje + + * configure.ac: + * ext/Makefile.am: + * ext/musepack/Makefile.am: + * ext/musepack/gstmusepackdec.cpp: + * ext/musepack/gstmusepackdec.h: + * ext/musepack/gstmusepackreader.cpp: + * ext/musepack/gstmusepackreader.h: + Add musepack decoder. + * ext/faad/gstfaad.c: (gst_faad_base_init): + Make pad templates static. + * gst/typefind/gsttypefindfunctions.c: (mp3_type_find), + (plugin_init): + Add musepack typefinder, make mp3 typefinding work halfway stream, + which doesn't actually work yet because id3demux doesn't implement + _get_length(). + 2004-11-07 Ronald S. Bultje * ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer), diff --git a/configure.ac b/configure.ac index 11b17ff0d5..a69a2bcd61 100644 --- a/configure.ac +++ b/configure.ac @@ -1359,6 +1359,23 @@ main (int argc, fi ]) +dnl *** musepack *** +translit(dnm, m, l) AM_CONDITIONAL(USE_MUSEPACK, true) +GST_CHECK_FEATURE(MUSEPACK, [musepackdec], musepack, [ + AC_LANG_CPLUSPLUS + OLD_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="-I/usr/include/musepack $CPPFLAGS" + AC_CHECK_HEADER(mpc_dec.h, [ + HAVE_MUSEPACK="yes" + MUSEPACK_LIBS="-lmusepack" + MUSEPACK_CFLAGS="-I/usr/include/musepack" + AC_SUBST(MUSEPACK_CFLAGS) + AC_SUBST(MUSEPACK_LIBS) + ], [HAVE_MUSEPACK="no"]) + CPPFLAGS="$OLD_CPPFLAGS" + AC_LANG_C +]) + dnl *** musicbrainz *** dnl libmusicbrainz <= 2.0.2 has symbol clashes with ffmpeg dnl however, our ffmpeg patch was accepted upstream @@ -1948,6 +1965,7 @@ ext/mikmod/Makefile ext/mpeg2dec/Makefile ext/mpeg2enc/Makefile ext/mplex/Makefile +ext/musepack/Makefile ext/musicbrainz/Makefile ext/nas/Makefile ext/ogg/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index cd9c5ac3fa..311a320933 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -238,6 +238,12 @@ endif #MAS_DIR= #endif +if USE_MUSEPACK +MUSEPACK_DIR=musepack +else +MUSEPACK_DIR= +endif + if USE_MUSICBRAINZ MUSICBRAINZ_DIR=musicbrainz else @@ -399,6 +405,7 @@ SUBDIRS=\ $(MPEG2DEC_DIR) \ $(MPEG2ENC_DIR) \ $(MPLEX_DIR) \ + $(MUSEPACK_DIR) \ $(MUSICBRAINZ_DIR) \ $(OGG_DIR) \ $(PANGO_DIR) \ @@ -458,6 +465,7 @@ DIST_SUBDIRS=\ mpeg2dec \ mpeg2enc \ mplex \ + musepack \ musicbrainz \ nas \ ogg \ diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index 3709f81593..b8f86d22e1 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -367,105 +367,117 @@ static GstStaticCaps mp3_caps = GST_STATIC_CAPS ("audio/mpeg, " static void mp3_type_find (GstTypeFind * tf, gpointer unused) { + guint64 length = gst_type_find_get_length (tf); + gint try; guint8 *data = NULL; - guint size = 0; - guint64 skipped = 0; + guint size; + guint64 skipped; - while (skipped < GST_MP3_TYPEFIND_TRY_SYNC) { - if (size <= 0) { - size = GST_MP3_TYPEFIND_SYNC_SIZE * 2; - do { - size /= 2; - data = gst_type_find_peek (tf, skipped, size); - } while (size > 10 && !data); - if (!data) - break; - } - if (*data == 0xFF) { - guint8 *head_data = NULL; - guint layer, bitrate, samplerate, channels; - guint found = 0; /* number of valid headers found */ - guint64 offset = skipped; + for (try = 0; try < 2; try++) { + guint64 start_off = (try == 0) ? 0 : length / 2; - while (found < GST_MP3_TYPEFIND_TRY_HEADERS) { - guint32 head; - guint length; - guint prev_layer = 0, prev_bitrate = 0, - prev_channels = 0, prev_samplerate = 0; + if (try != 0 && start_off == 0) + return; - if (offset + 4 <= skipped + size) { - head_data = data + offset - skipped; - } else { - head_data = gst_type_find_peek (tf, offset, 4); - } - if (!head_data) + size = 0; + skipped = 0; + while (skipped < GST_MP3_TYPEFIND_TRY_SYNC) { + if (size <= 0) { + size = GST_MP3_TYPEFIND_SYNC_SIZE * 2; + do { + size /= 2; + data = gst_type_find_peek (tf, skipped + start_off, size); + } while (size > 10 && !data); + if (!data) break; - head = GST_READ_UINT32_BE (head_data); - if (!(length = mp3_type_frame_length_from_header (head, &layer, - &channels, &bitrate, &samplerate))) { - GST_LOG ("%d. header at offset %" G_GUINT64_FORMAT - " (0x%X) was not an mp3 header", found + 1, offset, - (guint) offset); - break; - } - if ((prev_layer && prev_layer != layer) || - /* (prev_bitrate && prev_bitrate != bitrate) || <-- VBR */ - (prev_samplerate && prev_samplerate != samplerate) || - (prev_channels && prev_channels != channels)) { - /* this means an invalid property, or a change, which might mean - * that this is not a mp3 but just a random bytestream. It could - * be a freaking funky encoded mp3 though. We'll just not count - * this header*/ - prev_layer = layer; - prev_bitrate = bitrate; - prev_channels = channels; - prev_samplerate = samplerate; - } else { - found++; - GST_LOG ("found %d. header at offset %" G_GUINT64_FORMAT " (0x%X)", - found, offset, (guint) offset); - } - offset += length; } - g_assert (found <= GST_MP3_TYPEFIND_TRY_HEADERS); - if (found == GST_MP3_TYPEFIND_TRY_HEADERS || - (found >= GST_MP3_TYPEFIND_MIN_HEADERS && head_data == NULL)) { - /* we can make a valid guess */ - guint probability = found * GST_TYPE_FIND_MAXIMUM * - (GST_MP3_TYPEFIND_TRY_SYNC - skipped) / - GST_MP3_TYPEFIND_TRY_HEADERS / GST_MP3_TYPEFIND_TRY_SYNC; + if (*data == 0xFF) { + guint8 *head_data = NULL; + guint layer, bitrate, samplerate, channels; + guint found = 0; /* number of valid headers found */ + guint64 offset = skipped; - if (probability < GST_TYPE_FIND_MINIMUM) - probability = GST_TYPE_FIND_MINIMUM; - GST_INFO - ("audio/mpeg calculated %u = %u * %u / %u * (%u - %u) / %u", - probability, GST_TYPE_FIND_MAXIMUM, found, - GST_MP3_TYPEFIND_TRY_HEADERS, GST_MP3_TYPEFIND_TRY_SYNC, skipped, - GST_MP3_TYPEFIND_TRY_SYNC); - /* make sure we're not id3 tagged */ - head_data = gst_type_find_peek (tf, -128, 3); - if (!head_data) { - probability = probability * 4 / 5; - } else if (memcmp (head_data, "TAG", 3) == 0) { - probability = 0; - } - g_assert (probability <= GST_TYPE_FIND_MAXIMUM); - if (probability > 0) { - GstCaps *caps; + while (found < GST_MP3_TYPEFIND_TRY_HEADERS) { + guint32 head; + guint length; + guint prev_layer = 0, prev_bitrate = 0, + prev_channels = 0, prev_samplerate = 0; - g_assert (layer > 0); - caps = gst_caps_copy (MP3_CAPS); - gst_structure_set (gst_caps_get_structure (caps, 0), "layer", - G_TYPE_INT, layer, 0); - gst_type_find_suggest (tf, probability, caps); - gst_caps_free (caps); + if (offset + 4 <= skipped + size) { + head_data = data + offset - skipped; + } else { + head_data = gst_type_find_peek (tf, offset + start_off, 4); + } + if (!head_data) + break; + head = GST_READ_UINT32_BE (head_data); + if (!(length = mp3_type_frame_length_from_header (head, &layer, + &channels, &bitrate, &samplerate))) { + GST_LOG ("%d. header at offset %" G_GUINT64_FORMAT + " (0x%X) was not an mp3 header", found + 1, offset, + (guint) offset); + break; + } + if ((prev_layer && prev_layer != layer) || + /* (prev_bitrate && prev_bitrate != bitrate) || <-- VBR */ + (prev_samplerate && prev_samplerate != samplerate) || + (prev_channels && prev_channels != channels)) { + /* this means an invalid property, or a change, which might mean + * that this is not a mp3 but just a random bytestream. It could + * be a freaking funky encoded mp3 though. We'll just not count + * this header*/ + prev_layer = layer; + prev_bitrate = bitrate; + prev_channels = channels; + prev_samplerate = samplerate; + } else { + found++; + GST_LOG ("found %d. header at offset %" G_GUINT64_FORMAT " (0x%X)", + found, offset, (guint) offset); + } + offset += length; + } + g_assert (found <= GST_MP3_TYPEFIND_TRY_HEADERS); + if (found == GST_MP3_TYPEFIND_TRY_HEADERS || + (found >= GST_MP3_TYPEFIND_MIN_HEADERS && head_data == NULL)) { + /* we can make a valid guess */ + guint probability = found * GST_TYPE_FIND_MAXIMUM * + (GST_MP3_TYPEFIND_TRY_SYNC - skipped) / + GST_MP3_TYPEFIND_TRY_HEADERS / GST_MP3_TYPEFIND_TRY_SYNC; + + if (probability < GST_TYPE_FIND_MINIMUM) + probability = GST_TYPE_FIND_MINIMUM; + probability /= (try + 1); + GST_INFO + ("audio/mpeg calculated %u = %u * %u / %u * (%u - %u) / %u", + probability, GST_TYPE_FIND_MAXIMUM, found, + GST_MP3_TYPEFIND_TRY_HEADERS, GST_MP3_TYPEFIND_TRY_SYNC, skipped, + GST_MP3_TYPEFIND_TRY_SYNC); + /* make sure we're not id3 tagged */ + head_data = gst_type_find_peek (tf, -128, 3); + if (!head_data) { + probability = probability * 4 / 5; + } else if (memcmp (head_data, "TAG", 3) == 0) { + 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, 0); + gst_type_find_suggest (tf, probability, caps); + gst_caps_free (caps); + } + return; } - return; } + data++; + skipped++; + size--; } - data++; - skipped++; - size--; } } @@ -1399,6 +1411,7 @@ plugin_init (GstPlugin * plugin) }; static gchar *mp3_exts[] = { "mp3", "mp2", "mp1", "mpga", NULL }; static gchar *ac3_exts[] = { "ac3", NULL }; + static gchar *musepack_exts[] = { "mpc", NULL }; static gchar *mpeg_sys_exts[] = { "mpe", "mpeg", "mpg", NULL }; static gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL }; static gchar *ogg_exts[] = { "ogg", "ogm", NULL }; @@ -1439,6 +1452,8 @@ plugin_init (GstPlugin * plugin) asf_exts, "\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-musepack", GST_RANK_PRIMARY, + musepack_exts, "MP+", 3, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-au", GST_RANK_MARGINAL, au_exts, ".snd", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY,