From e9d4a825d61734611e652484eb53402c77bc8c9d Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Thu, 27 Jan 2005 10:29:19 +0000 Subject: [PATCH] ext/mad/: Add id3demuxbin (which is a simple bin consisting of id3demux and typefind), take over rank from id3demux, ... Original commit message from CVS: * ext/mad/Makefile.am: * ext/mad/gstid3demuxbin.c: (gst_id3demux_bin_get_type), (gst_id3demux_bin_base_init), (gst_id3demux_bin_class_init), (gst_id3demux_bin_init), (gst_id3demux_bin_remove_pad), (found_type), (gst_id3demux_bin_change_state): * ext/mad/gstid3tag.c: (gst_id3_tag_add_src_pad), (gst_id3_tag_init), (gst_id3_tag_handle_event), (gst_id3_tag_src_link), (gst_id3_tag_chain), (gst_id3_tag_change_state), (plugin_init): * ext/mad/gstmad.h: Add id3demuxbin (which is a simple bin consisting of id3demux and typefind), take over rank from id3demux, remove typefind code from id3demux. Makes all broken mp3s that I know of work, and thereby fixes #152688. --- ChangeLog | 17 ++++ ext/mad/Makefile.am | 5 +- ext/mad/gstid3demuxbin.c | 197 +++++++++++++++++++++++++++++++++++++++ ext/mad/gstid3tag.c | 137 ++------------------------- ext/mad/gstmad.h | 1 + 5 files changed, 229 insertions(+), 128 deletions(-) create mode 100644 ext/mad/gstid3demuxbin.c diff --git a/ChangeLog b/ChangeLog index 268671754b..da7576ddab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-01-27 Ronald S. Bultje + + * ext/mad/Makefile.am: + * ext/mad/gstid3demuxbin.c: (gst_id3demux_bin_get_type), + (gst_id3demux_bin_base_init), (gst_id3demux_bin_class_init), + (gst_id3demux_bin_init), (gst_id3demux_bin_remove_pad), + (found_type), (gst_id3demux_bin_change_state): + * ext/mad/gstid3tag.c: (gst_id3_tag_add_src_pad), + (gst_id3_tag_init), (gst_id3_tag_handle_event), + (gst_id3_tag_src_link), (gst_id3_tag_chain), + (gst_id3_tag_change_state), (plugin_init): + * ext/mad/gstmad.h: + Add id3demuxbin (which is a simple bin consisting of id3demux + and typefind), take over rank from id3demux, remove typefind + code from id3demux. Makes all broken mp3s that I know of work, + and thereby fixes #152688. + 2005-01-27 Edward Hervey Reviewed by: Ronald S. Bultje diff --git a/ext/mad/Makefile.am b/ext/mad/Makefile.am index 1452e256a5..c0775aaf27 100644 --- a/ext/mad/Makefile.am +++ b/ext/mad/Makefile.am @@ -1,6 +1,9 @@ plugin_LTLIBRARIES = libgstmad.la -libgstmad_la_SOURCES = gstmad.c gstid3tag.c +libgstmad_la_SOURCES = \ + gstmad.c \ + gstid3tag.c \ + gstid3demuxbin.c libgstmad_la_CFLAGS = $(GST_CFLAGS) $(MAD_CFLAGS) $(ID3_CFLAGS) libgstmad_la_LIBADD = $(MAD_LIBS) $(ID3_LIBS) diff --git a/ext/mad/gstid3demuxbin.c b/ext/mad/gstid3demuxbin.c new file mode 100644 index 0000000000..76b80f03c7 --- /dev/null +++ b/ext/mad/gstid3demuxbin.c @@ -0,0 +1,197 @@ +/* GStreamer + * (c) 2005 Ronald Bultje + * + * gstid3demuxbin.c: hack around autoplugging. + * + * 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. + */ + +#ifdef HAVE_CONFIG_G +#include "config.h" +#endif + +#include + +#define GST_TYPE_ID3DEMUX_BIN \ + (gst_id3demux_bin_get_type()) +#define GST_ID3DEMUX_BIN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_ID3DEMUX_BIN, \ + GstId3DemuxBin)) +#define GST_ID3DEMUX_BIN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_ID3DEMUX_BIN, \ + GstId3DemuxBinClass)) +#define GST_IS_ID3DEMUX_BIN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_ID3DEMUX_BIN)) +#define GST_IS_ID3DEMUX_BIN_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_ID3DEMUX_BIN)) + +typedef struct _GstId3DemuxBin +{ + GstBin parent; + + /* ghost pads */ + GstPad *srcpad; + + /* kids */ + GstElement *demux, *typefind; +} GstId3DemuxBin; + +typedef struct _GstId3DemuxBinClass +{ + GstBinClass parent; +} GstId3DemuxBinClass; + +static GstStaticPadTemplate id3demux_bin_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("ANY") + ); + +static GstStaticPadTemplate id3demux_bin_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-id3") + ); + +static void gst_id3demux_bin_class_init (GstId3DemuxBinClass * klass); +static void gst_id3demux_bin_base_init (GstId3DemuxBinClass * klass); +static void gst_id3demux_bin_init (GstId3DemuxBin * manager); + +static void found_type (GstElement * element, guint probability, + const GstCaps * caps, gpointer data); +static GstElementStateReturn gst_id3demux_bin_change_state (GstElement * + element); + +static GstBinClass *parent_class; + +GType +gst_id3demux_bin_get_type (void) +{ + static GType gst_id3demux_bin_type = 0; + + if (!gst_id3demux_bin_type) { + static const GTypeInfo gst_id3demux_bin_info = { + sizeof (GstId3DemuxBinClass), + (GBaseInitFunc) gst_id3demux_bin_base_init, + NULL, + (GClassInitFunc) gst_id3demux_bin_class_init, + NULL, + NULL, + sizeof (GstId3DemuxBin), + 0, + (GInstanceInitFunc) gst_id3demux_bin_init, + NULL + }; + + gst_id3demux_bin_type = + g_type_register_static (GST_TYPE_BIN, + "GstId3DemuxBin", &gst_id3demux_bin_info, 0); + } + + return gst_id3demux_bin_type; +} + +static void +gst_id3demux_bin_base_init (GstId3DemuxBinClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + static GstElementDetails gst_id3demux_bin_details = + GST_ELEMENT_DETAILS ("ID3-demux bin", + "Generic/Bin", + "Manages typefinding for an ID3 demuxer", + "Ronald Bultje "); + + gst_element_class_set_details (element_class, &gst_id3demux_bin_details); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&id3demux_bin_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&id3demux_bin_sink_template)); +} + +static void +gst_id3demux_bin_class_init (GstId3DemuxBinClass * klass) +{ + parent_class = g_type_class_ref (GST_TYPE_BIN); + + GST_ELEMENT_CLASS (klass)->change_state = gst_id3demux_bin_change_state; +} + +static void +gst_id3demux_bin_init (GstId3DemuxBin * id3) +{ + id3->demux = gst_element_factory_make ("id3demux", NULL); + id3->typefind = gst_element_factory_make ("typefind", NULL); + + g_signal_connect (id3->typefind, "have-type", G_CALLBACK (found_type), id3); + gst_pad_use_explicit_caps (gst_element_get_pad (id3->typefind, "src")); + gst_element_add_ghost_pad (GST_ELEMENT (id3), + gst_element_get_pad (id3->demux, "sink"), "sink"); + gst_bin_add_many (GST_BIN (id3), id3->demux, id3->typefind, NULL); + gst_element_link (id3->demux, id3->typefind); +} + +static void +gst_id3demux_bin_remove_pad (GstId3DemuxBin * id3) +{ + if (id3->srcpad) { + gst_element_remove_pad (GST_ELEMENT (id3), id3->srcpad); + id3->srcpad = NULL; + } +} + +static void +found_type (GstElement * element, guint probability, + const GstCaps * caps, gpointer data) +{ + GstId3DemuxBin *id3 = GST_ID3DEMUX_BIN (data); + + /* get rid of old */ + gst_id3demux_bin_remove_pad (id3); + + GST_LOG ("Found type"); + + /* add new */ + if (!gst_pad_set_explicit_caps (gst_element_get_pad (id3->typefind, + "src"), caps)) { + GST_ELEMENT_ERROR (id3, CORE, NEGOTIATION, (NULL), (NULL)); + return; + } + + id3->srcpad = gst_ghost_pad_new ("src", + gst_element_get_pad (id3->typefind, "src")); + gst_element_add_pad (GST_ELEMENT (id3), id3->srcpad); +} + +static GstElementStateReturn +gst_id3demux_bin_change_state (GstElement * element) +{ + GstId3DemuxBin *id3 = GST_ID3DEMUX_BIN (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_PAUSED_TO_READY: + gst_id3demux_bin_remove_pad (id3); + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/mad/gstid3tag.c b/ext/mad/gstid3tag.c index 830142b528..58c6702c26 100644 --- a/ext/mad/gstid3tag.c +++ b/ext/mad/gstid3tag.c @@ -76,7 +76,6 @@ struct _GstID3Tag /* caps */ GstID3ParseMode parse_mode; - GstCaps *found_caps; /* tags */ GstTagList *event_tags; @@ -124,8 +123,7 @@ GST_DEBUG_CATEGORY_EXTERN (mad_debug); static GstStaticPadTemplate id3_tag_src_any_template_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, - /* FIXME: for spider - should be GST_PAD_ALWAYS, */ - GST_PAD_SOMETIMES, + GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); @@ -283,28 +281,9 @@ gst_id3_tag_class_init (gpointer g_class, gpointer class_data) gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_id3_tag_get_property); } -static GstCaps * -gst_id3_tag_get_caps (GstPad * pad) -{ - GstID3Tag *tag = GST_ID3_TAG (gst_pad_get_parent (pad)); - - if (tag->found_caps) { - GstCaps *caps = gst_caps_copy (tag->found_caps); - - if (CAN_BE_MUXER (tag)) { - gst_caps_append (caps, - gst_caps_from_string ("application/x-gst-tags; application/x-id3")); - } - return caps; - } else { - return gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - } -} - static void gst_id3_tag_add_src_pad (GstID3Tag * tag) { - g_assert (tag->srcpad == NULL); tag->srcpad = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (tag), "src"), "src"); @@ -316,8 +295,6 @@ gst_id3_tag_add_src_pad (GstID3Tag * tag) GST_DEBUG_FUNCPTR (gst_id3_tag_src_query)); gst_pad_set_query_type_function (tag->srcpad, GST_DEBUG_FUNCPTR (gst_id3_tag_get_query_types)); - gst_pad_set_getcaps_function (tag->srcpad, - GST_DEBUG_FUNCPTR (gst_id3_tag_get_caps)); gst_pad_set_link_function (tag->srcpad, GST_DEBUG_FUNCPTR (gst_id3_tag_src_link)); gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad); @@ -336,13 +313,11 @@ gst_id3_tag_init (GTypeInstance * instance, gpointer g_class) gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad); gst_pad_set_chain_function (tag->sinkpad, GST_DEBUG_FUNCPTR (gst_id3_tag_chain)); - } - if (GST_ID3_TAG_GET_CLASS (tag)->type == GST_ID3_TAG_PARSE_MUX) { - /* only the muxer class here, all other use sometimes pads */ + gst_id3_tag_add_src_pad (tag); + + tag->parse_mode = GST_ID3_TAG_GET_CLASS (tag)->type; } - /* FIXME: for the alli^H^H^H^Hspider - gst_id3_tag_add_src_pad (tag); */ - tag->parse_mode = GST_ID3_TAG_PARSE_BASE; tag->buffer = NULL; GST_FLAG_SET (tag, GST_ELEMENT_EVENT_AWARE); @@ -995,92 +970,6 @@ gst_id3_tag_handle_event (GstPad * pad, GstEvent * event) } return; } -typedef struct -{ - guint best_probability; - GstCaps *caps; - GstBuffer *buffer; -} -SimpleTypeFind; -guint8 * -simple_find_peek (gpointer data, gint64 offset, guint size) -{ - SimpleTypeFind *find = (SimpleTypeFind *) data; - - if (offset < 0) - return NULL; - - if (GST_BUFFER_SIZE (find->buffer) >= offset + size) { - return GST_BUFFER_DATA (find->buffer) + offset; - } - return NULL; -} -static void -simple_find_suggest (gpointer data, guint probability, const GstCaps * caps) -{ - SimpleTypeFind *find = (SimpleTypeFind *) data; - - if (probability > find->best_probability) { - gst_caps_replace (&find->caps, gst_caps_copy (caps)); - find->best_probability = probability; - } -} -static GstCaps * -gst_id3_tag_do_typefind (GstID3Tag * tag, GstBuffer * buffer) -{ - GList *walk, *type_list; - SimpleTypeFind find; - GstTypeFind gst_find; - - /* this will help us detecting the media stream type after - * this id3 thingy... Please note that this is a cruel hack - * for as long as spider doesn't support multi-type-finding. - */ - walk = type_list = gst_type_find_factory_get_list (); - - find.buffer = buffer; - find.best_probability = 0; - find.caps = NULL; - gst_find.data = &find; - gst_find.peek = simple_find_peek; - gst_find.get_length = NULL; - gst_find.suggest = simple_find_suggest; - while (walk) { - GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data); - - gst_type_find_factory_call_function (factory, &gst_find); - if (find.best_probability >= GST_TYPE_FIND_MAXIMUM) - break; - walk = g_list_next (walk); - } - g_list_free (type_list); - if (find.best_probability > 0) { - return find.caps; - } else { - GST_ELEMENT_ERROR (tag, CORE, CAPS, (NULL), ("no caps found")); - return NULL; - } -} -static gboolean -gst_id3_tag_do_caps_nego (GstID3Tag * tag, GstBuffer * buffer) -{ - if (buffer != NULL && CAN_BE_DEMUXER (tag)) { - tag->found_caps = gst_id3_tag_do_typefind (tag, buffer); - if (!tag->found_caps) { - return FALSE; - } - } - if (!tag->srcpad) - gst_id3_tag_add_src_pad (tag); - if (!gst_pad_is_linked (tag->srcpad)) { - GST_DEBUG_OBJECT (tag, "srcpad not linked, not proceeding"); - tag->parse_mode = GST_ID3_TAG_GET_CLASS (tag)->type; - return TRUE; - } else { - GST_DEBUG_OBJECT (tag, "renegotiating"); - return gst_pad_renegotiate (tag->srcpad) != GST_PAD_LINK_REFUSED; - } -} static GstPadLinkReturn gst_id3_tag_src_link (GstPad * pad, const GstCaps * caps) @@ -1090,8 +979,6 @@ gst_id3_tag_src_link (GstPad * pad, const GstCaps * caps) tag = GST_ID3_TAG (gst_pad_get_parent (pad)); - if (!tag->found_caps && CAN_BE_DEMUXER (tag)) - return GST_PAD_LINK_DELAYED; if (!CAN_BE_MUXER (tag) || !CAN_BE_DEMUXER (tag)) { tag->parse_mode = GST_ID3_TAG_GET_CLASS (tag)->type; return GST_PAD_LINK_OK; @@ -1270,9 +1157,6 @@ gst_id3_tag_chain (GstPad * pad, GstData * data) GST_BUFFER_OFFSET_END (tag->buffer) + tag->v2tag_size; gst_data_unref (GST_DATA (tag->buffer)); tag->buffer = NULL; - if (tag->found_caps == NULL) - if (!gst_id3_tag_do_caps_nego (tag, buffer)) - return; /* seek to ID3v1 tag */ if (gst_pad_send_event (GST_PAD_PEER (tag->sinkpad), gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_END | @@ -1333,6 +1217,7 @@ gst_id3_tag_chain (GstPad * pad, GstData * data) GstBuffer *sub = gst_buffer_create_sub (buffer, 0, buffer->size - 128); + GST_BUFFER_OFFSET (sub) = GST_BUFFER_OFFSET (buffer); gst_data_unref (GST_DATA (buffer)); buffer = sub; } @@ -1397,11 +1282,7 @@ gst_id3_tag_change_state (GstElement * element) gst_data_unref (GST_DATA (tag->buffer)); tag->buffer = NULL; } - if (tag->found_caps) { - gst_caps_free (tag->found_caps); - tag->found_caps = NULL; - } - tag->parse_mode = GST_ID3_TAG_PARSE_BASE; + tag->parse_mode = GST_ID3_TAG_GET_CLASS (tag)->type; break; case GST_STATE_READY_TO_NULL: break; @@ -1420,13 +1301,15 @@ plugin_init (GstPlugin * plugin) if (!gst_element_register (plugin, "mad", GST_RANK_PRIMARY, gst_mad_get_type ()) - || !gst_element_register (plugin, "id3demux", GST_RANK_PRIMARY, + || !gst_element_register (plugin, "id3demux", GST_RANK_NONE, gst_id3_tag_get_type (GST_ID3_TAG_PARSE_DEMUX)) || !gst_element_register (plugin, "id3mux", GST_RANK_NONE, /* removed for spider */ gst_id3_tag_get_type (GST_ID3_TAG_PARSE_MUX)) /* FIXME 0.9: remove this element */ || !gst_element_register (plugin, "id3tag", GST_RANK_NONE, - gst_id3_tag_get_type (GST_ID3_TAG_PARSE_ANY))) { + gst_id3_tag_get_type (GST_ID3_TAG_PARSE_ANY)) + || !gst_element_register (plugin, "id3demuxbin", GST_RANK_PRIMARY, + gst_id3demux_bin_get_type ())) { return FALSE; } diff --git a/ext/mad/gstmad.h b/ext/mad/gstmad.h index a19a6c6096..16acce31cd 100644 --- a/ext/mad/gstmad.h +++ b/ext/mad/gstmad.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS GType gst_mad_get_type (void); GType gst_id3_tag_get_type (guint type); +GType gst_id3demux_bin_get_type (void); GstTagList* gst_mad_id3_to_tag_list (const struct id3_tag * tag); struct id3_tag * gst_mad_tag_list_to_id3_tag (GstTagList * list);