diff --git a/ChangeLog b/ChangeLog index 23df3a5817..52c41a4823 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2004-10-04 Wim Taymans + + * ext/libmng/Makefile.am: + * ext/libmng/gstmng.c: (plugin_init): + * ext/libmng/gstmng.h: + * ext/libmng/gstmngdec.c: (gst_mngdec_get_type), + (gst_mngdec_base_init), (gst_mngdec_class_init), + (gst_mngdec_sinklink), (gst_mngdec_init), (gst_mngdec_src_getcaps), + (gst_mngdec_loop), (gst_mngdec_get_property), + (gst_mngdec_set_property), (mngdec_error), (mngdec_openstream), + (mngdec_closestream), (mngdec_handle_sink_event), + (mngdec_readdata), (mngdec_gettickcount), (mngdec_settimer), + (mngdec_processheader), (mngdec_getcanvasline), (mngdec_refresh), + (gst_mngdec_change_state): + * ext/libmng/gstmngdec.h: + * ext/libmng/gstmngenc.c: (gst_mngenc_get_type), + (mng_caps_factory), (raw_caps_factory), (gst_mngenc_base_init), + (gst_mngenc_class_init), (gst_mngenc_sinklink), (gst_mngenc_init), + (gst_mngenc_chain), (gst_mngenc_get_property), + (gst_mngenc_set_property): + * ext/libmng/gstmngenc.h: + Added basic MNG decoder. Needs more work. The encoder does + not work yet. + 2004-10-04 Ronald S. Bultje * gst/realmedia/rmdemux.c: (gst_rmdemux_handle_sink_event), diff --git a/ext/libmng/Makefile.am b/ext/libmng/Makefile.am new file mode 100644 index 0000000000..8936bc3f49 --- /dev/null +++ b/ext/libmng/Makefile.am @@ -0,0 +1,9 @@ + +plugin_LTLIBRARIES = libgstmng.la + +libgstmng_la_SOURCES = gstmng.c gstmngdec.c gstmngenc.c +libgstmng_la_CFLAGS = $(GST_CFLAGS) +libgstmng_la_LIBADD = $(GST_LIBS) $(LIBMNG_LIBS) +libgstmng_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstmngdec.h gstmngenc.h diff --git a/ext/libmng/gstmng.c b/ext/libmng/gstmng.c new file mode 100644 index 0000000000..d84a71b1f8 --- /dev/null +++ b/ext/libmng/gstmng.c @@ -0,0 +1,45 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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_H +#include +#endif + +#include +#include + +#include "gstmngdec.h" +#include "gstmngenc.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_library_load ("gstbytestream")) + return FALSE; + + if (!gst_element_register (plugin, "mngdec", GST_RANK_PRIMARY, + GST_TYPE_MNGDEC)) + return FALSE; + + if (!gst_element_register (plugin, "mngenc", GST_RANK_NONE, GST_TYPE_MNGENC)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mng", + "MNG plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN) diff --git a/ext/libmng/gstmng.h b/ext/libmng/gstmng.h new file mode 100644 index 0000000000..b0dcc19541 --- /dev/null +++ b/ext/libmng/gstmng.h @@ -0,0 +1,22 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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 + +GType gst_mngenc_get_type (void); +extern GstElementDetails gst_mngenc_details; + +extern GstPadTemplate *gst_mng_sink_factory (); +extern GstPadTemplate *gst_mng_src_factory (); diff --git a/ext/libmng/gstmngdec.c b/ext/libmng/gstmngdec.c new file mode 100644 index 0000000000..0266fd57b9 --- /dev/null +++ b/ext/libmng/gstmngdec.c @@ -0,0 +1,516 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * 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_H +#include "config.h" +#endif +#include +#include +#include "gstmngdec.h" +#include + +static GstElementDetails gst_mngdec_details = { + "MNG decoder", + "Codec/Decoder/Image", + "Decode a mng video to raw images", + "Wim Taymans ", +}; + + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0 +}; + +static void gst_mngdec_base_init (gpointer g_class); +static void gst_mngdec_class_init (GstMngDecClass * klass); +static void gst_mngdec_init (GstMngDec * mngdec); + +static void gst_mngdec_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_mngdec_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); + +static GstElementStateReturn gst_mngdec_change_state (GstElement * element); + +static void gst_mngdec_loop (GstElement * element); + +static GstCaps *gst_mngdec_src_getcaps (GstPad * pad); + +static GstElementClass *parent_class = NULL; + + +GType +gst_mngdec_get_type (void) +{ + static GType mngdec_type = 0; + + if (!mngdec_type) { + static const GTypeInfo mngdec_info = { + sizeof (GstMngDecClass), + gst_mngdec_base_init, + NULL, + (GClassInitFunc) gst_mngdec_class_init, + NULL, + NULL, + sizeof (GstMngDec), + 0, + (GInstanceInitFunc) gst_mngdec_init, + }; + + mngdec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstMngDec", + &mngdec_info, 0); + } + return mngdec_type; +} + +static GstStaticPadTemplate gst_mngdec_src_pad_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB) + ); + +static GstStaticPadTemplate gst_mngdec_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-mng, " + "width = (int) [ 16, 4096 ], " + "height = (int) [ 16, 4096 ], " "framerate = (double) [ 0.0, MAX ]") + ); + +static void +gst_mngdec_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_mngdec_src_pad_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_mngdec_sink_pad_template)); + gst_element_class_set_details (element_class, &gst_mngdec_details); +} + +static void +gst_mngdec_class_init (GstMngDecClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gstelement_class->change_state = gst_mngdec_change_state; + + gstelement_class->get_property = gst_mngdec_get_property; + gstelement_class->set_property = gst_mngdec_set_property; + +} + + +static GstPadLinkReturn +gst_mngdec_sinklink (GstPad * pad, const GstCaps * caps) +{ + GstMngDec *mngdec; + GstStructure *structure; + + mngdec = GST_MNGDEC (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + gst_structure_get_double (structure, "framerate", &mngdec->fps); + + return TRUE; +} + +static void +gst_mngdec_init (GstMngDec * mngdec) +{ + mngdec->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_mngdec_sink_pad_template), "sink"); + gst_element_add_pad (GST_ELEMENT (mngdec), mngdec->sinkpad); + + mngdec->srcpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_mngdec_src_pad_template), "src"); + gst_element_add_pad (GST_ELEMENT (mngdec), mngdec->srcpad); + + gst_pad_set_link_function (mngdec->sinkpad, gst_mngdec_sinklink); + + gst_pad_set_getcaps_function (mngdec->srcpad, gst_mngdec_src_getcaps); + + mngdec->mng = NULL; + mngdec->buffer_out = NULL; + + mngdec->color_type = -1; + mngdec->width = -1; + mngdec->height = -1; + mngdec->fps = -1; + + gst_element_set_loop_function (GST_ELEMENT (mngdec), gst_mngdec_loop); +} + +static GstCaps * +gst_mngdec_src_getcaps (GstPad * pad) +{ + GstMngDec *mngdec; + GstCaps *caps; + gint i; + GstPadTemplate *templ; + GstCaps *inter; + + mngdec = GST_MNGDEC (gst_pad_get_parent (pad)); + templ = gst_static_pad_template_get (&gst_mngdec_src_pad_template); + caps = gst_caps_copy (gst_pad_template_get_caps (templ)); + + if (mngdec->color_type != -1) { + GstCaps *to_inter = NULL; + + switch (mngdec->color_type) { + case MNG_COLORTYPE_RGB: + to_inter = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 24, NULL); + break; + case MNG_COLORTYPE_RGBA: + to_inter = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 32, NULL); + break; + case MNG_COLORTYPE_GRAY: + case MNG_COLORTYPE_INDEXED: + case MNG_COLORTYPE_GRAYA: + default: + GST_ELEMENT_ERROR (mngdec, STREAM, NOT_IMPLEMENTED, (NULL), + ("mngdec does not support grayscale or paletted data yet")); + break; + } + inter = gst_caps_intersect (caps, to_inter); + gst_caps_free (caps); + gst_caps_free (to_inter); + caps = inter; + } + + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *structure = gst_caps_get_structure (caps, i); + + if (mngdec->width != -1) { + gst_structure_set (structure, "width", G_TYPE_INT, mngdec->width, NULL); + } + + if (mngdec->height != -1) { + gst_structure_set (structure, "height", G_TYPE_INT, mngdec->height, NULL); + } + + if (mngdec->fps != -1) { + gst_structure_set (structure, + "framerate", G_TYPE_DOUBLE, mngdec->fps, NULL); + } + } + + return caps; +} + + +static void +gst_mngdec_loop (GstElement * element) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (element); + + if (mngdec->first) { + GST_DEBUG ("display"); + mng_readdisplay (mngdec->mng); + mngdec->first = FALSE; + } else { + GST_DEBUG ("resume"); + mng_display_resume (mngdec->mng); + } +} + +static void +gst_mngdec_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +gst_mngdec_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static mng_bool +mngdec_error (mng_handle mng, mng_int32 code, mng_int8 severity, + mng_chunkid chunktype, mng_uint32 chunkseq, + mng_int32 extra1, mng_int32 extra2, mng_pchar text) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + GST_ERROR_OBJECT (mngdec, "error in chunk %4.4s (%d): %s", + (gchar *) & chunktype, chunkseq, text); + + return FALSE; +} + +static mng_bool +mngdec_openstream (mng_handle mng) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + mngdec->bs = gst_bytestream_new (mngdec->sinkpad); + + return MNG_TRUE; +} + +static mng_bool +mngdec_closestream (mng_handle mng) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + gst_bytestream_destroy (mngdec->bs); + + return MNG_TRUE; +} + +static gboolean +mngdec_handle_sink_event (GstMngDec * mngdec) +{ + guint32 remaining; + GstEvent *event; + GstEventType type; + + gst_bytestream_get_status (mngdec->bs, &remaining, &event); + + type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; + GST_DEBUG ("mngdec: event %p %d", event, type); + + switch (type) { + case GST_EVENT_EOS: + gst_bytestream_flush (mngdec->bs, remaining); + gst_pad_event_default (mngdec->sinkpad, event); + return FALSE; + case GST_EVENT_FLUSH: + break; + case GST_EVENT_DISCONTINUOUS: + GST_DEBUG ("discontinuous event"); + break; + default: + g_warning ("unhandled event %d", type); + break; + } + + gst_event_unref (event); + return TRUE; +} + +static mng_bool +mngdec_readdata (mng_handle mng, mng_ptr buffer, + mng_uint32 size, mng_uint32 * bytesread) +{ + GstMngDec *mngdec; + guint8 *bytes; + guint32 read; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + GST_DEBUG ("read data %d", size); + + do { + read = gst_bytestream_peek_bytes (mngdec->bs, &bytes, size); + if (read != size) { + if (!mngdec_handle_sink_event (mngdec)) { + /* EOS */ + *bytesread = 0; + return MNG_FALSE; + } + } else { + break; + } + } while (TRUE); + + memcpy (buffer, bytes, size); + gst_bytestream_flush_fast (mngdec->bs, read); + *bytesread = size; + + return MNG_TRUE; +} + +static mng_uint32 +mngdec_gettickcount (mng_handle mng) +{ + GTimeVal time; + guint32 val; + + + g_get_current_time (&time); + + val = time.tv_sec * 1000 + time.tv_usec; + GST_DEBUG ("get tick count %d", val); + + return val; +} + +static mng_bool +mngdec_settimer (mng_handle mng, mng_uint32 msecs) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + //mymng->delay = msecs; + GST_DEBUG ("set timer %d", msecs); + + return MNG_TRUE; +} + +static mng_bool +mngdec_processheader (mng_handle mng, mng_uint32 width, mng_uint32 height) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + g_print ("process header %d %d\n", width, height); + GST_DEBUG ("process header %d %d", width, height); + + if (mngdec->width != width || mngdec->height != height) { + mngdec->width = width; + mngdec->stride = ((width + 3) & ~3) * 4; + mngdec->height = height; + + if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (mngdec->srcpad))) { + GST_ELEMENT_ERROR (mngdec, CORE, NEGOTIATION, (NULL), (NULL)); + return MNG_FALSE; + } + + mngdec->buffer_out = + gst_buffer_new_and_alloc (mngdec->height * mngdec->stride); + } + return MNG_TRUE; +} + +static mng_ptr +mngdec_getcanvasline (mng_handle mng, mng_uint32 line) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + GST_DEBUG ("get canvas line %d", line); + + return (mng_ptr) (GST_BUFFER_DATA (mngdec->buffer_out) + + (line * mngdec->stride)); +} + +static mng_bool +mngdec_refresh (mng_handle mng, mng_uint32 x, mng_uint32 y, + mng_uint32 w, mng_uint32 h) +{ + GstMngDec *mngdec; + + mngdec = GST_MNGDEC (mng_get_userdata (mng)); + + GST_DEBUG ("refresh %d %d %d %d", x, y, w, h); + if (h == mngdec->height) { + GstBuffer *out = gst_buffer_copy (mngdec->buffer_out); + + gst_pad_push (mngdec->srcpad, GST_DATA (out)); + } + + return MNG_TRUE; +} + +static GstElementStateReturn +gst_mngdec_change_state (GstElement * element) +{ + GstMngDec *mngdec = GST_MNGDEC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + /* init library, make sure to pass an alloc function that sets the + * memory to 0 */ + mngdec->mng = + mng_initialize (mngdec, (mng_memalloc) g_malloc0, + (mng_memfree) g_free, MNG_NULL); + if (mngdec->mng == MNG_NULL) { + return GST_STATE_FAILURE; + } + /* set the callbacks */ + mng_setcb_errorproc (mngdec->mng, mngdec_error); + mng_setcb_openstream (mngdec->mng, mngdec_openstream); + mng_setcb_closestream (mngdec->mng, mngdec_closestream); + mng_setcb_readdata (mngdec->mng, mngdec_readdata); + mng_setcb_gettickcount (mngdec->mng, mngdec_gettickcount); + mng_setcb_settimer (mngdec->mng, mngdec_settimer); + mng_setcb_processheader (mngdec->mng, mngdec_processheader); + mng_setcb_getcanvasline (mngdec->mng, mngdec_getcanvasline); + mng_setcb_refresh (mngdec->mng, mngdec_refresh); + mng_set_canvasstyle (mngdec->mng, MNG_CANVAS_RGBA8); + mng_set_doprogressive (mngdec->mng, MNG_FALSE); + break; + case GST_STATE_READY_TO_PAUSED: + mngdec->first = TRUE; + mngdec->fps = 10.0; + break; + case GST_STATE_PAUSED_TO_PLAYING: + break; + case GST_STATE_PLAYING_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_READY: + break; + case GST_STATE_READY_TO_NULL: + mng_cleanup (&mngdec->mng); + 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/libmng/gstmngdec.h b/ext/libmng/gstmngdec.h new file mode 100644 index 0000000000..ab953f9c59 --- /dev/null +++ b/ext/libmng/gstmngdec.h @@ -0,0 +1,75 @@ +/* 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_MNGDEC_H__ +#define __GST_MNGDEC_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_MNGDEC (gst_mngdec_get_type()) +#define GST_MNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MNGDEC,GstMngDec)) +#define GST_MNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MNGDEC,GstMngDec)) +#define GST_IS_MNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MNGDEC)) +#define GST_IS_MNGDEC_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MNGDEC)) + +typedef struct _GstMngDec GstMngDec; +typedef struct _GstMngDecClass GstMngDecClass; + +struct _GstMngDec +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + GstBuffer *buffer_out; + GstByteStream *bs; + + mng_handle mng; + gboolean first; + + gint width; + gint stride; + gint height; + gint bpp; + gint color_type; + gdouble fps; +}; + +struct _GstMngDecClass +{ + GstElementClass parent_class; +}; + +GType gst_mngdec_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_MNGDEC_H__ */ diff --git a/ext/libmng/gstmngenc.c b/ext/libmng/gstmngenc.c new file mode 100644 index 0000000000..53ad34a652 --- /dev/null +++ b/ext/libmng/gstmngenc.c @@ -0,0 +1,249 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * Filter: + * Copyright (C) 2000 Donald A. Graft + * + * 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_H +#include "config.h" +#endif +#include +#include +#include "gstmngenc.h" +#include + +#define MAX_HEIGHT 4096 + + +GstElementDetails gst_mngenc_details = { + "MNG encoder", + "Codec/Encoder/Image", + "Encode a video frame to an .mng video", + "Wim Taymans ", +}; + + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +#define DEFAULT_SNAPSHOT TRUE + +enum +{ + ARG_0, + ARG_SNAPSHOT, + ARG_NEWMEDIA +}; + +static void gst_mngenc_base_init (gpointer g_class); +static void gst_mngenc_class_init (GstMngEncClass * klass); +static void gst_mngenc_init (GstMngEnc * mngenc); +static void gst_mngenc_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_mngenc_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +static void gst_mngenc_chain (GstPad * pad, GstData * _data); + +GstPadTemplate *mngenc_src_template, *mngenc_sink_template; + +static GstElementClass *parent_class = NULL; + + +GType +gst_mngenc_get_type (void) +{ + static GType mngenc_type = 0; + + if (!mngenc_type) { + static const GTypeInfo mngenc_info = { + sizeof (GstMngEncClass), + gst_mngenc_base_init, + NULL, + (GClassInitFunc) gst_mngenc_class_init, + NULL, + NULL, + sizeof (GstMngEnc), + 0, + (GInstanceInitFunc) gst_mngenc_init, + }; + + mngenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstMngEnc", + &mngenc_info, 0); + } + return mngenc_type; +} + +static GstCaps * +mng_caps_factory (void) +{ + return gst_caps_new_simple ("video/x-mng", + "width", GST_TYPE_INT_RANGE, 16, 4096, + "height", GST_TYPE_INT_RANGE, 16, 4096, + "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL); +} + + +static GstCaps * +raw_caps_factory (void) +{ + return gst_caps_from_string (GST_VIDEO_CAPS_RGB); +} + +static void +gst_mngenc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstCaps *raw_caps, *mng_caps; + + raw_caps = raw_caps_factory (); + mng_caps = mng_caps_factory (); + + mngenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, raw_caps); + + mngenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, mng_caps); + + gst_element_class_add_pad_template (element_class, mngenc_sink_template); + gst_element_class_add_pad_template (element_class, mngenc_src_template); + gst_element_class_set_details (element_class, &gst_mngenc_details); +} + +static void +gst_mngenc_class_init (GstMngEncClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (gobject_class, ARG_SNAPSHOT, + g_param_spec_boolean ("snapshot", "Snapshot", + "Send EOS after encoding a frame, useful for snapshots", + DEFAULT_SNAPSHOT, (GParamFlags) G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_NEWMEDIA, + g_param_spec_boolean ("newmedia", "newmedia", + "Send new media discontinuity after encoding each frame", + FALSE, (GParamFlags) G_PARAM_READWRITE)); + + gstelement_class->get_property = gst_mngenc_get_property; + gstelement_class->set_property = gst_mngenc_set_property; +} + + +static GstPadLinkReturn +gst_mngenc_sinklink (GstPad * pad, const GstCaps * caps) +{ + GstMngEnc *mngenc; + gdouble fps; + GstStructure *structure; + + mngenc = GST_MNGENC (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + gst_structure_get_int (structure, "width", &mngenc->width); + gst_structure_get_int (structure, "height", &mngenc->height); + gst_structure_get_double (structure, "framerate", &fps); + gst_structure_get_int (structure, "bpp", &mngenc->bpp); + + caps = gst_caps_new_simple ("video/x-mng", + "framerate", G_TYPE_DOUBLE, fps, + "width", G_TYPE_INT, mngenc->width, + "height", G_TYPE_INT, mngenc->height, NULL); + + return gst_pad_try_set_caps (mngenc->srcpad, caps); +} + +static void +gst_mngenc_init (GstMngEnc * mngenc) +{ + mngenc->sinkpad = gst_pad_new_from_template (mngenc_sink_template, "sink"); + gst_element_add_pad (GST_ELEMENT (mngenc), mngenc->sinkpad); + + mngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (mngenc), mngenc->srcpad); + + gst_pad_set_chain_function (mngenc->sinkpad, gst_mngenc_chain); + gst_pad_set_link_function (mngenc->sinkpad, gst_mngenc_sinklink); + + mngenc->snapshot = DEFAULT_SNAPSHOT; + mngenc->newmedia = FALSE; +} + +static void +gst_mngenc_chain (GstPad * pad, GstData * _data) +{ + GstBuffer *buf = GST_BUFFER (_data); + GstMngEnc *mngenc; + + mngenc = GST_MNGENC (gst_pad_get_parent (pad)); + + /* FIXME, do something here */ + + gst_buffer_unref (buf); +} + + +static void +gst_mngenc_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstMngEnc *mngenc; + + mngenc = GST_MNGENC (object); + + switch (prop_id) { + case ARG_SNAPSHOT: + g_value_set_boolean (value, mngenc->snapshot); + break; + case ARG_NEWMEDIA: + g_value_set_boolean (value, mngenc->newmedia); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +gst_mngenc_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstMngEnc *mngenc; + + mngenc = GST_MNGENC (object); + + switch (prop_id) { + case ARG_SNAPSHOT: + mngenc->snapshot = g_value_get_boolean (value); + break; + case ARG_NEWMEDIA: + mngenc->newmedia = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/ext/libmng/gstmngenc.h b/ext/libmng/gstmngenc.h new file mode 100644 index 0000000000..98545f68c7 --- /dev/null +++ b/ext/libmng/gstmngenc.h @@ -0,0 +1,73 @@ +/* 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_MNGENC_H__ +#define __GST_MNGENC_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_MNGENC (gst_mngenc_get_type()) +#define GST_MNGENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MNGENC,GstMngEnc)) +#define GST_MNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MNGENC,GstMngEnc)) +#define GST_IS_MNGENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MNGENC)) +#define GST_IS_MNGENC_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MNGENC)) + +typedef struct _GstMngEnc GstMngEnc; +typedef struct _GstMngEncClass GstMngEncClass; + +extern GstPadTemplate *mngenc_src_template, *mngenc_sink_template; + +struct _GstMngEnc +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + GstBuffer *buffer_out; + + mng_handle mng; + + gint width; + gint height; + gint bpp; + + gboolean snapshot; + gboolean newmedia; +}; + +struct _GstMngEncClass +{ + GstElementClass parent_class; +}; + +GType gst_mngenc_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_MNGENC_H__ */