From 0ea59b7a7b442ce721db4dfa129cccfdb37575be Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Wed, 1 Oct 2003 13:14:51 +0000 Subject: [PATCH] New typefind system: bytestream is now part of the core all plugins have been modified to use this new typefind syste... Original commit message from CVS: New typefind system: * bytestream is now part of the core * all plugins have been modified to use this new typefind system * asf typefinding added * mpeg video stream typefiding removed because it's broken * duplicate typefind entries removed * extra id3 typefinding added, because we've seen 4 types of files (riff/wav, flac, vorbis, mp3) with id3 headers and each of these needs to work. Instead, I've added an id3 element and let it redo typefiding after the id3 header. this needs a hack because spider only typefinds once. We can remove this hack once spider supports multiple typefinds. * with all this, mp3 typefinding is semi-rewritten * id3 typefinding in flac/vorbis is removed, it's no longer needed * fixed spider and gst-typefind to use this, too. * Other general cleanups --- configure.ac | 3 +- ext/Makefile.am | 5 +- ext/a52dec/gsta52dec.c | 4 - ext/a52dec/gsta52dec.h | 2 +- ext/mad/gstmad.c | 7 +- gst/asfdemux/gstasfdemux.c | 149 +++---------- gst/asfdemux/gstasfdemux.h | 2 +- gst/asfdemux/gstasfmux.c | 19 +- gst/mpegaudioparse/Makefile.am | 10 +- gst/mpegaudioparse/gstmp3types.c | 251 --------------------- gst/mpegaudioparse/gstmpegaudioparse.c | 288 ++++++++++++++++++++----- gst/mpegstream/gstmpegdemux.c | 4 - gst/mpegstream/gstmpegpacketize.h | 2 +- gst/mpegstream/gstmpegparse.c | 4 - gst/mpegstream/gstmpegparse.h | 2 +- gst/mpegstream/gstmpegstream.c | 4 - gst/mpegstream/gstrfc2250enc.c | 4 - gst/mpegstream/gstrfc2250enc.h | 2 +- gst/realmedia/rmdemux.c | 32 +-- gst/realmedia/rmdemux.h | 2 +- 20 files changed, 312 insertions(+), 484 deletions(-) delete mode 100644 gst/mpegaudioparse/gstmp3types.c diff --git a/configure.ac b/configure.ac index bf0338ee8c..5bcb93ac67 100644 --- a/configure.ac +++ b/configure.ac @@ -262,7 +262,7 @@ GST_PLUGINS_ALL="\ ac3parse adder audioscale auparse avi \ asfdemux audioconvert cdxaparse chart \ cutter debug deinterlace effectv festival \ - filter flx goom intfloat law level median mixmatrix \ + filter flx goom id3 intfloat law level median mixmatrix \ mpeg1sys mpeg1videoparse mpeg2enc mpeg2sub \ mpegaudio mpegaudioparse mpegstream mpegtypes \ monoscope oneton overlay passthrough playondemand qtdemux \ @@ -1180,6 +1180,7 @@ gst/festival/Makefile gst/filter/Makefile gst/flx/Makefile gst/goom/Makefile +gst/id3/Makefile gst/intfloat/Makefile gst/law/Makefile gst/level/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index 2b1ab6eca2..66346eaceb 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -278,8 +278,9 @@ SUBDIRS=$(A52DEC_DIR) $(AALIB_DIR) $(ALSA_DIR) \ $(ARTS_DIR) $(ARTSC_DIR) $(AUDIOFILE_DIR) \ $(CDPARANOIA_DIR) $(DIVX_DIR) \ $(DVDREAD_DIR) $(DVDNAV_DIR) $(ESD_DIR) $(MAS_DIR) \ - $(FFMPEG_DIR) $(FLAC_DIR) $(GDK_PIXBUF_DIR) $(GNOMEVFS_DIR) $(GSM_DIR) \ - $(HERMES_DIR) $(JACK_DIR) $(JPEG_DIR) \ + $(FFMPEG_DIR) $(FLAC_DIR) $(GDK_PIXBUF_DIR) \ + $(GNOMEVFS_DIR) $(GSM_DIR) $(HERMES_DIR) \ + $(JACK_DIR) $(JPEG_DIR) \ $(LADSPA_DIR) $(LAME_DIR) $(LCS_DIR) \ $(LIBDV_DIR) $(LIBFAME_DIR) $(LIBPNG_DIR) \ $(MAD_DIR) $(MATROSKA_DIR) $(MIKMOD_DIR) \ diff --git a/ext/a52dec/gsta52dec.c b/ext/a52dec/gsta52dec.c index 7a92c55075..a3f5be0c4c 100644 --- a/ext/a52dec/gsta52dec.c +++ b/ext/a52dec/gsta52dec.c @@ -619,10 +619,6 @@ plugin_init (GModule * module, GstPlugin * plugin) { GstElementFactory *factory; - /* this filter needs the bytestream package */ - if (!gst_library_load ("gstbytestream")) - return FALSE; - /* create an elementfactory for the a52dec element */ factory = gst_element_factory_new ("a52dec", GST_TYPE_A52DEC, &gst_a52dec_details); g_return_val_if_fail (factory != NULL, FALSE); diff --git a/ext/a52dec/gsta52dec.h b/ext/a52dec/gsta52dec.h index 4cffd90808..6d00ca0740 100644 --- a/ext/a52dec/gsta52dec.h +++ b/ext/a52dec/gsta52dec.h @@ -23,7 +23,7 @@ #include #include -#include +#include G_BEGIN_DECLS diff --git a/ext/mad/gstmad.c b/ext/mad/gstmad.c index 354c864f0f..41e61e1220 100644 --- a/ext/mad/gstmad.c +++ b/ext/mad/gstmad.c @@ -139,6 +139,7 @@ GST_PAD_TEMPLATE_FACTORY (mad_sink_template_factory, "mad_sink", "audio/mpeg", /* we don't need channel/rate ... */ + "mpegversion", GST_PROPS_INT (1), "layer", GST_PROPS_INT_RANGE (1, 3) ) ) @@ -1184,15 +1185,13 @@ gst_mad_chain (GstPad *pad, GstBuffer *buffer) mad->stream.bufend - mad->stream.this_frame); if (tagsize > mad->tempsize) { - GST_INFO ( - "mad: got partial id3 tag in buffer, skipping"); + GST_INFO ("mad: got partial id3 tag in buffer, skipping"); } else if (tagsize > 0) { struct id3_tag *tag; id3_byte_t const *data; - GST_INFO ( - "mad: got ID3 tag size %ld", tagsize); + GST_INFO ("mad: got ID3 tag size %ld", tagsize); data = mad->stream.this_frame; diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c index 5abe5744e9..5788e28a0d 100644 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -35,123 +35,41 @@ static GstElementDetails gst_asf_demux_details = { "(C) 2002", }; -static GstCaps* asf_asf_type_find (GstBuffer *buf, gpointer private); -static GstCaps* asf_wma_type_find (GstBuffer *buf, gpointer private); -static GstCaps* asf_wax_type_find (GstBuffer *buf, gpointer private); -static GstCaps* asf_wmv_type_find (GstBuffer *buf, gpointer private); -static GstCaps* asf_wvx_type_find (GstBuffer *buf, gpointer private); -static GstCaps* asf_wm_type_find (GstBuffer *buf, gpointer private); +static GstCaps* asf_type_find (GstByteStream *bs, gpointer private); /* typefactory for 'asf' */ -static GstTypeDefinition asf_type_definitions[] = { - { "asfdemux_video/asf", - "video/x-ms-asf", - ".asf .asx", - asf_asf_type_find }, - { "asfdemux_video/wma", - "video/x-ms-wma", - ".wma", - asf_wma_type_find }, - { "asfdemux_video/wax", - "video/x-ms-wax", - ".wax", - asf_wax_type_find }, - { "asfdemux_video/wmv", - "video/x-ms-wmv", - ".wmv", - asf_wmv_type_find }, - { "asfdemux_video/wvx", - "video/x-ms-wvx", - ".wvx", - asf_wvx_type_find }, - { "asfdemux_video/wm", - "video/x-ms-wm", - ".wm", - asf_wm_type_find }, - { NULL, NULL, NULL, NULL } +static GstTypeDefinition asf_type_definition = { + "asfdemux_video/asf", + "video/x-ms-asf", + /* note: asx/wax/wmx are XML files, we don't handle them */ + ".asf .wma .wmv .wm", + asf_type_find, }; static GstCaps* -asf_asf_type_find (GstBuffer *buf, gpointer private) +asf_type_find (GstByteStream *bs, gpointer private) { - GstCaps *new; + GstCaps *new = NULL; + GstBuffer *buf = NULL; - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); - return new; -} + if (gst_bytestream_peek (bs, &buf, 16) == 16) { + guint32 uid1 = GUINT32_FROM_LE (((guint32 *) GST_BUFFER_DATA (buf))[0]), + uid2 = GUINT32_FROM_LE (((guint32 *) GST_BUFFER_DATA (buf))[1]), + uid3 = GUINT32_FROM_LE (((guint32 *) GST_BUFFER_DATA (buf))[2]), + uid4 = GUINT32_FROM_LE (((guint32 *) GST_BUFFER_DATA (buf))[3]); -static GstCaps* -asf_wma_type_find (GstBuffer *buf, gpointer private) -{ - GstCaps *new; + if (uid1 == 0x75B22630 && uid2 == 0x11CF668E && + uid3 == 0xAA00D9A6 && uid4 == 0x6CCE6200) { + new = GST_CAPS_NEW ("asf_type_find", + "video/x-ms-asf", + NULL); + } + } - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); - return new; -} + if (buf != NULL) { + gst_buffer_unref (buf); + } -static GstCaps* -asf_wax_type_find (GstBuffer *buf, gpointer private) -{ - GstCaps *new; - - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); - return new; -} - -static GstCaps* -asf_wmv_type_find (GstBuffer *buf, gpointer private) -{ - GstCaps *new; - - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); - return new; -} - -static GstCaps* -asf_wvx_type_find (GstBuffer *buf, gpointer private) -{ - GstCaps *new; - - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); - return new; -} - -static GstCaps* -asf_wm_type_find (GstBuffer *buf, gpointer private) -{ - GstCaps *new; - - new = gst_caps_new ( - "asf_type_find", - "video/x-ms-asf", - gst_props_new ("asfversion", - GST_PROPS_INT (1), - NULL)); return new; } @@ -1644,6 +1562,7 @@ static gboolean plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; + GstTypeFactory *type; gint i = 0; GstCaps *audcaps = NULL, *vidcaps = NULL, *temp; guint32 vid_list[] = { @@ -1670,23 +1589,13 @@ plugin_init (GModule *module, GstPlugin *plugin) -1 /* end */ }; - /* this filter needs bytestream */ - if (!gst_library_load ("gstbytestream")) { - GST_INFO ("asfdemux: could not load support library: 'gstbytestream'\n"); - return FALSE; - } - /* create an elementfactory for the asf_demux element */ factory = gst_element_factory_new ("asfdemux",GST_TYPE_ASF_DEMUX, &gst_asf_demux_details); - while (asf_type_definitions[i].name) { - GstTypeFactory *type; - - type = gst_type_factory_new (&asf_type_definitions[i]); - //gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); - i++; - } + /* type finding */ + type = gst_type_factory_new (&asf_type_definition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); g_return_val_if_fail (factory != NULL, FALSE); gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_NONE); diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h index a38b8be1e7..778b1995a7 100644 --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "asfheaders.h" G_BEGIN_DECLS diff --git a/gst/asfdemux/gstasfmux.c b/gst/asfdemux/gstasfmux.c index e44efbd0a4..90b9d1637f 100644 --- a/gst/asfdemux/gstasfmux.c +++ b/gst/asfdemux/gstasfmux.c @@ -414,6 +414,7 @@ gst_asfmux_vidsinkconnect (GstPad *pad, GstCaps *vscaps) return GST_PAD_LINK_REFUSED; done: + stream->bitrate = 1024 * 1024; stream->header.video.format.size = stream->header.video.stream.size; stream->header.video.format.width = stream->header.video.stream.width; stream->header.video.format.height = stream->header.video.stream.height; @@ -465,7 +466,6 @@ gst_asfmux_audsinkconnect (GstPad *pad, GstCaps *vscaps) stream->header.audio.sample_rate = rate; stream->header.audio.channels = channels; - stream->bitrate = 0; /* TODO */ if (!strcmp (mimetype, "audio/x-raw-int")) { gint block, size; @@ -507,7 +507,7 @@ gst_asfmux_audsinkconnect (GstPad *pad, GstCaps *vscaps) } stream->header.audio.block_align = 1; - stream->header.audio.byte_rate = 0; + stream->header.audio.byte_rate = 8 * 1024; stream->header.audio.word_size = 16; stream->header.audio.size = 0; @@ -521,6 +521,7 @@ gst_asfmux_audsinkconnect (GstPad *pad, GstCaps *vscaps) return GST_PAD_LINK_REFUSED; done: + stream->bitrate = stream->header.audio.byte_rate * 8; return GST_PAD_LINK_OK; } @@ -632,9 +633,11 @@ gst_asfmux_can_seek (GstAsfMux *asfmux) const GstEventMask *masks = gst_pad_get_event_masks (GST_PAD_PEER (asfmux->srcpad)); /* this is for stream or file-storage */ - while (masks->type != 0) { + while (masks != NULL && masks->type != 0) { if (masks->type == GST_EVENT_SEEK) { return TRUE; + } else { + masks++; } } @@ -724,7 +727,7 @@ gst_asfmux_put_buffer (GstBuffer *packet, guint8 *data, guint length) { - if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) > length) { + if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) >= length) { guint8 *pos = GST_BUFFER_DATA (packet) + GST_BUFFER_SIZE (packet); memcpy (pos, data, length); GST_BUFFER_SIZE (packet) += length; @@ -737,7 +740,7 @@ static void gst_asfmux_put_byte (GstBuffer *packet, guint8 data) { - if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) > sizeof (data)) { + if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) >= sizeof (data)) { guint8 *pos = GST_BUFFER_DATA (packet) + GST_BUFFER_SIZE (packet); * (guint8 *) pos = data; GST_BUFFER_SIZE (packet) += 1; @@ -750,7 +753,7 @@ static void gst_asfmux_put_le16 (GstBuffer *packet, guint16 data) { - if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) > sizeof (data)) { + if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) >= sizeof (data)) { guint8 *pos = GST_BUFFER_DATA (packet) + GST_BUFFER_SIZE (packet); * (guint16 *) pos = GUINT16_TO_LE (data); GST_BUFFER_SIZE (packet) += 2; @@ -763,7 +766,7 @@ static void gst_asfmux_put_le32 (GstBuffer *packet, guint32 data) { - if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) > sizeof (data)) { + if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) >= sizeof (data)) { guint8 *pos = GST_BUFFER_DATA (packet) + GST_BUFFER_SIZE (packet); * (guint32 *) pos = GUINT32_TO_LE (data); GST_BUFFER_SIZE (packet) += 4; @@ -776,7 +779,7 @@ static void gst_asfmux_put_le64 (GstBuffer *packet, guint64 data) { - if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) > sizeof (data)) { + if ((GST_BUFFER_MAXSIZE (packet) - GST_BUFFER_SIZE (packet)) >= sizeof (data)) { guint8 *pos = GST_BUFFER_DATA (packet) + GST_BUFFER_SIZE (packet); * (guint64 *) pos = GUINT64_TO_LE (data); GST_BUFFER_SIZE (packet) += 8; diff --git a/gst/mpegaudioparse/Makefile.am b/gst/mpegaudioparse/Makefile.am index ee22c43e37..cb06727fd6 100644 --- a/gst/mpegaudioparse/Makefile.am +++ b/gst/mpegaudioparse/Makefile.am @@ -1,17 +1,9 @@ -#FIXME clean me up a bit - -plugin_LTLIBRARIES = libgstmpegaudioparse.la libgstmp3types.la +plugin_LTLIBRARIES = libgstmpegaudioparse.la libgstmpegaudioparse_la_SOURCES = gstmpegaudioparse.c libgstmpegaudioparse_la_CFLAGS = $(GST_CFLAGS) libgstmpegaudioparse_la_LIBADD = libgstmpegaudioparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstmp3types_la_SOURCES = gstmp3types.c -libgstmp3types_la_CFLAGS = $(GST_CFLAGS) -libgstmp3types_la_LIBADD = -libgstmp3types_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) - noinst_HEADERS = gstmpegaudioparse.h EXTRA_DIST = README - diff --git a/gst/mpegaudioparse/gstmp3types.c b/gst/mpegaudioparse/gstmp3types.c deleted file mode 100644 index cf5e860ffd..0000000000 --- a/gst/mpegaudioparse/gstmp3types.c +++ /dev/null @@ -1,251 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/*#define DEBUG_ENABLED */ -#include -#include /* memcmp */ - -static GstCaps* mp3_type_find(GstBuffer *buf, gpointer private); -static GstCaps* mp3_type_find_stream(GstBuffer *buf, gpointer private); - -static GstTypeDefinition mp3type_definitions[] = { - { "mp3types_audio/mpeg", "audio/mpeg", ".mp3 .mp2 .mp1 .mpga", mp3_type_find }, - { "mp3types_stream_audio/mpeg", "audio/mpeg", ".mp3 .mp2 .mp1 .mpga", mp3_type_find_stream }, - { NULL, NULL, NULL, NULL }, -}; - -static GstCaps* -mp3_type_find(GstBuffer *buf, gpointer private) -{ - guint8 *data; - gint size, layer; - guint32 head; - GstCaps *caps; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - GST_DEBUG ("mp3typefind: typefind"); - - /* gracefully ripped from libid3 */ - if (size >= 3 && - data[0] == 'T' && data[1] == 'A' && data[2] == 'G') { - /* ID V1 tags */ - data += 128; - size -= 128; - - GST_DEBUG ("mp3typefind: detected ID3 Tag V1"); - } else if (size >= 10 && - (data[0] == 'I' && data[1] == 'D' && data[2] == '3') && - data[3] < 0xff && data[4] < 0xff && - data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) - { - guint32 skip = 0; - - skip = (skip << 7) | (data[6] & 0x7f); - skip = (skip << 7) | (data[7] & 0x7f); - skip = (skip << 7) | (data[8] & 0x7f); - skip = (skip << 7) | (data[9] & 0x7f); - - /* include size of header */ - skip += 10; - /* footer present? (only available since version 4) */ - if (data[3] > 3 && (data[5] & 0x10)) - skip += 10; - - GST_DEBUG ("mp3typefind: detected ID3 Tag V2 with %u bytes", skip); - size -= skip; - data += skip; - } - - if (size < 4) - return NULL; - - /* now with the right postion, do typefinding */ - head = GUINT32_FROM_BE(*((guint32 *)data)); - if ((head & 0xffe00000) != 0xffe00000) - return NULL; - if (!(layer = ((head >> 17) & 3))) - return NULL; - layer = 4 - layer; - if (((head >> 12) & 0xf) == 0xf) - return NULL; - if (!((head >> 12) & 0xf)) - return NULL; - if (((head >> 10) & 0x3) == 0x3) - return NULL; - - caps = GST_CAPS_NEW ("mp3_type_find", "audio/mpeg", "layer", GST_PROPS_INT (layer)); - - return caps; -} -static guint mp3types_bitrates[2][3][16] = -{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, }, - {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, }, - {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } }, - { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, }, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, }, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } }, -}; -static guint mp3types_freqs[3][3] = -{ {44100, 48000, 32000}, - {22050, 24000, 16000}, - {11025, 12000, 8000}}; -static inline guint -mp3_type_frame_length_from_header (guint32 header, guint *put_layer) -{ - guint length; - gulong samplerate, bitrate, layer, version; - - /* we don't need extension, mode, copyright, original or emphasis for the frame length */ - header >>= 9; - /* padding */ - length = header & 0x1; - header >>= 1; - /* sampling frequency */ - samplerate = header & 0x3; - if (samplerate == 3) - return 0; - header >>= 2; - /* bitrate index */ - bitrate = header & 0xF; - if (bitrate == 15 || bitrate == 0) - return 0; - /* ignore error correction, too */ - header >>= 5; - /* layer */ - layer = 4 - (header & 0x3); - if (layer == 4) - return 0; - header >>= 2; - /* version */ - version = header & 0x3; - if (version == 1) - return 0; - /* lookup */ - bitrate = mp3types_bitrates[version == 3 ? 0 : 1][layer - 1][bitrate]; - samplerate = mp3types_freqs[version > 0 ? version - 1 : 0][samplerate]; - /* calculating */ - if (layer == 1) { - length = ((12000 * bitrate / samplerate) + length) * 4; - } else { - length += ((layer == 3 && version == 0) ? 144000 : 72000) * bitrate / samplerate; - } - - GST_DEBUG ("Calculated mad frame length of %u bytes", length); - GST_DEBUG ("samplerate = %lu - bitrate = %lu - layer = %lu - version = %lu", samplerate, bitrate, layer, version); - if (put_layer) - *put_layer = layer; - return length; -} -/* increase this value when this function finds too many false positives */ -/** - * The chance that random data is identified as a valid mp3 header is 63 / 2^18 - * (0.024%) per try. This makes the function for calculating false positives - * 1 - (1 - ((63 / 2 ^18) ^ GST_MP3_TYPEFIND_MIN_HEADERS)) ^ buffersize) - * This has the following probabilities of false positives: - * bufsize MIN_HEADERS - * (bytes) 1 2 3 4 - * 4096 62.6% 0.02% 0% 0% - * 16384 98% 0.09% 0% 0% - * 1 MiB 100% 5.88% 0% 0% - * 1 GiB 100% 100% 1.44% 0% - * 1 TiB 100% 100% 100% 0.35% - * This means that the current choice (3 headers by most of the time 4096 byte - * buffers is pretty safe for now. - * It is however important to note that in a worst case example a buffer of size - * 1440 * GST_MP3_TYPEFIND_MIN_HEADERS + 3 - * bytes is needed to reliable find the mp3 stream in a buffer when scanning - * starts at a random position. This is currently (4323 bytes) slightly above - * the default buffer size. But you rarely hit the worst case - average mp3 - * frames are in the 500 bytes range. - */ -#define GST_MP3_TYPEFIND_MIN_HEADERS 3 -static GstCaps* -mp3_type_find_stream (GstBuffer *buf, gpointer private) -{ - guint8 *data; - guint size; - guint32 head; - gint layer = 0; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - while (size >= 4) { - head = GUINT32_FROM_BE(*((guint32 *)data)); - if ((head & 0xffe00000) == 0xffe00000) { - guint length; - guint prev_layer = 0; - guint found = 0; /* number of valid headers found */ - guint pos = 0; - do { - if ((length = mp3_type_frame_length_from_header (head, &layer))) { - if (prev_layer && prev_layer != layer) - break; - prev_layer = layer; - pos += length; - found++; - if (pos + 4 >= size) { - if (found >= GST_MP3_TYPEFIND_MIN_HEADERS) - goto success; - } - head = GUINT32_FROM_BE(*((guint32 *) &(data[pos]))); - if ((head & 0xffe00000) != 0xffe00000) - break; - } else { - break; - } - } while (TRUE); - } - data++; - size--; - } - - return NULL; - -success: - g_assert (layer); - return GST_CAPS_NEW ("mp3_type_find", "audio/mpeg", "layer", GST_PROPS_INT (layer)); -} - -static gboolean -plugin_init (GModule *module, GstPlugin *plugin) -{ - gint i=0; - - while (mp3type_definitions[i].name) { - GstTypeFactory *type; - - type = gst_type_factory_new (&mp3type_definitions[i]); - gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); - i++; - } - - /* gst_info("gsttypes: loaded %d mp3 types\n",i); */ - - return TRUE; -} - -GstPluginDesc plugin_desc = { - GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "mp3types", - plugin_init -}; diff --git a/gst/mpegaudioparse/gstmpegaudioparse.c b/gst/mpegaudioparse/gstmpegaudioparse.c index ba207c0eb6..920ab22c25 100644 --- a/gst/mpegaudioparse/gstmpegaudioparse.c +++ b/gst/mpegaudioparse/gstmpegaudioparse.c @@ -35,6 +35,15 @@ static GstElementDetails mp3parse_details = { "(C) 1999", }; +static GstCaps * mp3_type_find (GstByteStream *bs, gpointer data); + +static GstTypeDefinition mp3type_definition = { + "mp3_audio/mpeg", + "audio/mpeg", + ".mp3 .mp2 .mp1 .mpga", + mp3_type_find, +}; + static GstPadTemplate* mp3_src_factory (void) { @@ -115,11 +124,221 @@ gst_mp3parse_get_type(void) { 0, (GInstanceInitFunc)gst_mp3parse_init, }; - mp3parse_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMPEGAudioParse", &mp3parse_info, 0); + mp3parse_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstMPEGAudioParse", + &mp3parse_info, 0); } return mp3parse_type; } +static guint mp3types_bitrates[2][3][16] = +{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, }, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, }, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } }, + { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, }, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, }, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } }, +}; + +static guint mp3types_freqs[3][3] = +{ {44100, 48000, 32000}, + {22050, 24000, 16000}, + {11025, 12000, 8000}}; + +static inline guint +mp3_type_frame_length_from_header (guint32 header, guint *put_layer, + guint *put_channels, guint *put_bitrate, + guint *put_samplerate) +{ + guint length; + gulong mode, samplerate, bitrate, layer, version, channels; + + /* we don't need extension, copyright, original or + * emphasis for the frame length */ + header >>= 6; + + /* mode */ + mode = header & 0x3; + header >>= 3; + + /* padding */ + length = header & 0x1; + header >>= 1; + + /* sampling frequency */ + samplerate = header & 0x3; + if (samplerate == 3) + return 0; + header >>= 2; + + /* bitrate index */ + bitrate = header & 0xF; + if (bitrate == 15 || bitrate == 0) + return 0; + + /* ignore error correction, too */ + header >>= 5; + + /* layer */ + layer = 4 - (header & 0x3); + if (layer == 4) + return 0; + header >>= 2; + + /* version */ + version = header & 0x3; + if (version == 1) + return 0; + + /* lookup */ + channels = (mode == 3) ? 1 : 2; + bitrate = mp3types_bitrates[version == 3 ? 0 : 1][layer - 1][bitrate]; + samplerate = mp3types_freqs[version > 0 ? version - 1 : 0][samplerate]; + + /* calculating */ + if (layer == 1) { + length = ((12000 * bitrate / samplerate) + length) * 4; + } else { + length += ((layer == 3 && version == 0) ? 144000 : 72000) * bitrate / samplerate; + } + + GST_DEBUG ("Calculated mp3 frame length of %u bytes", length); + GST_DEBUG ("samplerate = %lu - bitrate = %lu - layer = %lu - version = %lu" + " - channels = %lu", + samplerate, bitrate, layer, version, channels); + + if (put_layer) + *put_layer = layer; + if (put_channels) + *put_channels = channels; + if (put_bitrate) + *put_bitrate = bitrate; + if (put_samplerate) + *put_samplerate = samplerate; + + return length; +} + +/** + * The chance that random data is identified as a valid mp3 header is 63 / 2^18 + * (0.024%) per try. This makes the function for calculating false positives + * 1 - (1 - ((63 / 2 ^18) ^ GST_MP3_TYPEFIND_MIN_HEADERS)) ^ buffersize) + * This has the following probabilities of false positives: + * bufsize MIN_HEADERS + * (bytes) 1 2 3 4 + * 4096 62.6% 0.02% 0% 0% + * 16384 98% 0.09% 0% 0% + * 1 MiB 100% 5.88% 0% 0% + * 1 GiB 100% 100% 1.44% 0% + * 1 TiB 100% 100% 100% 0.35% + * This means that the current choice (3 headers by most of the time 4096 byte + * buffers is pretty safe for now. + * + * The max. size of each frame is 1440 bytes, which means that for N frames + * to be detected, we need 1440 * GST_MP3_TYPEFIND_MIN_HEADERS + 3 of data. + * Assuming we step into the stream right after the frame header, this + * means we need 1440 * (GST_MP3_TYPEFIND_MIN_HEADERS + 1) - 1 + 3 bytes + * of data (5762) to always detect any mp3. + */ + +/* increase this value when this function finds too many false positives */ +#define GST_MP3_TYPEFIND_MIN_HEADERS 3 +#define GST_MP3_TYPEFIND_MIN_DATA (1440 * (GST_MP3_TYPEFIND_MIN_HEADERS + 1) - 1 + 3) + +static GstCaps * +mp3_caps_create (guint layer, guint channels, + guint bitrate, guint samplerate) +{ + GstCaps *new; + + g_assert (layer); + g_assert (samplerate); + g_assert (bitrate); + g_assert (channels); + + new = GST_CAPS_NEW ("mp3_type_find", + "audio/mpeg", + "mpegversion", GST_PROPS_INT (1), + "layer", GST_PROPS_INT (layer), + /*"bitrate", GST_PROPS_INT (bitrate),*/ + "rate", GST_PROPS_INT (samplerate), + "channels", GST_PROPS_INT (channels)); + + return new; +} + +static GstCaps * +mp3_type_find (GstByteStream *bs, gpointer private) +{ + GstBuffer *buf = NULL; + GstCaps *new = NULL; + guint8 *data; + guint size; + guint32 head; + guint layer = 0, bitrate = 0, samplerate = 0, channels = 0; + + /* note that even if we don't get the requested size, + * it might still be a (very small) mp3 */ + gst_bytestream_peek (bs, &buf, GST_MP3_TYPEFIND_MIN_DATA); + if (!buf) { + goto done; + } + + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + while (size >= 4) { + head = GUINT32_FROM_BE(*((guint32 *)data)); + if ((head & 0xffe00000) == 0xffe00000) { + guint length; + guint prev_layer = 0, prev_bitrate = 0, + prev_channels = 0, prev_samplerate = 0; + guint found = 0; /* number of valid headers found */ + guint pos = 0; + + do { + if (!(length = mp3_type_frame_length_from_header (head, &layer, + &channels, &bitrate, + &samplerate))) { + break; + } + if ((prev_layer && prev_layer != layer) || !layer || + (prev_bitrate && prev_bitrate != bitrate) || !bitrate || + (prev_samplerate && prev_samplerate != samplerate) || !samplerate || + (prev_channels && prev_channels != channels) || !channels) { + /* this means an invalid property, or a change, which likely + * indicates that this is not a mp3 but just a random bytestream */ + break; + } + prev_layer = layer; + prev_bitrate = bitrate; + prev_channels = channels; + prev_samplerate = samplerate; + pos += length; + if (++found >= GST_MP3_TYPEFIND_MIN_HEADERS) { + /* we're pretty sure that this is mp3 now */ + new = mp3_caps_create (layer, channels, bitrate, samplerate); + goto done; + } + + /* and now, find a new head */ + head = GUINT32_FROM_BE(*((guint32 *) &(data[pos]))); + if ((head & 0xffe00000) != 0xffe00000) + break; + } while (TRUE); + } + data++; + size--; + } + +done: + if (buf != NULL) { + gst_buffer_unref (buf); + } + + return new; +} + static void gst_mp3parse_class_init (GstMPEGAudioParseClass *klass) { @@ -247,7 +466,10 @@ gst_mp3parse_chain (GstPad *pad, GstBuffer *buf) header2 = GUINT32_FROM_BE(*((guint32 *)(data+offset+bpf))); GST_DEBUG ("mp3parse: header=%08X, header2=%08X, bpf=%d", (unsigned int)header, (unsigned int)header2, bpf ); - #define HDRMASK ~( (0xF<<12)/*bitrate*/ | (1<<9)/*padding*/ | (3<<4)/*mode extension*/ ) /* mask the bits which are allowed to differ between frames */ +/* mask the bits which are allowed to differ between frames */ +#define HDRMASK ~((0xF << 12) /* bitrate */ | \ + (0x1 << 9) /* padding */ | \ + (0x3 << 4)) /*mode extension*/ if ( (header2&HDRMASK) != (header&HDRMASK) ) { /* require 2 matching headers in a row */ GST_DEBUG ("mp3parse: next header doesn't match (header=%08X, header2=%08X, bpf=%d)", (unsigned int)header, (unsigned int)header2, bpf ); @@ -309,56 +531,23 @@ gst_mp3parse_chain (GstPad *pad, GstBuffer *buf) } } -static int mp3parse_tabsel[2][3][16] = -{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, }, - {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, }, - {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } }, - { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, }, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, }, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } }, -}; - -static long mp3parse_freqs[9] = -{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000}; - - static long bpf_from_header (GstMPEGAudioParse *parse, unsigned long header) { - int layer_index,layer,lsf,samplerate_index,padding,mode; - long bpf; - gint channels, rate; + guint bitrate, layer, rate, channels, length; - /*mpegver = (header >> 19) & 0x3; // don't need this for bpf */ - layer_index = (header >> 17) & 0x3; - layer = 4 - layer_index; - lsf = (header & (1 << 20)) ? ((header & (1 << 19)) ? 0 : 1) : 1; - parse->bit_rate = mp3parse_tabsel[lsf][layer - 1][((header >> 12) & 0xf)]; - samplerate_index = (header >> 10) & 0x3; - padding = (header >> 9) & 0x1; - mode = (header >> 6) & 0x3; - - if (layer == 1) { - bpf = parse->bit_rate * 12000; - bpf /= mp3parse_freqs[samplerate_index]; - bpf = ((bpf + padding) << 2); - } else { - bpf = parse->bit_rate * 144000; - bpf /= mp3parse_freqs[samplerate_index]; - bpf += padding; + if (!(length = mp3_type_frame_length_from_header (header, &layer, + &channels, + &bitrate, &rate))) { + return 0; } - channels = (mode == 3) ? 1 : 2; - rate = mp3parse_freqs[samplerate_index]; if (channels != parse->channels || rate != parse->rate || - layer != parse->layer) { - GstCaps *caps = GST_CAPS_NEW ("mp3parse_src", - "audio/mpeg", - "mpegversion", GST_PROPS_INT (1), - "layer", GST_PROPS_INT (layer), - "channels", GST_PROPS_INT (channels), - "rate", GST_PROPS_INT (rate)); + layer != parse->layer || + bitrate != parse->bit_rate) { + GstCaps *caps = mp3_caps_create (layer, channels, bitrate, rate); + if (gst_pad_try_set_caps(parse->srcpad, caps) <= 0) { gst_element_error (GST_ELEMENT (parse), "mp3parse: failed to negotiate format with next element"); @@ -367,12 +556,10 @@ bpf_from_header (GstMPEGAudioParse *parse, unsigned long header) parse->channels = channels; parse->layer = layer; parse->rate = rate; + parse->bit_rate = bitrate; } - /*g_print("%08x: layer %d lsf %d bitrate %d samplerate_index %d padding %d - bpf %d\n", */ -/*header,layer,lsf,bitrate,samplerate_index,padding,bpf); */ - - return bpf; + return length; } static gboolean @@ -470,6 +657,7 @@ static gboolean plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; + GstTypeFactory *type; /* create an elementfactory for the mp3parse element */ factory = gst_element_factory_new ("mp3parse", @@ -485,6 +673,10 @@ plugin_init (GModule *module, GstPlugin *plugin) gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + /* type finding */ + type = gst_type_factory_new (&mp3type_definition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); + return TRUE; } diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index 3b3801659a..9c81db003a 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -1235,10 +1235,6 @@ gst_mpeg_demux_plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; - /* this filter needs the bytestream package */ - if (!gst_library_load ("gstbytestream")) - return FALSE; - /* create an elementfactory for the mpeg_demux element */ factory = gst_element_factory_new ("mpegdemux", GST_TYPE_MPEG_DEMUX, &mpeg_demux_details); diff --git a/gst/mpegstream/gstmpegpacketize.h b/gst/mpegstream/gstmpegpacketize.h index 415f718855..d4c1c3b668 100644 --- a/gst/mpegstream/gstmpegpacketize.h +++ b/gst/mpegstream/gstmpegpacketize.h @@ -24,7 +24,7 @@ #include #include -#include +#include #ifdef __cplusplus diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index 85041f37e4..9d09390057 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -915,10 +915,6 @@ gst_mpeg_parse_plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; - /* this filter needs the bytestream package */ - if (!gst_library_load ("gstbytestream")) - return FALSE; - /* create an elementfactory for the mpeg_parse element */ factory = gst_element_factory_new ("mpegparse", GST_TYPE_MPEG_PARSE, &mpeg_parse_details); diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index 03757f3d1a..27adb2a0c1 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -22,7 +22,7 @@ #define __MPEG_PARSE_H__ #include -#include +#include #include "gstmpegpacketize.h" #ifdef __cplusplus diff --git a/gst/mpegstream/gstmpegstream.c b/gst/mpegstream/gstmpegstream.c index 869704f8bb..81339745d5 100644 --- a/gst/mpegstream/gstmpegstream.c +++ b/gst/mpegstream/gstmpegstream.c @@ -25,10 +25,6 @@ static gboolean plugin_init (GModule *module, GstPlugin *plugin) { - /* mpegdemux needs the bytestream package */ - if (!gst_library_load ("gstbytestream")) - return FALSE; - /* short-circuit here; this is potentially dangerous since if the second * or third init fails then the whole plug-in will be placed on the register * stack again and the first _init will be called more than once diff --git a/gst/mpegstream/gstrfc2250enc.c b/gst/mpegstream/gstrfc2250enc.c index 71991f36a1..1423fa5d82 100644 --- a/gst/mpegstream/gstrfc2250enc.c +++ b/gst/mpegstream/gstrfc2250enc.c @@ -328,10 +328,6 @@ gst_rfc2250_enc_plugin_init (GModule *module, GstPlugin *plugin) { GstElementFactory *factory; - /* this filter needs the bytestream package */ - if (!gst_library_load("gstbytestream")) - return FALSE; - /* create an elementfactory for the rfc2250_enc element */ factory = gst_element_factory_new ("rfc2250enc", GST_TYPE_RFC2250_ENC, &rfc2250_enc_details); diff --git a/gst/mpegstream/gstrfc2250enc.h b/gst/mpegstream/gstrfc2250enc.h index 2103c51d4b..5f405fa524 100644 --- a/gst/mpegstream/gstrfc2250enc.h +++ b/gst/mpegstream/gstrfc2250enc.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include "gstmpegpacketize.h" diff --git a/gst/realmedia/rmdemux.c b/gst/realmedia/rmdemux.c index 87b5e3bb96..1efe2514be 100644 --- a/gst/realmedia/rmdemux.c +++ b/gst/realmedia/rmdemux.c @@ -87,7 +87,7 @@ gst_rmdemux_details = "(C) 2003", }; -static GstCaps* realmedia_type_find (GstBuffer *buf, gpointer private); +static GstCaps* realmedia_type_find (GstByteStream *bs, gpointer private); static GstTypeDefinition realmediadefinition = { "rmdemux_video/realmedia", @@ -195,21 +195,26 @@ gst_rmdemux_init (GstRMDemux *rmdemux) } static GstCaps* -realmedia_type_find (GstBuffer *buf, gpointer private) +realmedia_type_find (GstByteStream *bs, gpointer private) { - gchar *data = GST_BUFFER_DATA (buf); + GstBuffer *buf = NULL; + GstCaps *new = NULL; - g_return_val_if_fail (data != NULL, NULL); - - if(GST_BUFFER_SIZE(buf) < 4){ - return NULL; + if (gst_bytestream_peek (bs, &buf, 4) == 4) { + gchar *data = GST_BUFFER_DATA (buf); + + if (!strncmp (data, ".RMF", 4)) { + new = GST_CAPS_NEW ("realmedia_type_find", + "application/vnd.rn-realmedia", + NULL); + } } - if (strncmp (data, ".RMF", 4)==0) { - return gst_caps_new ("realmedia_type_find", - "application/vnd.rn-realmedia", - NULL); + + if (buf != NULL) { + gst_buffer_unref (buf); } - return NULL; + + return new; } static gboolean @@ -218,9 +223,6 @@ plugin_init (GModule *module, GstPlugin *plugin) GstElementFactory *factory; GstTypeFactory *type; - if (!gst_library_load ("gstbytestream")) - return FALSE; - factory = gst_element_factory_new ("rmdemux", GST_TYPE_RMDEMUX, &gst_rmdemux_details); g_return_val_if_fail(factory != NULL, FALSE); diff --git a/gst/realmedia/rmdemux.h b/gst/realmedia/rmdemux.h index 905eadef00..231e1546af 100644 --- a/gst/realmedia/rmdemux.h +++ b/gst/realmedia/rmdemux.h @@ -22,7 +22,7 @@ #define __GST_RMDEMUX_H__ #include -#include +#include #ifdef __cplusplus extern "C" {