From 4996d4c7d2eae47dfb9b819a4363065a6790fbed Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Nov 2002 23:53:46 +0000 Subject: [PATCH] Release early.. try to wrap more ffmpeg stuff, like muxers and demuxers. Original commit message from CVS: Release early.. try to wrap more ffmpeg stuff, like muxers and demuxers. This thing needs a fix in ffmpeg (which I will send to the ffmpeg authors eventually) --- common | 2 +- ext/ffmpeg/Makefile.am | 13 +- ext/ffmpeg/gstffmpeg.c | 16 +- ext/ffmpeg/gstffmpegcodecmap.c | 237 +++++++++++++++++++++++ ext/ffmpeg/gstffmpegdec.c | 42 +++- ext/ffmpeg/gstffmpegdec.h | 99 ---------- ext/ffmpeg/gstffmpegdemux.c | 370 +++++++++++++++++++++++++++++++++++ ext/ffmpeg/gstffmpegenc.c | 47 ++++- ext/ffmpeg/gstffmpegenc.h | 105 ---------- ext/ffmpeg/gstffmpegmux.c | 428 +++++++++++++++++++++++++++++++++++++++++ ext/ffmpeg/gstffmpegprotocol.c | 102 ++++++++++ 11 files changed, 1245 insertions(+), 216 deletions(-) create mode 100644 ext/ffmpeg/gstffmpegcodecmap.c delete mode 100644 ext/ffmpeg/gstffmpegdec.h create mode 100644 ext/ffmpeg/gstffmpegdemux.c delete mode 100644 ext/ffmpeg/gstffmpegenc.h create mode 100644 ext/ffmpeg/gstffmpegmux.c create mode 100644 ext/ffmpeg/gstffmpegprotocol.c diff --git a/common b/common index 2f6d9cf..1ca7d9a 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 2f6d9cfdaaa83ab454d263d6eba88046debadc2d +Subproject commit 1ca7d9a20180cab830f4383cde5ba932338e50b1 diff --git a/ext/ffmpeg/Makefile.am b/ext/ffmpeg/Makefile.am index deffae7..a4df85c 100644 --- a/ext/ffmpeg/Makefile.am +++ b/ext/ffmpeg/Makefile.am @@ -2,9 +2,16 @@ plugindir = $(libdir)/gst plugin_LTLIBRARIES = libgstffmpeg.la -libgstffmpeg_la_SOURCES = gstffmpeg.c gstffmpegenc.c gstffmpegdec.c -libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) -I/opt/src/sourceforge/ffmpeg/ +libgstffmpeg_la_SOURCES = gstffmpeg.c \ + gstffmpegenc.c \ + gstffmpegdec.c \ + gstffmpegdemux.c \ + gstffmpegmux.c \ + gstffmpegprotocol.c \ + gstffmpegcodecmap.c + +libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) -I/opt/src/sourceforge/ffmpeg/ -I/opt/src/sourceforge/ffmpeg/libavcodec/ libgstffmpeg_la_LIBADD = libgstffmpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -L/opt/src/sourceforge/ffmpeg/libavcodec -lavcodec -L/opt/src/sourceforge/ffmpeg/libav -lavformat -noinst_HEADERS = gstffmpegenc.h gstffmpegdec.h +noinst_HEADERS = diff --git a/ext/ffmpeg/gstffmpeg.c b/ext/ffmpeg/gstffmpeg.c index 24e22a4..dde73cc 100644 --- a/ext/ffmpeg/gstffmpeg.c +++ b/ext/ffmpeg/gstffmpeg.c @@ -20,17 +20,29 @@ /* First, include the header file for the plugin, to bring in the * object definition and other useful things. */ -#include "gstffmpegdec.h" -#include "gstffmpegenc.h" + +#include +#include + +#include + +extern gboolean gst_ffmpegdemux_register (GstPlugin *plugin); +extern gboolean gst_ffmpegdec_register (GstPlugin *plugin); +extern gboolean gst_ffmpegenc_register (GstPlugin *plugin); static gboolean plugin_init (GModule *module, GstPlugin *plugin) { avcodec_init (); avcodec_register_all (); + av_register_all (); + + if (!gst_library_load ("gstbytestream")) + return FALSE; gst_ffmpegenc_register (plugin); gst_ffmpegdec_register (plugin); + gst_ffmpegdemux_register (plugin); /* 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 new file mode 100644 index 0000000..fa66f7f --- /dev/null +++ b/ext/ffmpeg/gstffmpegcodecmap.c @@ -0,0 +1,237 @@ +/* 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 + +GstCaps * +gst_ffmpegcodec_codec_context_to_caps (AVCodecContext *context) +{ + switch (context->codec_id) { + case CODEC_ID_NONE: + return GST_CAPS_NEW ("ffmpeg_none", + "unkown/unkown", + NULL); + break; + case CODEC_ID_MPEG1VIDEO: + return GST_CAPS_NEW ("ffmpeg_mpeg1video", + "video/mpeg", + "mpegversion", GST_PROPS_INT (1), + "systemstream", GST_PROPS_BOOLEAN (FALSE) + ); + break; + case CODEC_ID_H263: + return GST_CAPS_NEW ("ffmpeg_h263", + "video/H263", + NULL); + break; + case CODEC_ID_RV10: + return GST_CAPS_NEW ("ffmpeg_rv10", + "video/x-rv10", + NULL); + break; + case CODEC_ID_MP2: + return GST_CAPS_NEW ("ffmpeg_mp2", + "audio/mp3", + NULL); + break; + case CODEC_ID_MP3LAME: + return GST_CAPS_NEW ("ffmpeg_mp3", + "audio/mp3", + NULL); + break; + case CODEC_ID_VORBIS: + return GST_CAPS_NEW ("ffmpeg_vorbis", + "application/x-ogg", + NULL); + break; + case CODEC_ID_AC3: + return GST_CAPS_NEW ("ffmpeg_ac3", + "audio/ac3", + NULL); + break; + case CODEC_ID_MJPEG: + return GST_CAPS_NEW ("ffmpeg_mjpeg", + "video/x-mjpeg", + 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) + ); + break; + case CODEC_ID_RAWVIDEO: + return GST_CAPS_NEW ("ffmpeg_rawvideo", + "video/raw", + 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) + ); + 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) + ); + 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) + ); + 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) + ); + break; + case CODEC_ID_WMV2: + return GST_CAPS_NEW ("ffmpeg_wmv2", + "unkown/unkown", + NULL); + break; + case CODEC_ID_H263P: + return GST_CAPS_NEW ("ffmpeg_h263p", + "unkown/unkown", + NULL); + break; + case CODEC_ID_H263I: + return GST_CAPS_NEW ("ffmpeg_h263i", + "unkown/unkown", + NULL); + break; + case CODEC_ID_SVQ1: + return GST_CAPS_NEW ("ffmpeg_svq1", + "unkown/unkown", + NULL); + break; + case CODEC_ID_DVVIDEO: + return GST_CAPS_NEW ("ffmpeg_dvvideo", + "unkown/unkown", + NULL); + break; + case CODEC_ID_DVAUDIO: + return GST_CAPS_NEW ("ffmpeg_dvaudio", + "unkown/unkown", + NULL); + break; + case CODEC_ID_WMAV1: + return GST_CAPS_NEW ("ffmpeg_wmav1", + "unkown/unkown", + NULL); + break; + case CODEC_ID_WMAV2: + return GST_CAPS_NEW ("ffmpeg_wmav2", + "unkown/unkown", + NULL); + break; + case CODEC_ID_MACE3: + return GST_CAPS_NEW ("ffmpeg_mace3", + "unkown/unkown", + NULL); + break; + case CODEC_ID_MACE6: + return GST_CAPS_NEW ("ffmpeg_mace6", + "unkown/unkown", + NULL); + break; + /* various pcm "codecs" */ + case CODEC_ID_PCM_S16LE: + return GST_CAPS_NEW ("ffmpeg_s16le", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_S16BE: + return GST_CAPS_NEW ("ffmpeg_s16be", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_U16LE: + return GST_CAPS_NEW ("ffmpeg_u16le", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_U16BE: + return GST_CAPS_NEW ("ffmpeg_u16be", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_S8: + return GST_CAPS_NEW ("ffmpeg_s8", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_U8: + return GST_CAPS_NEW ("ffmpeg_u8", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_MULAW: + return GST_CAPS_NEW ("ffmpeg_mulaw", + "unkown/unkown", + NULL); + break; + case CODEC_ID_PCM_ALAW: + return GST_CAPS_NEW ("ffmpeg_alaw", + "unkown/unkown", + NULL); + break; + /* various adpcm codecs */ + case CODEC_ID_ADPCM_IMA_QT: + return GST_CAPS_NEW ("ffmpeg_adpcm_ima_qt", + "unkown/unkown", + NULL); + break; + case CODEC_ID_ADPCM_IMA_WAV: + return GST_CAPS_NEW ("ffmpeg_adpcm_ima_wav", + "unkown/unkown", + NULL); + break; + case CODEC_ID_ADPCM_MS: + return GST_CAPS_NEW ("ffmpeg_adpcm_ms", + "unkown/unkown", + NULL); + break; + default: + g_warning ("no caps found for codec id %d\n", context->codec_id); + break; + } + + return NULL; +} diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index f66fdd9..d756f55 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -17,9 +17,43 @@ * Boston, MA 02111-1307, USA. */ -#include "gstffmpegdec.h" - +#include #include +#include + +#include + +typedef struct _GstFFMpegDec GstFFMpegDec; + +struct _GstFFMpegDec { + GstElement element; + + /* We need to keep track of our pads, so we do so here. */ + GstPad *srcpad; + GstPad *sinkpad; + + AVCodecContext *context; + AVPicture *picture; +}; + +typedef struct _GstFFMpegDecClass GstFFMpegDecClass; + +struct _GstFFMpegDecClass { + GstElementClass parent_class; + + AVCodec *in_plugin; +}; + +#define GST_TYPE_FFMPEGDEC \ + (gst_ffmpegdec_get_type()) +#define GST_FFMPEGDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec)) +#define GST_FFMPEGDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDecClass)) +#define GST_IS_FFMPEGDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) +#define GST_IS_FFMPEGDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) enum { /* FILL ME */ @@ -341,7 +375,7 @@ gst_ffmpegdec_register (GstPlugin *plugin) goto next; } /* construct the type */ - type_name = g_strdup_printf("ffmpeg%s_%s", codec_type, in_plugin->name); + type_name = g_strdup_printf("ff%s_%s", codec_type, in_plugin->name); /* if it's already registered, drop it */ if (g_type_from_name(type_name)) { @@ -370,6 +404,8 @@ gst_ffmpegdec_register (GstPlugin *plugin) 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)); diff --git a/ext/ffmpeg/gstffmpegdec.h b/ext/ffmpeg/gstffmpegdec.h deleted file mode 100644 index 246123d..0000000 --- a/ext/ffmpeg/gstffmpegdec.h +++ /dev/null @@ -1,99 +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. - */ - - -#ifndef __GST_FFMPEGDEC_H__ -#define __GST_FFMPEGDEC_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef __GST_FFMPEG_AV_H__ -#define __GST_FFMPEG_AV_H__ -#undef ABS -#undef MAX -#undef MIN -#include -#include -#endif /* __GST_FFMPEG_AV_H__ */ - -/* This is the definition of the element's object structure. */ -typedef struct _GstFFMpegDec GstFFMpegDec; - -/* The structure itself is derived from GstElement, as can be seen by the - * fact that there's a complete instance of the GstElement structure at - * the beginning of the object. This allows the element to be cast to - * an Element or even an Object. - */ -struct _GstFFMpegDec { - GstElement element; - - /* We need to keep track of our pads, so we do so here. */ - GstPad *srcpad; - GstPad *sinkpad; - - AVCodecContext *context; - AVPicture *picture; -}; - -/* The other half of the object is its class. The class also derives from - * the same parent, though it must be the class structure this time. - * Function pointers for polymophic methods and signals are placed in this - * structure. */ -typedef struct _GstFFMpegDecClass GstFFMpegDecClass; - -struct _GstFFMpegDecClass { - GstElementClass parent_class; - - AVCodec *in_plugin; -}; - -/* Five standard preprocessing macros are used in the Gtk+ object system. - * The first uses the object's _get_type function to return the GType - * of the object. - */ -#define GST_TYPE_FFMPEGDEC \ - (gst_ffmpegdec_get_type()) -/* The second is a checking cast to the correct type. If the object passed - * is not the right type, a warning will be generated on stderr. - */ -#define GST_FFMPEGDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec)) -/* The third is a checking cast of the class instead of the object. */ -#define GST_FFMPEGDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDec)) -/* The last two simply check to see if the passed pointer is an object or - * class of the correct type. */ -#define GST_IS_FFMPEGDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) -#define GST_IS_FFMPEGDEC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) - -gboolean gst_ffmpegdec_register (GstPlugin *plugin); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GST_FFMPEGDEC_H__ */ diff --git a/ext/ffmpeg/gstffmpegdemux.c b/ext/ffmpeg/gstffmpegdemux.c new file mode 100644 index 0000000..c066c2c --- /dev/null +++ b/ext/ffmpeg/gstffmpegdemux.c @@ -0,0 +1,370 @@ +/* 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 + +extern URLProtocol gstreamer_protocol; + +typedef enum { + STATE_OPEN, + STATE_STREAM_INFO, + STATE_DEMUX, + STATE_END, +} DemuxState; + +typedef struct _GstFFMpegDemux GstFFMpegDemux; + +struct _GstFFMpegDemux { + GstElement element; + + /* We need to keep track of our pads, so we do so here. */ + GstPad *sinkpad; + + AVFormatContext *context; + DemuxState state; + + GstPad *srcpads[MAX_STREAMS]; +}; + +typedef struct _GstFFMpegDemuxClass GstFFMpegDemuxClass; + +struct _GstFFMpegDemuxClass { + GstElementClass parent_class; + + AVInputFormat *in_plugin; +}; + +#define GST_TYPE_FFMPEGDEC \ + (gst_ffmpegdec_get_type()) +#define GST_FFMPEGDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDemux)) +#define GST_FFMPEGDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDemuxClass)) +#define GST_IS_FFMPEGDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC)) +#define GST_IS_FFMPEGDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC)) + +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdemux_sink_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + NULL +) + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdemux_audio_src_factory, + "audio_%02d", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + NULL +) + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegdemux_video_src_factory, + "video_%02d", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + NULL +) + +static GHashTable *global_plugins; + +/* A number of functon prototypes are given so we can refer to them later. */ +static void gst_ffmpegdemux_class_init (GstFFMpegDemuxClass *klass); +static void gst_ffmpegdemux_init (GstFFMpegDemux *ffmpegdemux); + +static void gst_ffmpegdemux_loop (GstElement *element); + +static void gst_ffmpegdemux_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *pspec); +static void gst_ffmpegdemux_get_property (GObject *object, guint prop_id, GValue *value, + GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; + +/*static guint gst_ffmpegdemux_signals[LAST_SIGNAL] = { 0 }; */ + +static void +gst_ffmpegdemux_class_init (GstFFMpegDemuxClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + 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, + GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class))); + + gobject_class->set_property = gst_ffmpegdemux_set_property; + gobject_class->get_property = gst_ffmpegdemux_get_property; +} + +static void +gst_ffmpegdemux_init(GstFFMpegDemux *ffmpegdemux) +{ + //GstFFMpegDemuxClass *oclass = (GstFFMpegDemuxClass*)(G_OBJECT_GET_CLASS (ffmpegdemux)); + + ffmpegdemux->sinkpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_sink_factory), "sink"); + + gst_element_add_pad (GST_ELEMENT (ffmpegdemux), ffmpegdemux->sinkpad); + gst_element_set_loop_function (GST_ELEMENT (ffmpegdemux), gst_ffmpegdemux_loop); + + ffmpegdemux->state = STATE_OPEN; +} + +static void +gst_ffmpegdemux_loop (GstElement *element) +{ + GstFFMpegDemux *ffmpegdemux = (GstFFMpegDemux *)(element); + GstFFMpegDemuxClass *oclass = (GstFFMpegDemuxClass*)(G_OBJECT_GET_CLASS (ffmpegdemux)); + gint res = 0; + + switch (ffmpegdemux->state) { + case STATE_OPEN: + { + res = av_open_input_file (&ffmpegdemux->context, + g_strdup_printf ("gstreamer://%p", ffmpegdemux->sinkpad), + oclass->in_plugin, + 0, + NULL); + + /* this doesn't work */ + av_set_pts_info (ffmpegdemux->context, 33, 1, 100000); + + ffmpegdemux->state = STATE_DEMUX; + break; + } + case STATE_DEMUX: + { + gint res; + AVPacket pkt; + AVFormatContext *ct = ffmpegdemux->context; + AVStream *st; + GstPad *pad; + + res = av_read_packet(ct, &pkt); + if (res < 0) { + gint i; + + for (i = 0; i < ct->nb_streams; i++) { + GstPad *pad; + + pad = ffmpegdemux->srcpads[i]; + + if (GST_PAD_IS_USABLE (pad)) { + gst_pad_push (pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS))); + } + } + gst_element_set_eos (element); + return; + } + + st = ct->streams[pkt.stream_index]; + + if (st->codec_info_state == 0) { + gchar *padname = NULL; + GstPadTemplate *templ = 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); + } + 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); + } + + if (padname != NULL) { + 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); + return; + } + } + else { + pad = ffmpegdemux->srcpads[pkt.stream_index]; + } + + if (GST_PAD_IS_USABLE (pad)) { + GstBuffer *outbuf; + + 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; + } + else { + GST_BUFFER_TIMESTAMP (outbuf) = -1; + } + + gst_pad_push (pad, outbuf); + } + break; + } + default: + gst_element_set_eos (element); + break; + } +} + +static void +gst_ffmpegdemux_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstFFMpegDemux *ffmpegdemux; + + /* Get a pointer of the right type. */ + ffmpegdemux = (GstFFMpegDemux *)(object); + + /* Check the argument id to see which argument we're setting. */ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* The set function is simply the inverse of the get fuction. */ +static void +gst_ffmpegdemux_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstFFMpegDemux *ffmpegdemux; + + /* It's not null if we got it, but it might not be ours */ + ffmpegdemux = (GstFFMpegDemux *)(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +gst_ffmpegdemux_register (GstPlugin *plugin) +{ + GstElementFactory *factory; + GTypeInfo typeinfo = { + sizeof(GstFFMpegDemuxClass), + NULL, + NULL, + (GClassInitFunc)gst_ffmpegdemux_class_init, + NULL, + NULL, + sizeof(GstFFMpegDemux), + 0, + (GInstanceInitFunc)gst_ffmpegdemux_init, + }; + GType type; + GstElementDetails *details; + AVInputFormat *in_plugin; + + in_plugin = first_iformat; + + global_plugins = g_hash_table_new (NULL, NULL); + + while (in_plugin) { + gchar *type_name; + gchar *p; + + /* construct the type */ + type_name = g_strdup_printf("ffdemux_%s", in_plugin->name); + + p = type_name; + + while (*p) { + if (*p == '.') *p = '_'; + p++; + } + + /* if it's already registered, drop it */ + if (g_type_from_name(type_name)) { + g_free(type_name); + goto next; + } + + /* create the gtk type now */ + type = g_type_register_static(GST_TYPE_ELEMENT, type_name , &typeinfo, 0); + + /* construct the element details struct */ + details = g_new0 (GstElementDetails,1); + details->longname = g_strdup (in_plugin->name); + details->klass = "Codec/Demuxer/FFMpeg"; + details->license = "LGPL"; + details->description = g_strdup (in_plugin->name); + details->version = g_strdup("1.0.0"); + details->author = g_strdup("The FFMPEG crew, GStreamer plugin by Wim Taymans "); + details->copyright = g_strdup("(c) 2002"); + + 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_ffmpegdemux_sink_factory)); + + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_video_src_factory)); + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (gst_ffmpegdemux_audio_src_factory)); + + /* 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_protocol (&gstreamer_protocol); + + return TRUE; +} diff --git a/ext/ffmpeg/gstffmpegenc.c b/ext/ffmpeg/gstffmpegenc.c index 52bc7fc..fdf8265 100644 --- a/ext/ffmpeg/gstffmpegenc.c +++ b/ext/ffmpeg/gstffmpegenc.c @@ -17,9 +17,50 @@ * Boston, MA 02111-1307, USA. */ -#include "gstffmpegenc.h" - #include +#include +#include + +#include + +typedef struct _GstFFMpegEnc GstFFMpegEnc; + +struct _GstFFMpegEnc { + GstElement element; + + /* We need to keep track of our pads, so we do so here. */ + GstPad *srcpad; + GstPad *sinkpad; + + gboolean need_resample; + gint in_width, in_height; + gint out_width, out_height; + + guchar *buffer; + gint buffer_pos; + + AVCodecContext *context; + ImgReSampleContext *resample; +}; + +typedef struct _GstFFMpegEncClass GstFFMpegEncClass; + +struct _GstFFMpegEncClass { + GstElementClass parent_class; + + AVCodec *in_plugin; +}; + +#define GST_TYPE_FFMPEGENC \ + (gst_ffmpegenc_get_type()) +#define GST_FFMPEGENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc)) +#define GST_FFMPEGENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEncClass)) +#define GST_IS_FFMPEGENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC)) +#define GST_IS_FFMPEGENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC)) #define VIDEO_BUFFER_SIZE (1024*1024) @@ -515,7 +556,7 @@ gst_ffmpegenc_register (GstPlugin *plugin) goto next; } /* construct the type */ - type_name = g_strdup_printf("ffmpeg%s_%s", codec_type, in_plugin->name); + type_name = g_strdup_printf("ff%s_%s", codec_type, in_plugin->name); /* if it's already registered, drop it */ if (g_type_from_name(type_name)) { diff --git a/ext/ffmpeg/gstffmpegenc.h b/ext/ffmpeg/gstffmpegenc.h deleted file mode 100644 index 2c4423f..0000000 --- a/ext/ffmpeg/gstffmpegenc.h +++ /dev/null @@ -1,105 +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. - */ - - -#ifndef __GST_FFMPEGENC_H__ -#define __GST_FFMPEGENC_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef __GST_FFMPEG_AV_H__ -#define __GST_FFMPEG_AV_H__ -#undef ABS -#undef MAX -#undef MIN -#include -#include -#endif /* __GST_FFMPEG_AV_H__ */ - -/* This is the definition of the element's object structure. */ -typedef struct _GstFFMpegEnc GstFFMpegEnc; - -/* The structure itself is derived from GstElement, as can be seen by the - * fact that there's a complete instance of the GstElement structure at - * the beginning of the object. This allows the element to be cast to - * an Element or even an Object. - */ -struct _GstFFMpegEnc { - GstElement element; - - /* We need to keep track of our pads, so we do so here. */ - GstPad *srcpad; - GstPad *sinkpad; - - gboolean need_resample; - gint in_width, in_height; - gint out_width, out_height; - - guchar *buffer; - gint buffer_pos; - - AVCodecContext *context; - ImgReSampleContext *resample; -}; - -/* The other half of the object is its class. The class also derives from - * the same parent, though it must be the class structure this time. - * Function pointers for polymophic methods and signals are placed in this - * structure. */ -typedef struct _GstFFMpegEncClass GstFFMpegEncClass; - -struct _GstFFMpegEncClass { - GstElementClass parent_class; - - AVCodec *in_plugin; -}; - -/* Five standard preprocessing macros are used in the Gtk+ object system. - * The first uses the object's _get_type function to return the GType - * of the object. - */ -#define GST_TYPE_FFMPEGENC \ - (gst_ffmpegenc_get_type()) -/* The second is a checking cast to the correct type. If the object passed - * is not the right type, a warning will be generated on stderr. - */ -#define GST_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc)) -/* The third is a checking cast of the class instead of the object. */ -#define GST_FFMPEGENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEnc)) -/* The last two simply check to see if the passed pointer is an object or - * class of the correct type. */ -#define GST_IS_FFMPEGENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC)) -#define GST_IS_FFMPEGENC_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC)) - -gboolean gst_ffmpegenc_register (GstPlugin *plugin); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GST_FFMPEGENC_H__ */ diff --git a/ext/ffmpeg/gstffmpegmux.c b/ext/ffmpeg/gstffmpegmux.c new file mode 100644 index 0000000..849720a --- /dev/null +++ b/ext/ffmpeg/gstffmpegmux.c @@ -0,0 +1,428 @@ +/* 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 + +typedef struct _GstFFMpegMux GstFFMpegMux; + +struct _GstFFMpegMux { + GstElement element; + + /* We need to keep track of our pads, so we do so here. */ + GstPad *srcpad; + GstPad *sinkpad; + + AVCodecContext *context; + AVPicture *picture; +}; + +typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass; + +struct _GstFFMpegMuxClass { + GstElementClass parent_class; + + AVCodec *in_plugin; +}; + +#define GST_TYPE_FFMPEGMUX \ + (gst_ffmpegdec_get_type()) +#define GST_FFMPEGMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGMUX,GstFFMpegMux)) +#define GST_FFMPEGMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGMUX,GstFFMpegMuxClass)) +#define GST_IS_FFMPEGMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGMUX)) +#define GST_IS_FFMPEGMUX_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGMUX)) + +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegmux_sink_factory, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "ffmpegmux_sink", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids") + ), + GST_CAPS_NEW ( + "ffmpegmux_sink", + "video/mpeg", + NULL + ) +) + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegmux_audio_src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "ffmpegmux_src", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT_RANGE (8000, 96000), + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +) + +/* This factory is much simpler, and defines the source pad. */ +GST_PAD_TEMPLATE_FACTORY (gst_ffmpegmux_video_src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "ffmpegmux_src", + "video/raw", + "format", GST_PROPS_LIST ( + GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")) + ), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) +) + +static GHashTable *global_plugins; + +/* A number of functon prototypes are given so we can refer to them later. */ +static void gst_ffmpegmux_class_init (GstFFMpegMuxClass *klass); +static void gst_ffmpegmux_init (GstFFMpegMux *ffmpegmux); + +static void gst_ffmpegmux_chain_audio (GstPad *pad, GstBuffer *buffer); +static void gst_ffmpegmux_chain_video (GstPad *pad, GstBuffer *buffer); + +static void gst_ffmpegmux_set_property (GObject *object, guint prop_id, const GValue *value, + GParamSpec *pspec); +static void gst_ffmpegmux_get_property (GObject *object, guint prop_id, GValue *value, + GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; + +/*static guint gst_ffmpegmux_signals[LAST_SIGNAL] = { 0 }; */ + +static void +gst_ffmpegmux_class_init (GstFFMpegMuxClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + 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, + GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class))); + + gobject_class->set_property = gst_ffmpegmux_set_property; + gobject_class->get_property = gst_ffmpegmux_get_property; +} + +static GstPadConnectReturn +gst_ffmpegmux_sinkconnect (GstPad *pad, GstCaps *caps) +{ + GstFFMpegMux *ffmpegmux = (GstFFMpegMux *)(gst_pad_get_parent (pad)); + GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass*)(G_OBJECT_GET_CLASS (ffmpegmux)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_CONNECT_DELAYED; + + if (gst_caps_has_property_typed (caps, "width", GST_PROPS_INT_TYPE)) + gst_caps_get_int (caps, "width", &ffmpegmux->context->width); + if (gst_caps_has_property_typed (caps, "height", GST_PROPS_INT_TYPE)) + gst_caps_get_int (caps, "height", &ffmpegmux->context->height); + + ffmpegmux->context->pix_fmt = PIX_FMT_YUV420P; + ffmpegmux->context->frame_rate = 23 * FRAME_RATE_BASE; + ffmpegmux->context->bit_rate = 0; + + /* FIXME bug in ffmpeg */ + if (avcodec_open (ffmpegmux->context, avcodec_find_encoder(CODEC_ID_MPEG1VIDEO)) <0 ) { + g_warning ("ffmpegmux: could not open codec"); + return GST_PAD_CONNECT_REFUSED; + } + + if (avcodec_open (ffmpegmux->context, oclass->in_plugin) < 0) { + g_warning ("ffmpegmux: could not open codec"); + return GST_PAD_CONNECT_REFUSED; + } + return GST_PAD_CONNECT_OK; +} + +static void +gst_ffmpegmux_init(GstFFMpegMux *ffmpegmux) +{ + GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass*)(G_OBJECT_GET_CLASS (ffmpegmux)); + + ffmpegmux->context = g_malloc0 (sizeof (AVCodecContext)); + + ffmpegmux->sinkpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (gst_ffmpegmux_sink_factory), "sink"); + gst_pad_set_connect_function (ffmpegmux->sinkpad, gst_ffmpegmux_sinkconnect); + + if (oclass->in_plugin->type == CODEC_TYPE_VIDEO) { + ffmpegmux->srcpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (gst_ffmpegmux_video_src_factory), "src"); + gst_pad_set_chain_function (ffmpegmux->sinkpad, gst_ffmpegmux_chain_video); + } + else if (oclass->in_plugin->type == CODEC_TYPE_AUDIO) { + ffmpegmux->srcpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (gst_ffmpegmux_audio_src_factory), "src"); + gst_pad_set_chain_function (ffmpegmux->sinkpad, gst_ffmpegmux_chain_audio); + } + + gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->sinkpad); + gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->srcpad); + + ffmpegmux->picture = g_malloc0 (sizeof (AVPicture)); +} + +static void +gst_ffmpegmux_chain_audio (GstPad *pad, GstBuffer *inbuf) +{ + /*GstFFMpegMux *ffmpegmux = (GstFFMpegMux *)(gst_pad_get_parent (pad)); */ + gpointer data; + gint size; + + data = GST_BUFFER_DATA (inbuf); + size = GST_BUFFER_SIZE (inbuf); + + GST_DEBUG (0, "got buffer %p %d", data, size); + + gst_buffer_unref (inbuf); +} + +static void +gst_ffmpegmux_chain_video (GstPad *pad, GstBuffer *inbuf) +{ + GstBuffer *outbuf; + GstFFMpegMux *ffmpegmux = (GstFFMpegMux *)(gst_pad_get_parent (pad)); + guchar *data; + gint size, frame_size, len; + gint have_picture; + + data = GST_BUFFER_DATA (inbuf); + size = GST_BUFFER_SIZE (inbuf); + + do { + ffmpegmux->context->frame_number++; + + len = avcodec_decode_video (ffmpegmux->context, ffmpegmux->picture, + &have_picture, data, size); + + if (len < 0) { + g_warning ("ffmpegmux: decoding error"); + break; + } + + if (have_picture) { + guchar *picdata, *picdata2, *outdata, *outdata2; + gint xsize, i, width, height; + + width = ffmpegmux->context->width; + height = ffmpegmux->context->height; + + if (!GST_PAD_CAPS (ffmpegmux->srcpad)) { + gst_pad_try_set_caps (ffmpegmux->srcpad, + GST_CAPS_NEW ( + "ffmpegmux_src", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420")), + "width", GST_PROPS_INT (width), + "height", GST_PROPS_INT (height) + )); + } + + frame_size = width * height; + + outbuf = gst_buffer_new (); + GST_BUFFER_SIZE (outbuf) = (frame_size*3)>>1; + outdata = GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf)); + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf); + + picdata = ffmpegmux->picture->data[0]; + xsize = ffmpegmux->picture->linesize[0]; + for (i=height; i; i--) { + memcpy (outdata, picdata, width); + outdata += width; + picdata += xsize; + } + + frame_size >>= 2; + width >>= 1; + height >>= 1; + outdata2 = outdata + frame_size; + + picdata = ffmpegmux->picture->data[1]; + picdata2 = ffmpegmux->picture->data[2]; + xsize = ffmpegmux->picture->linesize[1]; + for (i=height; i; i--) { + memcpy (outdata, picdata, width); + memcpy (outdata2, picdata2, width); + outdata += width; outdata2 += width; + picdata += xsize; picdata2 += xsize; + } + + gst_pad_push (ffmpegmux->srcpad, outbuf); + } + + size -= len; + data += len; + } + while (size > 0); + + gst_buffer_unref (inbuf); +} + +static void +gst_ffmpegmux_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstFFMpegMux *ffmpegmux; + + /* Get a pointer of the right type. */ + ffmpegmux = (GstFFMpegMux *)(object); + + /* Check the argument id to see which argument we're setting. */ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/* The set function is simply the inverse of the get fuction. */ +static void +gst_ffmpegmux_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstFFMpegMux *ffmpegmux; + + /* It's not null if we got it, but it might not be ours */ + ffmpegmux = (GstFFMpegMux *)(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +gst_ffmpegmux_register (GstPlugin *plugin) +{ + GstElementFactory *factory; + GTypeInfo typeinfo = { + sizeof(GstFFMpegMuxClass), + NULL, + NULL, + (GClassInitFunc)gst_ffmpegmux_class_init, + NULL, + NULL, + sizeof(GstFFMpegMux), + 0, + (GInstanceInitFunc)gst_ffmpegmux_init, + }; + GType type; + GstElementDetails *details; + AVCodec *in_plugin; + + in_plugin = first_avcodec; + + global_plugins = g_hash_table_new (NULL, NULL); + + while (in_plugin) { + gchar *type_name; + gchar *codec_type; + + if (in_plugin->decode) { + codec_type = "dec"; + } + else { + goto next; + } + /* construct the type */ + type_name = g_strdup_printf("ff%s_%s", codec_type, in_plugin->name); + + /* if it's already registered, drop it */ + if (g_type_from_name(type_name)) { + g_free(type_name); + goto next; + } + + /* create the gtk type now */ + type = g_type_register_static(GST_TYPE_ELEMENT, type_name , &typeinfo, 0); + + /* construct the element details struct */ + details = g_new0 (GstElementDetails,1); + details->longname = g_strdup (in_plugin->name); + details->klass = "Codec/FFMpeg"; + details->license = "LGPL"; + details->description = g_strdup (in_plugin->name); + details->version = g_strdup("1.0.0"); + 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_ffmpegmux_sink_factory)); + + if (in_plugin->type == CODEC_TYPE_VIDEO) { + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (gst_ffmpegmux_video_src_factory)); + } + else if (in_plugin->type == CODEC_TYPE_AUDIO) { + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (gst_ffmpegmux_audio_src_factory)); + } + + /* 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; + } + + return TRUE; +} diff --git a/ext/ffmpeg/gstffmpegprotocol.c b/ext/ffmpeg/gstffmpegprotocol.c new file mode 100644 index 0000000..21d3858 --- /dev/null +++ b/ext/ffmpeg/gstffmpegprotocol.c @@ -0,0 +1,102 @@ +/* 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 +#include + + +typedef struct _GstProtocolInfo GstProtocolInfo; + +struct _GstProtocolInfo +{ + GstPad *pad; + + int flags; + GstByteStream *bs; +}; + +static int +gst_open (URLContext *h, const char *filename, int flags) +{ + GstProtocolInfo *info; + GstPad *pad; + + info = g_new0 (GstProtocolInfo, 1); + info->flags = flags; + + if (sscanf (&filename[12], "%p", &pad) != 1) { + g_warning ("could not decode pad from %s", &filename[12]); + return -EIO; + } + + if (!GST_IS_PAD (pad)) { + g_warning ("decoded string is not a pad, %s", &filename[12]); + return -EIO; + } + + info->bs = gst_bytestream_new (pad); + + h->priv_data = (void *) info; + + return 0; +} + +static int +gst_read (URLContext *h, unsigned char *buf, int size) +{ + GstByteStream *bs; + guint32 total; + guint8 *data; + GstProtocolInfo *info; + + info = (GstProtocolInfo *) h->priv_data; + bs = info->bs; + + total = gst_bytestream_peek_bytes (bs, &data, size); + memcpy (buf, data, total); + + gst_bytestream_flush_fast (bs, total); + + return total; +} + +static int gst_write(URLContext *h, unsigned char *buf, int size) +{ + g_print ("write %p, %d\n", buf, size); + + return 0; +} + +static int gst_close(URLContext *h) +{ + return 0; +} + +URLProtocol gstreamer_protocol = { + "gstreamer", + gst_open, + gst_read, + gst_write, + NULL, + gst_close, +}; + -- 2.7.4