From ba9ed9b9e4f57fa20e85f4454b3863a9c8d77edf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 25 Nov 2002 21:37:26 +0000 Subject: [PATCH] More ffmpeg wrapping going on here Original commit message from CVS: More ffmpeg wrapping going on here --- ext/ffmpeg/Makefile.am | 5 +- ext/ffmpeg/gstffmpeg.c | 6 ++ ext/ffmpeg/gstffmpegcodecmap.c | 128 ++++++++++++++++++++++++++++------------ ext/ffmpeg/gstffmpegdec.c | 56 +++++++++--------- ext/ffmpeg/gstffmpegdemux.c | 53 +++++++++-------- ext/ffmpeg/gstffmpegprotocol.c | 36 ++++++++++-- ext/ffmpeg/gstffmpegtypes.c | 129 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 317 insertions(+), 96 deletions(-) create mode 100644 ext/ffmpeg/gstffmpegtypes.c diff --git a/ext/ffmpeg/Makefile.am b/ext/ffmpeg/Makefile.am index a4df85c..133d3a3 100644 --- a/ext/ffmpeg/Makefile.am +++ b/ext/ffmpeg/Makefile.am @@ -3,12 +3,13 @@ plugindir = $(libdir)/gst plugin_LTLIBRARIES = libgstffmpeg.la libgstffmpeg_la_SOURCES = gstffmpeg.c \ - gstffmpegenc.c \ + gstffmpegcodecmap.c \ gstffmpegdec.c \ gstffmpegdemux.c \ + gstffmpegenc.c \ gstffmpegmux.c \ gstffmpegprotocol.c \ - gstffmpegcodecmap.c + gstffmpegtypes.c libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) -I/opt/src/sourceforge/ffmpeg/ -I/opt/src/sourceforge/ffmpeg/libavcodec/ libgstffmpeg_la_LIBADD = diff --git a/ext/ffmpeg/gstffmpeg.c b/ext/ffmpeg/gstffmpeg.c index dde73cc..e9d04ec 100644 --- a/ext/ffmpeg/gstffmpeg.c +++ b/ext/ffmpeg/gstffmpeg.c @@ -29,6 +29,9 @@ extern gboolean gst_ffmpegdemux_register (GstPlugin *plugin); extern gboolean gst_ffmpegdec_register (GstPlugin *plugin); extern gboolean gst_ffmpegenc_register (GstPlugin *plugin); +extern gboolean gst_ffmpegtypes_register (GstPlugin *plugin); + +extern URLProtocol gstreamer_protocol; static gboolean plugin_init (GModule *module, GstPlugin *plugin) @@ -43,6 +46,9 @@ plugin_init (GModule *module, GstPlugin *plugin) gst_ffmpegenc_register (plugin); gst_ffmpegdec_register (plugin); gst_ffmpegdemux_register (plugin); + gst_ffmpegtypes_register (plugin); + + register_protocol (&gstreamer_protocol); /* Now we can return the pointer to the newly created Plugin object. */ return TRUE; diff --git a/ext/ffmpeg/gstffmpegcodecmap.c b/ext/ffmpeg/gstffmpegcodecmap.c index fa66f7f..13add65 100644 --- a/ext/ffmpeg/gstffmpegcodecmap.c +++ b/ext/ffmpeg/gstffmpegcodecmap.c @@ -21,9 +21,9 @@ #include GstCaps * -gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context) +gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context, int codec_id) { - switch (context->codec_id) { + switch (codec_id) { case CODEC_ID_NONE: return GST_CAPS_NEW ("ffmpeg_none", "unkown/unkown", @@ -72,13 +72,24 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context) NULL); break; case CODEC_ID_MPEG4: - return GST_CAPS_NEW ("ffmpeg_mpeg4", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids"), - "fourcc", GST_PROPS_FOURCC (context->fourcc), - "width", GST_PROPS_INT (context->width), - "height", GST_PROPS_INT (context->height) - ); + if (context) { + return GST_CAPS_NEW ("ffmpeg_mpeg4", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (context->fourcc), + "width", GST_PROPS_INT (context->width), + "height", GST_PROPS_INT (context->height) + ); + } + else { + return GST_CAPS_NEW ("ffmpeg_mpeg4", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")), + "width", GST_PROPS_INT_RANGE (0, 4096), + "height", GST_PROPS_INT_RANGE (0, 4096) + ); + } break; case CODEC_ID_RAWVIDEO: return GST_CAPS_NEW ("ffmpeg_rawvideo", @@ -86,40 +97,81 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context) NULL); break; case CODEC_ID_MSMPEG4V1: - return GST_CAPS_NEW ("ffmpeg_msmpeg4v1", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids"), - "fourcc", GST_PROPS_FOURCC (context->fourcc), - "width", GST_PROPS_INT (context->width), - "height", GST_PROPS_INT (context->height) - ); + if (context) { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v1", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MPG4")), + "width", GST_PROPS_INT (context->width), + "height", GST_PROPS_INT (context->height) + ); + } + else { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v1", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MPG4")), + "width", GST_PROPS_INT_RANGE (0, 4096), + "height", GST_PROPS_INT_RANGE (0, 4096) + ); + } break; case CODEC_ID_MSMPEG4V2: - return GST_CAPS_NEW ("ffmpeg_msmpeg4v2", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids"), - "fourcc", GST_PROPS_FOURCC (context->fourcc), - "width", GST_PROPS_INT (context->width), - "height", GST_PROPS_INT (context->height) - ); + if (context) { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v2", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MP42")), + "width", GST_PROPS_INT (context->width), + "height", GST_PROPS_INT (context->height) + ); + } + else { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v2", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("MP42")), + "width", GST_PROPS_INT_RANGE (0, 4096), + "height", GST_PROPS_INT_RANGE (0, 4096) + ); + } break; case CODEC_ID_MSMPEG4V3: - return GST_CAPS_NEW ("ffmpeg_msmpeg4v3", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids"), - "fourcc", GST_PROPS_FOURCC (context->fourcc), - "width", GST_PROPS_INT (context->width), - "height", GST_PROPS_INT (context->height) - ); + if (context) { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v3", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")), + "width", GST_PROPS_INT (context->width), + "height", GST_PROPS_INT (context->height) + ); + } + else { + return GST_CAPS_NEW ("ffmpeg_msmpeg4v3", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("DIV3")), + "width", GST_PROPS_INT_RANGE (0, 4096), + "height", GST_PROPS_INT_RANGE (0, 4096) + ); + } break; case CODEC_ID_WMV1: - return GST_CAPS_NEW ("ffmpeg_wmv1", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids"), - "fourcc", GST_PROPS_FOURCC (GST_STR_FOURCC ("WMV1")), - "width", GST_PROPS_INT (context->width), - "height", GST_PROPS_INT (context->height) - ); + if (context) { + return GST_CAPS_NEW ("ffmpeg_wmv1", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids"), + "compression", GST_PROPS_FOURCC (GST_STR_FOURCC ("WMV1")), + "width", GST_PROPS_INT (context->width), + "height", GST_PROPS_INT (context->height) + ); + } + else { + return GST_CAPS_NEW ("ffmpeg_wmv1", + "video/x-wmv1", + NULL + ); + } break; case CODEC_ID_WMV2: return GST_CAPS_NEW ("ffmpeg_wmv2", @@ -229,7 +281,7 @@ gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context) NULL); break; default: - g_warning ("no caps found for codec id %d\n", context->codec_id); + g_warning ("no caps found for codec id %d\n", codec_id); break; } diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index d756f55..46b499d 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -23,6 +23,9 @@ #include +extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *ctx, int id); + + typedef struct _GstFFMpegDec GstFFMpegDec; struct _GstFFMpegDec { @@ -42,8 +45,14 @@ struct _GstFFMpegDecClass { GstElementClass parent_class; AVCodec *in_plugin; + GstPadTemplate *templ; }; +typedef struct { + AVCodec *in_plugin; + GstPadTemplate *templ; +} GstFFMpegClassParams; + #define GST_TYPE_FFMPEGDEC \ (gst_ffmpegdec_get_type()) #define GST_FFMPEGDEC(obj) \ @@ -66,23 +75,6 @@ enum { }; /* This factory is much simpler, and defines the source pad. */ -GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdec_sink_factory, - "sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_CAPS_NEW ( - "ffmpegdec_sink", - "video/avi", - "format", GST_PROPS_STRING ("strf_vids") - ), - GST_CAPS_NEW ( - "ffmpegdec_sink", - "video/mpeg", - NULL - ) -) - -/* This factory is much simpler, and defines the source pad. */ GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdec_audio_src_factory, "src", GST_PAD_SRC, @@ -140,15 +132,19 @@ gst_ffmpegdec_class_init (GstFFMpegDecClass *klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; + GstFFMpegClassParams *params; gobject_class = (GObjectClass*)klass; gstelement_class = (GstElementClass*)klass; parent_class = g_type_class_ref(GST_TYPE_ELEMENT); - klass->in_plugin = g_hash_table_lookup (global_plugins, + params = g_hash_table_lookup (global_plugins, GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class))); + klass->in_plugin = params->in_plugin; + klass->templ = params->templ; + gobject_class->set_property = gst_ffmpegdec_set_property; gobject_class->get_property = gst_ffmpegdec_get_property; } @@ -168,7 +164,6 @@ gst_ffmpegdec_sinkconnect (GstPad *pad, GstCaps *caps) gst_caps_get_int (caps, "height", &ffmpegdec->context->height); ffmpegdec->context->pix_fmt = PIX_FMT_YUV420P; - ffmpegdec->context->frame_rate = 23 * FRAME_RATE_BASE; ffmpegdec->context->bit_rate = 0; /* FIXME bug in ffmpeg */ @@ -191,8 +186,7 @@ gst_ffmpegdec_init(GstFFMpegDec *ffmpegdec) ffmpegdec->context = g_malloc0 (sizeof (AVCodecContext)); - ffmpegdec->sinkpad = gst_pad_new_from_template ( - GST_PAD_TEMPLATE_GET (gst_ffmpegdec_sink_factory), "sink"); + ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->templ, "sink"); gst_pad_set_connect_function (ffmpegdec->sinkpad, gst_ffmpegdec_sinkconnect); if (oclass->in_plugin->type == CODEC_TYPE_VIDEO) { @@ -367,6 +361,9 @@ gst_ffmpegdec_register (GstPlugin *plugin) while (in_plugin) { gchar *type_name; gchar *codec_type; + GstPadTemplate *sinktempl; + GstCaps *sinkcaps; + GstFFMpegClassParams *params; if (in_plugin->decode) { codec_type = "dec"; @@ -396,18 +393,23 @@ gst_ffmpegdec_register (GstPlugin *plugin) details->author = g_strdup("The FFMPEG crew, GStreamer plugin by Wim Taymans "); details->copyright = g_strdup("(c) 2001"); - g_hash_table_insert (global_plugins, - GINT_TO_POINTER (type), - (gpointer) in_plugin); - /* register the plugin with gstreamer */ factory = gst_element_factory_new(type_name,type,details); g_return_val_if_fail(factory != NULL, FALSE); gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_NONE); - gst_element_factory_add_pad_template (factory, - GST_PAD_TEMPLATE_GET (gst_ffmpegdec_sink_factory)); + sinkcaps = gst_ffmpegcodec_codec_context_to_caps (NULL, in_plugin->id); + sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sinkcaps, NULL); + gst_element_factory_add_pad_template (factory, sinktempl); + + params = g_new0 (GstFFMpegClassParams, 1); + params->in_plugin = in_plugin; + params->templ = sinktempl; + + g_hash_table_insert (global_plugins, + GINT_TO_POINTER (type), + (gpointer) params); if (in_plugin->type == CODEC_TYPE_VIDEO) { gst_element_factory_add_pad_template (factory, diff --git a/ext/ffmpeg/gstffmpegdemux.c b/ext/ffmpeg/gstffmpegdemux.c index c066c2c..6a620a9 100644 --- a/ext/ffmpeg/gstffmpegdemux.c +++ b/ext/ffmpeg/gstffmpegdemux.c @@ -23,13 +23,11 @@ #include -extern URLProtocol gstreamer_protocol; +extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context, int codec_id); typedef enum { STATE_OPEN, - STATE_STREAM_INFO, STATE_DEMUX, - STATE_END, } DemuxState; typedef struct _GstFFMpegDemux GstFFMpegDemux; @@ -164,9 +162,6 @@ gst_ffmpegdemux_loop (GstElement *element) 0, NULL); - /* this doesn't work */ - av_set_pts_info (ffmpegdemux->context, 33, 1, 100000); - ffmpegdemux->state = STATE_DEMUX; break; } @@ -180,44 +175,53 @@ gst_ffmpegdemux_loop (GstElement *element) res = av_read_packet(ct, &pkt); if (res < 0) { - gint i; + if (url_feof (&ct->pb)) { + gint i; - for (i = 0; i < ct->nb_streams; i++) { - GstPad *pad; + for (i = 0; i < ct->nb_streams; i++) { + GstPad *pad; - pad = ffmpegdemux->srcpads[i]; + pad = ffmpegdemux->srcpads[i]; - if (GST_PAD_IS_USABLE (pad)) { - gst_pad_push (pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS))); + if (GST_PAD_IS_USABLE (pad)) { + gst_pad_push (pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS))); + } } + gst_element_set_eos (element); } - gst_element_set_eos (element); return; } st = ct->streams[pkt.stream_index]; if (st->codec_info_state == 0) { - gchar *padname = NULL; - GstPadTemplate *templ = NULL; + gchar *templname = NULL; st->codec_info_state = 1; if (st->codec.codec_type == CODEC_TYPE_VIDEO) { - padname = g_strdup_printf ("video_%02d", pkt.stream_index); - templ = GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_video_src_factory); + templname = "video_%02d"; } else if (st->codec.codec_type == CODEC_TYPE_AUDIO) { - padname = g_strdup_printf ("audio_%02d", pkt.stream_index); - templ = GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_audio_src_factory); + templname = "audio_%02d"; } - if (padname != NULL) { + if (templname != NULL) { + gchar *padname; + GstCaps *caps; + GstPadTemplate *templ; + + caps = gst_ffmpegcodec_codec_context_to_caps (&st->codec, st->codec.codec_id); + templ = gst_pad_template_new (templname, + GST_PAD_SRC, + GST_PAD_SOMETIMES, + caps, NULL); + + padname = g_strdup_printf (templname, pkt.stream_index); pad = gst_pad_new_from_template (templ, padname); ffmpegdemux->srcpads[pkt.stream_index] = pad; gst_element_add_pad (GST_ELEMENT (ffmpegdemux), pad); - g_print ("new pad\n"); } else { g_warning ("unkown pad type %d", st->codec.codec_type); @@ -234,8 +238,9 @@ gst_ffmpegdemux_loop (GstElement *element) outbuf = gst_buffer_new (); GST_BUFFER_DATA (outbuf) = pkt.data; GST_BUFFER_SIZE (outbuf) = pkt.size; - if (pkt.pts != 0) { - GST_BUFFER_TIMESTAMP (outbuf) = pkt.pts * GST_SECOND / 90000LL; + + if (pkt.pts != AV_NOPTS_VALUE && ct->pts_den) { + GST_BUFFER_TIMESTAMP (outbuf) = pkt.pts * GST_SECOND * ct->pts_num / ct->pts_den; } else { GST_BUFFER_TIMESTAMP (outbuf) = -1; @@ -364,7 +369,5 @@ next: in_plugin = in_plugin->next; } - register_protocol (&gstreamer_protocol); - return TRUE; } diff --git a/ext/ffmpeg/gstffmpegprotocol.c b/ext/ffmpeg/gstffmpegprotocol.c index 21d3858..9d9cdb4 100644 --- a/ext/ffmpeg/gstffmpegprotocol.c +++ b/ext/ffmpeg/gstffmpegprotocol.c @@ -28,10 +28,11 @@ typedef struct _GstProtocolInfo GstProtocolInfo; struct _GstProtocolInfo { - GstPad *pad; + GstPad *pad; - int flags; + int flags; GstByteStream *bs; + gboolean eos; }; static int @@ -54,6 +55,7 @@ gst_open (URLContext *h, const char *filename, int flags) } info->bs = gst_bytestream_new (pad); + info->eos = FALSE; h->priv_data = (void *) info; @@ -71,10 +73,36 @@ gst_read (URLContext *h, unsigned char *buf, int size) info = (GstProtocolInfo *) h->priv_data; bs = info->bs; + if (info->eos) + return 0; + total = gst_bytestream_peek_bytes (bs, &data, size); - memcpy (buf, data, total); - gst_bytestream_flush_fast (bs, total); + if (total < size) { + GstEvent *event; + guint32 remaining; + + gst_bytestream_get_status (bs, &remaining, &event); + + if (!event) { + g_warning ("gstffmpegprotocol: no bytestream event"); + return total; + } + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_DISCONTINUOUS: + gst_bytestream_flush_fast (bs, remaining); + case GST_EVENT_EOS: + info->eos = TRUE; + break; + default: + break; + } + gst_event_unref (event); + } + + memcpy (buf, data, total); + gst_bytestream_flush (bs, total); return total; } diff --git a/ext/ffmpeg/gstffmpegtypes.c b/ext/ffmpeg/gstffmpegtypes.c new file mode 100644 index 0000000..d201e18 --- /dev/null +++ b/ext/ffmpeg/gstffmpegtypes.c @@ -0,0 +1,129 @@ +/* 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. + */ + +#include +#include +#include + +#include + +static GHashTable *global_types = NULL; + +extern GstCaps* gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *ctx, int id); + +static GstCaps* +gst_ffmpegtypes_typefind (GstBuffer *buffer, gpointer priv) +{ + AVInputFormat *in_plugin; + AVInputFormat *highest = NULL; + gint max = 0; + gint res = 0; + + in_plugin = first_iformat; + + while (in_plugin) { + if (in_plugin->read_probe) { + AVProbeData probe_data; + + probe_data.filename = ""; + probe_data.buf = GST_BUFFER_DATA (buffer); + probe_data.buf_size = GST_BUFFER_SIZE (buffer); + + res = in_plugin->read_probe (&probe_data); + if (res > max) { + max = res; + highest = in_plugin; + } + } + in_plugin = in_plugin->next; + } + if (highest) { + GstCaps *caps; + caps = g_hash_table_lookup (global_types, highest->name); + return caps; + } + + return NULL; +} + +#define ADD_TYPE(key,caps) g_hash_table_insert (global_types, (key), (caps)) + +static void +register_standard_formats (void) +{ + global_types = g_hash_table_new (g_str_hash, g_str_equal); + + ADD_TYPE ("avi", GST_CAPS_NEW ("ffmpeg_type_avi", "video/avi", NULL)); + ADD_TYPE ("mpeg", GST_CAPS_NEW ("ffmpeg_type_mpeg", "video/mpeg", + "systemstream", GST_PROPS_BOOLEAN (TRUE))); + ADD_TYPE ("mpegts", GST_CAPS_NEW ("ffmpeg_type_mpegts", "video/x-mpegts", + "systemstream", GST_PROPS_BOOLEAN (TRUE))); + ADD_TYPE ("rm", GST_CAPS_NEW ("ffmpeg_type_rm", "audio/x-pn-realaudio", NULL)); + ADD_TYPE ("asf", GST_CAPS_NEW ("ffmpeg_type_asf", "video/x-ms-asf", NULL)); + ADD_TYPE ("avi", GST_CAPS_NEW ("ffmpeg_type_avi", "video/avi", + "format", GST_PROPS_STRING ("AVI"))); + ADD_TYPE ("mov", GST_CAPS_NEW ("ffmpeg_type_mov", "video/quicktime", NULL)); + ADD_TYPE ("swf", GST_CAPS_NEW ("ffmpeg_type_swf", "application/x-shockwave-flash", NULL)); + ADD_TYPE ("au", GST_CAPS_NEW ("ffmpeg_type_au", "audio/basic", NULL)); + ADD_TYPE ("mov", GST_CAPS_NEW ("ffmpeg_type_mov", "video/quicktime", NULL)); +} + +gboolean +gst_ffmpegtypes_register (GstPlugin *plugin) +{ + AVInputFormat *in_plugin; + GstTypeFactory *factory; + GstTypeDefinition *definition; + + in_plugin = first_iformat; + + while (in_plugin) { + gchar *type_name; + gchar *p; + + if (!in_plugin->read_probe) + goto next; + + /* construct the type */ + type_name = g_strdup_printf("fftype_%s", in_plugin->name); + + p = type_name; + + while (*p) { + if (*p == '.') *p = '_'; + p++; + } + + definition = g_new0 (GstTypeDefinition, 1); + definition->name = type_name; + definition->mime = type_name; + definition->exts = g_strdup (in_plugin->extensions); + definition->typefindfunc = gst_ffmpegtypes_typefind; + + factory = gst_type_factory_new (definition); + + /* The very last thing is to register the elementfactory with the plugin. */ + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); +next: + in_plugin = in_plugin->next; + } + register_standard_formats (); + + return TRUE; +} -- 2.7.4