mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
Add musepack decoder.
Original commit message from CVS: * 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().
This commit is contained in:
parent
67fb4efc00
commit
75c18f1b4e
4 changed files with 147 additions and 88 deletions
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
||||||
|
2004-11-07 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
|
||||||
|
* 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 <rbultje@ronald.bitfreak.net>
|
2004-11-07 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
|
||||||
* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
|
* ext/ogg/gstoggmux.c: (gst_ogg_mux_next_buffer),
|
||||||
|
|
18
configure.ac
18
configure.ac
|
@ -1359,6 +1359,23 @@ main (int argc,
|
||||||
fi
|
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 *** musicbrainz ***
|
||||||
dnl libmusicbrainz <= 2.0.2 has symbol clashes with ffmpeg
|
dnl libmusicbrainz <= 2.0.2 has symbol clashes with ffmpeg
|
||||||
dnl however, our ffmpeg patch was accepted upstream
|
dnl however, our ffmpeg patch was accepted upstream
|
||||||
|
@ -1948,6 +1965,7 @@ ext/mikmod/Makefile
|
||||||
ext/mpeg2dec/Makefile
|
ext/mpeg2dec/Makefile
|
||||||
ext/mpeg2enc/Makefile
|
ext/mpeg2enc/Makefile
|
||||||
ext/mplex/Makefile
|
ext/mplex/Makefile
|
||||||
|
ext/musepack/Makefile
|
||||||
ext/musicbrainz/Makefile
|
ext/musicbrainz/Makefile
|
||||||
ext/nas/Makefile
|
ext/nas/Makefile
|
||||||
ext/ogg/Makefile
|
ext/ogg/Makefile
|
||||||
|
|
|
@ -238,6 +238,12 @@ endif
|
||||||
#MAS_DIR=
|
#MAS_DIR=
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if USE_MUSEPACK
|
||||||
|
MUSEPACK_DIR=musepack
|
||||||
|
else
|
||||||
|
MUSEPACK_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_MUSICBRAINZ
|
if USE_MUSICBRAINZ
|
||||||
MUSICBRAINZ_DIR=musicbrainz
|
MUSICBRAINZ_DIR=musicbrainz
|
||||||
else
|
else
|
||||||
|
@ -399,6 +405,7 @@ SUBDIRS=\
|
||||||
$(MPEG2DEC_DIR) \
|
$(MPEG2DEC_DIR) \
|
||||||
$(MPEG2ENC_DIR) \
|
$(MPEG2ENC_DIR) \
|
||||||
$(MPLEX_DIR) \
|
$(MPLEX_DIR) \
|
||||||
|
$(MUSEPACK_DIR) \
|
||||||
$(MUSICBRAINZ_DIR) \
|
$(MUSICBRAINZ_DIR) \
|
||||||
$(OGG_DIR) \
|
$(OGG_DIR) \
|
||||||
$(PANGO_DIR) \
|
$(PANGO_DIR) \
|
||||||
|
@ -458,6 +465,7 @@ DIST_SUBDIRS=\
|
||||||
mpeg2dec \
|
mpeg2dec \
|
||||||
mpeg2enc \
|
mpeg2enc \
|
||||||
mplex \
|
mplex \
|
||||||
|
musepack \
|
||||||
musicbrainz \
|
musicbrainz \
|
||||||
nas \
|
nas \
|
||||||
ogg \
|
ogg \
|
||||||
|
|
|
@ -367,105 +367,117 @@ static GstStaticCaps mp3_caps = GST_STATIC_CAPS ("audio/mpeg, "
|
||||||
static void
|
static void
|
||||||
mp3_type_find (GstTypeFind * tf, gpointer unused)
|
mp3_type_find (GstTypeFind * tf, gpointer unused)
|
||||||
{
|
{
|
||||||
|
guint64 length = gst_type_find_get_length (tf);
|
||||||
|
gint try;
|
||||||
guint8 *data = NULL;
|
guint8 *data = NULL;
|
||||||
guint size = 0;
|
guint size;
|
||||||
guint64 skipped = 0;
|
guint64 skipped;
|
||||||
|
|
||||||
while (skipped < GST_MP3_TYPEFIND_TRY_SYNC) {
|
for (try = 0; try < 2; try++) {
|
||||||
if (size <= 0) {
|
guint64 start_off = (try == 0) ? 0 : length / 2;
|
||||||
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;
|
|
||||||
|
|
||||||
while (found < GST_MP3_TYPEFIND_TRY_HEADERS) {
|
if (try != 0 && start_off == 0)
|
||||||
guint32 head;
|
return;
|
||||||
guint length;
|
|
||||||
guint prev_layer = 0, prev_bitrate = 0,
|
|
||||||
prev_channels = 0, prev_samplerate = 0;
|
|
||||||
|
|
||||||
if (offset + 4 <= skipped + size) {
|
size = 0;
|
||||||
head_data = data + offset - skipped;
|
skipped = 0;
|
||||||
} else {
|
while (skipped < GST_MP3_TYPEFIND_TRY_SYNC) {
|
||||||
head_data = gst_type_find_peek (tf, offset, 4);
|
if (size <= 0) {
|
||||||
}
|
size = GST_MP3_TYPEFIND_SYNC_SIZE * 2;
|
||||||
if (!head_data)
|
do {
|
||||||
|
size /= 2;
|
||||||
|
data = gst_type_find_peek (tf, skipped + start_off, size);
|
||||||
|
} while (size > 10 && !data);
|
||||||
|
if (!data)
|
||||||
break;
|
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 (*data == 0xFF) {
|
||||||
if (found == GST_MP3_TYPEFIND_TRY_HEADERS ||
|
guint8 *head_data = NULL;
|
||||||
(found >= GST_MP3_TYPEFIND_MIN_HEADERS && head_data == NULL)) {
|
guint layer, bitrate, samplerate, channels;
|
||||||
/* we can make a valid guess */
|
guint found = 0; /* number of valid headers found */
|
||||||
guint probability = found * GST_TYPE_FIND_MAXIMUM *
|
guint64 offset = skipped;
|
||||||
(GST_MP3_TYPEFIND_TRY_SYNC - skipped) /
|
|
||||||
GST_MP3_TYPEFIND_TRY_HEADERS / GST_MP3_TYPEFIND_TRY_SYNC;
|
|
||||||
|
|
||||||
if (probability < GST_TYPE_FIND_MINIMUM)
|
while (found < GST_MP3_TYPEFIND_TRY_HEADERS) {
|
||||||
probability = GST_TYPE_FIND_MINIMUM;
|
guint32 head;
|
||||||
GST_INFO
|
guint length;
|
||||||
("audio/mpeg calculated %u = %u * %u / %u * (%u - %u) / %u",
|
guint prev_layer = 0, prev_bitrate = 0,
|
||||||
probability, GST_TYPE_FIND_MAXIMUM, found,
|
prev_channels = 0, prev_samplerate = 0;
|
||||||
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);
|
if (offset + 4 <= skipped + size) {
|
||||||
caps = gst_caps_copy (MP3_CAPS);
|
head_data = data + offset - skipped;
|
||||||
gst_structure_set (gst_caps_get_structure (caps, 0), "layer",
|
} else {
|
||||||
G_TYPE_INT, layer, 0);
|
head_data = gst_type_find_peek (tf, offset + start_off, 4);
|
||||||
gst_type_find_suggest (tf, probability, caps);
|
}
|
||||||
gst_caps_free (caps);
|
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 *mp3_exts[] = { "mp3", "mp2", "mp1", "mpga", NULL };
|
||||||
static gchar *ac3_exts[] = { "ac3", 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_sys_exts[] = { "mpe", "mpeg", "mpg", NULL };
|
||||||
static gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL };
|
static gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL };
|
||||||
static gchar *ogg_exts[] = { "ogg", "ogm", NULL };
|
static gchar *ogg_exts[] = { "ogg", "ogm", NULL };
|
||||||
|
@ -1439,6 +1452,8 @@ plugin_init (GstPlugin * plugin)
|
||||||
asf_exts,
|
asf_exts,
|
||||||
"\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16,
|
"\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16,
|
||||||
GST_TYPE_FIND_MAXIMUM);
|
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,
|
TYPE_FIND_REGISTER_START_WITH (plugin, "audio/x-au", GST_RANK_MARGINAL,
|
||||||
au_exts, ".snd", 4, GST_TYPE_FIND_MAXIMUM);
|
au_exts, ".snd", 4, GST_TYPE_FIND_MAXIMUM);
|
||||||
TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY,
|
TYPE_FIND_REGISTER_RIFF (plugin, "video/x-msvideo", GST_RANK_PRIMARY,
|
||||||
|
|
Loading…
Reference in a new issue