diff options
Diffstat (limited to 'ext/mimic')
-rw-r--r-- | ext/mimic/.git-darcs-dir | 0 | ||||
-rw-r--r-- | ext/mimic/Makefile.am | 9 | ||||
-rw-r--r-- | ext/mimic/gstmimdec.c | 346 | ||||
-rw-r--r-- | ext/mimic/gstmimdec.h | 69 | ||||
-rw-r--r-- | ext/mimic/gstmimenc.c | 416 | ||||
-rw-r--r-- | ext/mimic/gstmimenc.h | 69 | ||||
-rw-r--r-- | ext/mimic/gstmimic.c | 53 |
7 files changed, 962 insertions, 0 deletions
diff --git a/ext/mimic/.git-darcs-dir b/ext/mimic/.git-darcs-dir new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/ext/mimic/.git-darcs-dir diff --git a/ext/mimic/Makefile.am b/ext/mimic/Makefile.am new file mode 100644 index 00000000..2bbd5f10 --- /dev/null +++ b/ext/mimic/Makefile.am @@ -0,0 +1,9 @@ +plugin_LTLIBRARIES = libgstmimic.la + +libgstmimic_la_SOURCES = gstmimic.c gstmimdec.c gstmimenc.c + +libgstmimic_la_CFLAGS = $(GST_CFLAGS) $(MIMIC_CFLAGS) $(GST_BASE_CFLAGS) +libgstmimic_la_LIBADD = $(GST_LIBS) $(MIMIC_LIBS) +libgstmimic_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GST_BASE_LIBS) + +noinst_HEADERS = gstmimdec.h gstmimenc.h diff --git a/ext/mimic/gstmimdec.c b/ext/mimic/gstmimdec.c new file mode 100644 index 00000000..abdd5e12 --- /dev/null +++ b/ext/mimic/gstmimdec.c @@ -0,0 +1,346 @@ +/* + * GStreamer + * Copyright (c) 2005 INdT. + * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br> + * @author Rob Taylor <robtaylor@fastmail.fm> + * @author Philippe Khalaf <burger@speedy.org> + * + * 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_H +#include "config.h" +#endif + +#include <gst/gst.h> + +#include "gstmimdec.h" + +GST_DEBUG_CATEGORY (mimdec_debug); +#define GST_CAT_DEFAULT (mimdec_debug) + +static GstStaticPadTemplate sink_factory = +GST_STATIC_PAD_TEMPLATE ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-msnwebcam") +); + +static GstStaticPadTemplate src_factory = +GST_STATIC_PAD_TEMPLATE ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-rgb, " + "bpp = (int) 24, " + "depth = (int) 24, " + "endianness = (int) 4321, " + "framerate = (double) [1.0, 30.0], " + "red_mask = (int) 16711680, " + "green_mask = (int) 65280, " + "blue_mask = (int) 255, " + "height = (int) [16, 4096], " + "width = (int) [16, 4096]" + ) +); + +static void gst_mimdec_class_init (GstMimDecClass *klass); +static void gst_mimdec_base_init (GstMimDecClass *klass); +static void gst_mimdec_init (GstMimDec *mimdec); +static void gst_mimdec_dispose (GObject *object); + +static GstFlowReturn gst_mimdec_chain (GstPad *pad, + GstBuffer *in); +static GstCaps *gst_mimdec_src_getcaps (GstPad *pad); +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) +static GstElementStateReturn + gst_mimdec_change_state (GstElement *element); +#else +static GstStateChangeReturn + gst_mimdec_change_state (GstElement *element, + GstStateChange transition); +#endif + +static GstElementClass *parent_class = NULL; + +GType +gst_gst_mimdec_get_type (void) +{ + static GType plugin_type = 0; + + if (!plugin_type) + { + static const GTypeInfo plugin_info = + { + sizeof (GstMimDecClass), + (GBaseInitFunc) gst_mimdec_base_init, + NULL, + (GClassInitFunc) gst_mimdec_class_init, + NULL, + NULL, + sizeof (GstMimDec), + 0, + (GInstanceInitFunc) gst_mimdec_init, + }; + plugin_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstMimDec", + &plugin_info, 0); + } + return plugin_type; +} + +static void +gst_mimdec_base_init (GstMimDecClass *klass) +{ + static GstElementDetails plugin_details = { + "MimDec", + "Codec/Decoder/Video", + "Mimic decoder", + "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>" + }; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_details (element_class, &plugin_details); +} + +static void +gst_mimdec_class_init (GstMimDecClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*) klass; + gstelement_class = (GstElementClass*) klass; + gstelement_class->change_state = gst_mimdec_change_state; + + gobject_class->dispose = gst_mimdec_dispose; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + GST_DEBUG_CATEGORY_INIT (mimdec_debug, "mimdec", 0, "Mimic decoder plugin"); +} + +static void +gst_mimdec_init (GstMimDec *mimdec) +{ + mimdec->sinkpad = gst_pad_new_from_template ( + gst_static_pad_template_get (&sink_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (mimdec), mimdec->sinkpad); + gst_pad_set_chain_function (mimdec->sinkpad, gst_mimdec_chain); + + mimdec->srcpad = gst_pad_new_from_template ( + gst_static_pad_template_get (&src_factory), "src"); + gst_pad_set_getcaps_function (mimdec->srcpad, gst_mimdec_src_getcaps); + gst_element_add_pad (GST_ELEMENT (mimdec), mimdec->srcpad); + + mimdec->adapter = gst_adapter_new (); + + mimdec->dec = NULL; + mimdec->buffer_size = -1; + mimdec->have_header = FALSE; + mimdec->payload_size = -1; +} + +static void +gst_mimdec_dispose (GObject *object) +{ + GstMimDec *mimdec = GST_MIMDEC (object); + + gst_adapter_clear (mimdec->adapter); + g_object_unref (mimdec->adapter); +} + +static GstFlowReturn +gst_mimdec_chain (GstPad *pad, GstBuffer *in) +{ + GstMimDec *mimdec; + GstBuffer *out_buf, *buf; + guchar *header, *frame_body; + guint32 fourcc; + guint16 header_size; + gint width, height; + GstCaps *caps; + + g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); + + mimdec = GST_MIMDEC (GST_OBJECT_PARENT (pad)); + g_return_val_if_fail (GST_IS_MIMDEC (mimdec), GST_FLOW_ERROR); + + g_return_val_if_fail(GST_PAD_IS_LINKED(mimdec->srcpad), GST_FLOW_ERROR); + + buf = GST_BUFFER (in); + gst_adapter_push (mimdec->adapter, buf); + + // do we have enough bytes to read a header + while (gst_adapter_available (mimdec->adapter) >= (mimdec->have_header ? mimdec->payload_size : 24)) { + if (!mimdec->have_header) { + header = (guchar *) gst_adapter_peek (mimdec->adapter, 24); + header_size = GUINT16_FROM_LE (*(guint16 *) (header + 0)); + if (header_size != 24) { + GST_WARNING ("invalid frame: header size %d incorrect", header_size); + gst_adapter_flush (mimdec->adapter, 24); + return GST_FLOW_ERROR; + } + + fourcc = GST_MAKE_FOURCC ('M', 'L', '2', '0'); + if (GUINT32_FROM_LE (*((guint32 *) (header + 12))) != fourcc) { + GST_WARNING ("invalid frame: unknown FOURCC code %d", fourcc); + gst_adapter_flush (mimdec->adapter, 24); + return GST_FLOW_ERROR; + } + + mimdec->payload_size = GUINT32_FROM_LE (*((guint32 *) (header + 8))); + GST_DEBUG ("Got packet, payload size %d", mimdec->payload_size); + + gst_adapter_flush (mimdec->adapter, 24); + + mimdec->have_header = TRUE; + } + + if (gst_adapter_available (mimdec->adapter) < mimdec->payload_size) + { + return GST_FLOW_OK; + } + + frame_body = (guchar *) gst_adapter_peek (mimdec->adapter, mimdec->payload_size); + + if (mimdec->dec == NULL) { + mimdec->dec = mimic_open (); + if (mimdec->dec == NULL) { + GST_WARNING ("mimic_open error\n"); + + gst_adapter_flush (mimdec->adapter, mimdec->payload_size); + mimdec->have_header = FALSE; + return GST_FLOW_ERROR; + } + + if (!mimic_decoder_init (mimdec->dec, frame_body)) { + GST_WARNING ("mimic_decoder_init error\n"); + mimic_close (mimdec->dec); + mimdec->dec = NULL; + + gst_adapter_flush (mimdec->adapter, mimdec->payload_size); + mimdec->have_header = FALSE; + return GST_FLOW_ERROR; + } + + if (!mimic_get_property (mimdec->dec, "buffer_size", &mimdec->buffer_size)) { + GST_WARNING ("mimic_get_property('buffer_size') error\n"); + mimic_close (mimdec->dec); + mimdec->dec = NULL; + + gst_adapter_flush (mimdec->adapter, mimdec->payload_size); + mimdec->have_header = FALSE; + return GST_FLOW_ERROR; + } + } + + out_buf = gst_buffer_new_and_alloc (mimdec->buffer_size); + GST_BUFFER_TIMESTAMP(out_buf) = GST_BUFFER_TIMESTAMP(buf); + if (!mimic_decode_frame (mimdec->dec, frame_body, GST_BUFFER_DATA (out_buf))) { + GST_WARNING ("mimic_decode_frame error\n"); + + gst_adapter_flush (mimdec->adapter, mimdec->payload_size); + mimdec->have_header = FALSE; + + gst_buffer_unref (out_buf); + return GST_FLOW_ERROR; + } + + mimic_get_property(mimdec->dec, "width", &width); + mimic_get_property(mimdec->dec, "height", &height); + GST_DEBUG ("got WxH %d x %d payload size %d buffer_size %d", width, height, mimdec->payload_size, mimdec->buffer_size); + caps = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 24, + "depth", G_TYPE_INT, 24, + "endianness", G_TYPE_INT, 4321, + "framerate", G_TYPE_DOUBLE, 30.0, + "red_mask", G_TYPE_INT, 16711680, + "green_mask", G_TYPE_INT, 65280, + "blue_mask", G_TYPE_INT, 255, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); + // gst_pad_set_caps (mimdec->srcpad, caps); + gst_buffer_set_caps (out_buf, caps); + gst_caps_unref (caps); + gst_pad_push (mimdec->srcpad, out_buf); + + gst_adapter_flush (mimdec->adapter, mimdec->payload_size); + mimdec->have_header = FALSE; + + return GST_FLOW_OK; + } + + return GST_FLOW_OK; +} + +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) +static GstElementStateReturn +gst_mimdec_change_state (GstElement *element) +{ + GstMimDec *mimdec; + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_READY_TO_NULL: +#else +static GstStateChangeReturn +gst_mimdec_change_state (GstElement *element, GstStateChange transition) +{ + GstMimDec *mimdec; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: +#endif + mimdec = GST_MIMDEC (element); + if (mimdec->dec != NULL) { + mimic_close (mimdec->dec); + mimdec->dec = NULL; + mimdec->buffer_size = -1; + mimdec->have_header = FALSE; + mimdec->payload_size = -1; + } + break; + + default: + break; + } + +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); +#else + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); +#endif +} + +static GstCaps * +gst_mimdec_src_getcaps (GstPad *pad) +{ + GstCaps *caps; + + GST_LOCK (pad); + if (!(caps = GST_PAD_CAPS (pad))) + caps = (GstCaps *) gst_pad_get_pad_template_caps (pad); + caps = gst_caps_ref (caps); + GST_UNLOCK (pad); + + return caps; +} diff --git a/ext/mimic/gstmimdec.h b/ext/mimic/gstmimdec.h new file mode 100644 index 00000000..7f930529 --- /dev/null +++ b/ext/mimic/gstmimdec.h @@ -0,0 +1,69 @@ +/* + * GStreamer + * Copyright (c) 2005 INdT. + * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br> + * @author Philippe Khalaf <burger@speedy.org> + * + * 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_MIMDEC_H__ +#define __GST_MIMDEC_H__ + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> +#include <mimic.h> + +G_BEGIN_DECLS + +#define GST_TYPE_MIMDEC \ + (gst_gst_mimdec_get_type()) +#define GST_MIMDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MIMDEC,GstMimDec)) +#define GST_MIMDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MIMDEC,GstMimDec)) +#define GST_IS_MIMDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MIMDEC)) +#define GST_IS_MIMDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MIMDEC)) + +typedef struct _GstMimDec GstMimDec; +typedef struct _GstMimDecClass GstMimDecClass; + +struct _GstMimDec +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + GstAdapter *adapter; + + MimCtx *dec; + + gint buffer_size; + gboolean have_header; + guint32 payload_size; +}; + +struct _GstMimDecClass +{ + GstElementClass parent_class; +}; + +GType gst_gst_mimdec_get_type (void); + +G_END_DECLS + +#endif /* __GST_MIMDEC_H__ */ diff --git a/ext/mimic/gstmimenc.c b/ext/mimic/gstmimenc.c new file mode 100644 index 00000000..34e5da97 --- /dev/null +++ b/ext/mimic/gstmimenc.c @@ -0,0 +1,416 @@ + /* + * GStreamer + * Copyright (c) 2005 INdT. + * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br> + * @author Philippe Khalaf <burger@speedy.org> + * + * 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_H +#include "config.h" +#endif + +#include <gst/gst.h> + +#include "gstmimenc.h" + +GST_DEBUG_CATEGORY (mimenc_debug); +#define GST_CAT_DEFAULT (mimenc_debug) + +#define MAX_INTERFRAMES 15 + +static GstStaticPadTemplate sink_factory = +GST_STATIC_PAD_TEMPLATE ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ( + "video/x-raw-rgb, " + "bpp = (int) 24, " + "depth = (int) 24, " + "endianness = (int) 4321, " + "framerate = (double) [1.0, 30.0], " + "red_mask = (int) 16711680, " + "green_mask = (int) 65280, " + "blue_mask = (int) 255, " + "width = (int) 320, " + "height = (int) 240" + ";video/x-raw-rgb, " + "bpp = (int) 24, " + "depth = (int) 24, " + "endianness = (int) 4321, " + "framerate = (double) [1.0, 30.0], " + "red_mask = (int) 16711680, " + "green_mask = (int) 65280, " + "blue_mask = (int) 255, " + "width = (int) 160, " + "height = (int) 120" + ) +); + +static GstStaticPadTemplate src_factory = +GST_STATIC_PAD_TEMPLATE ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-msnwebcam") +); + +/* props */ +// FIXME remove or fix +/* +enum +{ + ARG_0, + ARG_RESOLUTION +}; +*/ + +static void gst_mimenc_class_init (GstMimEncClass *klass); +static void gst_mimenc_base_init (GstMimEncClass *klass); +static void gst_mimenc_init (GstMimEnc *mimenc); + +// FIXME remove or fix +/* +static void gst_mimenc_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *spec); +static void gst_mimenc_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *spec); +*/ + +static gboolean gst_mimenc_setcaps (GstPad *pad, + GstCaps *caps); +static GstFlowReturn gst_mimenc_chain (GstPad *pad, + GstBuffer *in); +static GstBuffer* gst_mimenc_create_tcp_header (GstMimEnc *mimenc, + gint payload_size); + +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) +static GstElementStateReturn + gst_mimenc_change_state (GstElement *element); +#else +static GstStateChangeReturn + gst_mimenc_change_state (GstElement *element, + GstStateChange transition); +#endif + +static GstElementClass *parent_class = NULL; + +GType +gst_gst_mimenc_get_type (void) +{ + static GType plugin_type = 0; + + if (!plugin_type) + { + static const GTypeInfo plugin_info = + { + sizeof (GstMimEncClass), + (GBaseInitFunc) gst_mimenc_base_init, + NULL, + (GClassInitFunc) gst_mimenc_class_init, + NULL, + NULL, + sizeof (GstMimEnc), + 0, + (GInstanceInitFunc) gst_mimenc_init, + }; + plugin_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstMimEnc", + &plugin_info, 0); + } + return plugin_type; +} + +static void +gst_mimenc_base_init (GstMimEncClass *klass) +{ + static GstElementDetails plugin_details = { + "MimEnc", + "Codec/Encoder/Video", + "Mimic encoder", + "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>" + }; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + gst_element_class_set_details (element_class, &plugin_details); +} + +static void +gst_mimenc_class_init (GstMimEncClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*) klass; + gstelement_class = (GstElementClass*) klass; + gstelement_class->change_state = gst_mimenc_change_state; + +/* + gobject_class->set_property = gst_mimenc_set_property; + gobject_class->get_property = gst_mimenc_get_property; + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RESOLUTION, + g_param_spec_uint ("resolution", "Input resolution", + "The input resolution (1 = 320x240 default) (2 = 160x120)", + 0, G_MAXUINT16, 0, G_PARAM_READWRITE)); +*/ + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + GST_DEBUG_CATEGORY_INIT (mimenc_debug, "mimenc", 0, "Mimic encoder plugin"); +} + +static void +gst_mimenc_init (GstMimEnc *mimenc) +{ + mimenc->sinkpad = gst_pad_new_from_template ( + gst_static_pad_template_get (&sink_factory), "sink"); + gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->sinkpad); + gst_pad_set_setcaps_function (mimenc->sinkpad, gst_mimenc_setcaps); + gst_pad_set_chain_function (mimenc->sinkpad, gst_mimenc_chain); + + mimenc->srcpad = gst_pad_new_from_template ( + gst_static_pad_template_get (&src_factory), "src"); + gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->srcpad); + + mimenc->enc = NULL; + + // TODO property to set resolution + mimenc->res = MIMIC_RES_HIGH; + mimenc->buffer_size = -1; + mimenc->width = 0; + mimenc->height = 0; + mimenc->frames = 0; +} + +static gboolean +gst_mimenc_setcaps (GstPad *pad, GstCaps *caps) +{ + GstMimEnc *filter; + GstStructure *structure; + int ret, height, width; + + filter = GST_MIMENC (gst_pad_get_parent (pad)); + g_return_val_if_fail (filter != NULL, FALSE); + g_return_val_if_fail (GST_IS_MIMENC (filter), FALSE); + + structure = gst_caps_get_structure( caps, 0 ); + ret = gst_structure_get_int( structure, "width", &width ); + ret = gst_structure_get_int( structure, "height", &height ); + filter->width = (guint16)width; + filter->height = (guint16)height; + filter->res = (width == 320) ? MIMIC_RES_HIGH : MIMIC_RES_LOW; + GST_DEBUG ("Got info from caps w : %d, h : %d", filter->width, filter->height); + if (!ret) { + return FALSE; + } + + return TRUE; +} + +static GstFlowReturn +gst_mimenc_chain (GstPad *pad, GstBuffer *in) +{ + GstMimEnc *mimenc; + GstBuffer *out_buf, *buf; + guchar *data; + gint buffer_size; + GstBuffer * header = NULL; + + g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); + mimenc = GST_MIMENC (GST_OBJECT_PARENT (pad)); + + g_return_val_if_fail (GST_IS_MIMENC (mimenc), GST_FLOW_ERROR); + g_return_val_if_fail (GST_PAD_IS_LINKED (mimenc->srcpad), GST_FLOW_ERROR); + + if (mimenc->enc == NULL) { + mimenc->enc = mimic_open (); + if (mimenc->enc == NULL) { + GST_WARNING ("mimic_open error\n"); + return GST_FLOW_ERROR; + } + + if (!mimic_encoder_init (mimenc->enc, mimenc->res)) { + GST_WARNING ("mimic_encoder_init error\n"); + mimic_close (mimenc->enc); + mimenc->enc = NULL; + return GST_FLOW_ERROR; + } + + if (!mimic_get_property (mimenc->enc, "buffer_size", &mimenc->buffer_size)) { + GST_WARNING ("mimic_get_property('buffer_size') error\n"); + mimic_close (mimenc->enc); + mimenc->enc = NULL; + return GST_FLOW_ERROR; + } + } + + buf = in; + data = GST_BUFFER_DATA (buf); + + out_buf = gst_buffer_new_and_alloc (mimenc->buffer_size); + GST_BUFFER_TIMESTAMP(out_buf) = GST_BUFFER_TIMESTAMP(buf); + buffer_size = mimenc->buffer_size; + if (!mimic_encode_frame (mimenc->enc, data, GST_BUFFER_DATA (out_buf), + &buffer_size, ((mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE))) { + GST_WARNING ("mimic_encode_frame error\n"); + gst_buffer_unref (out_buf); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } + GST_BUFFER_SIZE (out_buf) = buffer_size; + + GST_DEBUG ("incoming buf size %d, encoded size %d", GST_BUFFER_SIZE(buf), GST_BUFFER_SIZE(out_buf)); + ++mimenc->frames; + + // now let's create that tcp header + header = gst_mimenc_create_tcp_header (mimenc, buffer_size); + + if (header) + { + gst_pad_push (mimenc->srcpad, header); + gst_pad_push (mimenc->srcpad, out_buf); + } + else + { + GST_DEBUG("header not created succesfully"); + return GST_FLOW_ERROR; + } + + gst_buffer_unref (buf); + + return GST_FLOW_OK; +} + +static GstBuffer* +gst_mimenc_create_tcp_header (GstMimEnc *mimenc, gint payload_size) +{ + // 24 bytes + GstBuffer *buf_header = gst_buffer_new_and_alloc (24); + guchar *p = (guchar *) GST_BUFFER_DATA(buf_header); + + p[0] = 24; + *((guchar *) (p + 1)) = 0; + *((guint16 *) (p + 2)) = GUINT16_TO_LE(mimenc->width); + *((guint16 *) (p + 4)) = GUINT16_TO_LE(mimenc->height); + *((guint16 *) (p + 6)) = 0; + *((guint32 *) (p + 8)) = GUINT32_TO_LE(payload_size); + *((guint32 *) (p + 12)) = GUINT32_TO_LE(GST_MAKE_FOURCC ('M', 'L', '2', '0')); + *((guint32 *) (p + 16)) = 0; + *((guint32 *) (p + 20)) = 0; + + return buf_header; +} + +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) +static GstElementStateReturn +gst_mimenc_change_state (GstElement * element) +{ + GstMimEnc *mimenc; + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_READY_TO_NULL: +#else +static GstStateChangeReturn +gst_mimenc_change_state (GstElement * element, GstStateChange transition) +{ + GstMimEnc *mimenc; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: +#endif + mimenc = GST_MIMENC (element); + if (mimenc->enc != NULL) { + mimic_close (mimenc->enc); + mimenc->enc = NULL; + mimenc->buffer_size = -1; + mimenc->frames = 0; + } + break; + + default: + break; + } + +#if (GST_VERSION_MAJOR == 0) && (GST_VERSION_MINOR == 9) && (GST_VERSION_MICRO <= 1) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); +#else + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); +#endif +} + +// FIXME remove or fix +/* +static void +gst_mimenc_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GstMimEnc *mimenc; + guint res; + + g_return_if_fail (GST_IS_MIMENC (object)); + + mimenc = GST_MIMENC (object); + + switch (prop_id) { + case ARG_RESOLUTION: + res = g_value_get_uint(value); + if (res == 1) + mimenc->res = MIMIC_RES_HIGH; + else + mimenc->res = MIMIC_RES_LOW; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_mimenc_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GstMimEnc *mimenc; + + g_return_if_fail (GST_IS_MIMENC (object)); + + mimenc = GST_MIMENC (object); + + switch (prop_id) { + case ARG_RESOLUTION: + if (mimenc->res == MIMIC_RES_HIGH) + g_value_set_uint (value, 1); + else + g_value_set_uint (value, 2); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +*/ diff --git a/ext/mimic/gstmimenc.h b/ext/mimic/gstmimenc.h new file mode 100644 index 00000000..150e9c83 --- /dev/null +++ b/ext/mimic/gstmimenc.h @@ -0,0 +1,69 @@ +/* + * GStreamer + * Copyright (c) 2005 INdT. + * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br> + * @author Philippe Khalaf <burger@speedy.org> + * + * 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_MIMENC_H__ +#define __GST_MIMENC_H__ + +#include <glib.h> +#include <gst/gst.h> +#include <mimic.h> + +G_BEGIN_DECLS + +#define GST_TYPE_MIMENC \ + (gst_gst_mimenc_get_type()) +#define GST_MIMENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MIMENC,GstMimEnc)) +#define GST_MIMENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MIMENC,GstMimEnc)) +#define GST_IS_MIMENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MIMENC)) +#define GST_IS_MIMENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MIMENC)) + +typedef struct _GstMimEnc GstMimEnc; +typedef struct _GstMimEncClass GstMimEncClass; + +struct _GstMimEnc +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + MimCtx *enc; + + MimicResEnum res; + gint buffer_size; + guint32 frames; + guint16 height, width; +}; + +struct _GstMimEncClass +{ + GstElementClass parent_class; +}; + +GType gst_gst_mimenc_get_type (void); + +G_END_DECLS + +#endif /* __GST_MIMENC_H__ */ diff --git a/ext/mimic/gstmimic.c b/ext/mimic/gstmimic.c new file mode 100644 index 00000000..6931ebdb --- /dev/null +++ b/ext/mimic/gstmimic.c @@ -0,0 +1,53 @@ +/* + * GStreamer + * Copyright (c) 2005 INdT. + * @author Andre Moreira Magalhaes <andre.magalhaes@indt.org.br> + * @author Philippe Khalaf <burger@speedy.org> + * + * 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_H +#include "config.h" +#endif + +#include "gstmimenc.h" +#include "gstmimdec.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if ( + !gst_element_register (plugin, "mimenc", + GST_RANK_NONE, GST_TYPE_MIMENC) || + !gst_element_register (plugin, "mimdec", + GST_RANK_NONE, GST_TYPE_MIMDEC) + ) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mimic", + "Mimic codec", + plugin_init, + VERSION, + "GPL", + "Farsight", + "http://farsight.sf.net/") |