From bc6b5136209b09519deea1a91e5228a12e60f23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20Cr=C3=AAte?= Date: Fri, 3 Aug 2012 16:21:09 +0100 Subject: [PATCH] mimic: Port to 0.11 --- configure.ac | 6 +- ext/mimic/gstmimdec.c | 249 +++++++++++++--------------------- ext/mimic/gstmimdec.h | 2 +- ext/mimic/gstmimenc.c | 308 ++++++++++++++++++------------------------ ext/mimic/gstmimenc.h | 1 - 5 files changed, 233 insertions(+), 333 deletions(-) diff --git a/configure.ac b/configure.ac index 91840a344c..e1692528f5 100644 --- a/configure.ac +++ b/configure.ac @@ -322,7 +322,7 @@ GST_PLUGINS_NONPORTED=" aiff \ videomeasure videosignal vmnc \ decklink fbdev linsys vcd \ apexsink cdaudio cog dc1394 dirac directfb resindvd \ - gsettings jasper ladspa mimic \ + gsettings jasper ladspa \ musepack musicbrainz nas neon ofa openal rsvg sdl sndfile spandsp spc timidity \ directsound directdraw direct3d9 acm wininet \ wildmidi xvid lv2 teletextdec dvb sndio" @@ -1138,8 +1138,8 @@ AG_GST_CHECK_FEATURE(MODPLUG, modplug, modplug, [ dnl *** mimic *** translit(dnm, m, l) AM_CONDITIONAL(USE_MIMIC, true) AG_GST_CHECK_FEATURE(MIMIC, [libmimic library], mimic, [ - MIMDEC_REQUIRED=1.0 - PKG_CHECK_MODULES(MIMIC, libmimic >= $MIMDEC_REQUIRED, + MIMIC_REQUIRED=1.0 + PKG_CHECK_MODULES(MIMIC, libmimic >= $MIMIC_REQUIRED, HAVE_MIMIC=yes, HAVE_MIMIC=no) AC_SUBST(MIMIC_CFLAGS) AC_SUBST(MIMIC_LIBS) diff --git a/ext/mimic/gstmimdec.c b/ext/mimic/gstmimdec.c index 623f7496ca..5029655b9d 100644 --- a/ext/mimic/gstmimdec.c +++ b/ext/mimic/gstmimdec.c @@ -51,57 +51,24 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", 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 = (fraction) 0/1, " - "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 = (fraction) 0/1, " - "red_mask = (int) 16711680, " - "green_mask = (int) 65280, " - "blue_mask = (int) 255, " "width = (int) 160, " "height = (int) 120") + GST_STATIC_CAPS ("video/x-raw, format= (string) \"RGB\", " + "framerate = (fraction) 0/1, width = (int) 320, height = (int) 240;" + "video/x-raw, format= (string) \"RGB\", " + "framerate = (fraction) 0/1, width = (int) 160, height = (int) 120") ); static void gst_mim_dec_finalize (GObject * object); -static GstFlowReturn gst_mim_dec_chain (GstPad * pad, GstBuffer * in); +static GstFlowReturn gst_mim_dec_chain (GstPad * pad, GstObject * parent, + GstBuffer * in); static GstStateChangeReturn gst_mim_dec_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_mim_dec_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_mim_dec_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); -GST_BOILERPLATE (GstMimDec, gst_mim_dec, GstElement, GST_TYPE_ELEMENT); - -static void -gst_mim_dec_base_init (gpointer klass) -{ - 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_simple (element_class, - "Mimic Decoder", - "Codec/Decoder/Video", - "MSN Messenger compatible Mimic video decoder element", - "Andre Moreira Magalhaes , " - "Rob Taylor , " - "Philippe Khalaf , " - "Ole André Vadla Ravnås ," - "Olivier Crête change_state = GST_DEBUG_FUNCPTR (gst_mim_dec_change_state); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_details_simple (gstelement_class, + "Mimic Decoder", + "Codec/Decoder/Video", + "MSN Messenger compatible Mimic video decoder element", + "Andre Moreira Magalhaes , " + "Rob Taylor , " + "Philippe Khalaf , " + "Ole André Vadla Ravnås ," + "Olivier Crête finalize = gst_mim_dec_finalize; GST_DEBUG_CATEGORY_INIT (mimdec_debug, "mimdec", 0, "Mimic decoder plugin"); } static void -gst_mim_dec_init (GstMimDec * mimdec, GstMimDecClass * klass) +gst_mim_dec_init (GstMimDec * mimdec) { mimdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_element_add_pad (GST_ELEMENT (mimdec), mimdec->sinkpad); + gst_pad_use_fixed_caps (mimdec->sinkpad); gst_pad_set_chain_function (mimdec->sinkpad, GST_DEBUG_FUNCPTR (gst_mim_dec_chain)); gst_pad_set_event_function (mimdec->sinkpad, GST_DEBUG_FUNCPTR (gst_mim_dec_sink_event)); + gst_element_add_pad (GST_ELEMENT (mimdec), mimdec->sinkpad); mimdec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_use_fixed_caps (mimdec->srcpad); gst_element_add_pad (GST_ELEMENT (mimdec), mimdec->srcpad); mimdec->adapter = gst_adapter_new (); @@ -144,16 +128,15 @@ gst_mim_dec_finalize (GObject * object) gst_adapter_clear (mimdec->adapter); g_object_unref (mimdec->adapter); - - GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); + G_OBJECT_CLASS (gst_mim_dec_parent_class)->finalize (object); } static GstFlowReturn -gst_mim_dec_chain (GstPad * pad, GstBuffer * buf) +gst_mim_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { - GstMimDec *mimdec; + GstMimDec *mimdec = GST_MIM_DEC (parent); GstBuffer *out_buf; - guchar *header, *frame_body; + const guchar *header, *frame_body; guint32 fourcc; guint16 header_size; gint width, height; @@ -164,93 +147,107 @@ gst_mim_dec_chain (GstPad * pad, GstBuffer * buf) gboolean result = TRUE; guint32 payload_size; guint32 current_ts; - - g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); - - mimdec = GST_MIM_DEC (gst_pad_get_parent (pad)); - g_return_val_if_fail (GST_IS_MIM_DEC (mimdec), GST_FLOW_ERROR); + GstMapInfo map; gst_adapter_push (mimdec->adapter, buf); /* do we have enough bytes to read a header */ while (gst_adapter_available (mimdec->adapter) >= 24) { - header = (guchar *) gst_adapter_peek (mimdec->adapter, 24); + header = gst_adapter_map (mimdec->adapter, 24); header_size = header[0]; if (header_size != 24) { + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); GST_ELEMENT_ERROR (mimdec, STREAM, DECODE, (NULL), ("invalid frame: header size %d incorrect", header_size)); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } if (header[1] == 1) { /* This is a a paused frame, skip it */ + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); continue; } fourcc = GUINT32_FROM_LE (*((guint32 *) (header + 12))); if (GST_MAKE_FOURCC ('M', 'L', '2', '0') != fourcc) { + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, 24); GST_ELEMENT_ERROR (mimdec, STREAM, WRONG_TYPE, (NULL), ("invalid frame: unknown FOURCC code %X (%" GST_FOURCC_FORMAT ")", fourcc, GST_FOURCC_ARGS (fourcc))); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } payload_size = GUINT32_FROM_LE (*((guint32 *) (header + 8))); current_ts = GUINT32_FROM_LE (*((guint32 *) (header + 20))); + gst_adapter_unmap (mimdec->adapter); + GST_LOG_OBJECT (mimdec, "Got packet, payload size %d", payload_size); if (gst_adapter_available (mimdec->adapter) < payload_size + 24) - goto out; + return GST_FLOW_OK; /* We have a whole packet and have read the header, lets flush it out */ gst_adapter_flush (mimdec->adapter, 24); - frame_body = (guchar *) gst_adapter_peek (mimdec->adapter, payload_size); + frame_body = gst_adapter_map (mimdec->adapter, payload_size); if (mimdec->buffer_size < 0) { /* Check if its a keyframe, otherwise skip it */ if (GUINT32_FROM_LE (*((guint32 *) (frame_body + 12))) != 0) { + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); - res = GST_FLOW_OK; - goto out; + return GST_FLOW_OK; } if (!mimic_decoder_init (mimdec->dec, frame_body)) { + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); GST_ELEMENT_ERROR (mimdec, LIBRARY, INIT, (NULL), ("mimic_decoder_init error")); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } if (!mimic_get_property (mimdec->dec, "buffer_size", &mimdec->buffer_size)) { + gst_adapter_unmap (mimdec->adapter); gst_adapter_flush (mimdec->adapter, payload_size); GST_ELEMENT_ERROR (mimdec, LIBRARY, INIT, (NULL), ("mimic_get_property('buffer_size') error")); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } + + mimic_get_property (mimdec->dec, "width", &width); + mimic_get_property (mimdec->dec, "height", &height); + GST_DEBUG_OBJECT (mimdec, + "Initialised decoder with %d x %d payload size %d buffer_size %d", + width, height, payload_size, mimdec->buffer_size); + caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, "RGB", + "framerate", GST_TYPE_FRACTION, 0, 1, + "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); + gst_pad_set_caps (mimdec->srcpad, caps); + gst_caps_unref (caps); } - if (mimdec->need_newsegment) { + if (mimdec->need_segment) { + GstSegment segment; + + gst_segment_init (&segment, GST_FORMAT_TIME); + if (GST_CLOCK_TIME_IS_VALID (in_time)) - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - in_time, -1, 0); + segment.start = in_time; else - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - current_ts * GST_MSECOND, -1, 0); + segment.start = current_ts * GST_MSECOND; + event = gst_event_new_segment (&segment); } - mimdec->need_newsegment = FALSE; + mimdec->need_segment = FALSE; if (event) result = gst_pad_push_event (mimdec->srcpad, event); @@ -258,25 +255,25 @@ gst_mim_dec_chain (GstPad * pad, GstBuffer * buf) if (!result) { GST_WARNING_OBJECT (mimdec, "gst_pad_push_event failed"); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } - out_buf = gst_buffer_new_and_alloc (mimdec->buffer_size); + out_buf = gst_buffer_new_allocate (NULL, mimdec->buffer_size, NULL); + gst_buffer_map (out_buf, &map, GST_MAP_READWRITE); - if (!mimic_decode_frame (mimdec->dec, frame_body, - GST_BUFFER_DATA (out_buf))) { + if (!mimic_decode_frame (mimdec->dec, frame_body, map.data)) { GST_WARNING_OBJECT (mimdec, "mimic_decode_frame error\n"); gst_adapter_flush (mimdec->adapter, payload_size); + gst_buffer_unmap (out_buf, &map); gst_buffer_unref (out_buf); GST_ELEMENT_ERROR (mimdec, STREAM, DECODE, (NULL), ("mimic_decode_frame error")); - res = GST_FLOW_ERROR; - goto out; + return GST_FLOW_ERROR; } + gst_buffer_unmap (out_buf, &map); gst_adapter_flush (mimdec->adapter, payload_size); if (GST_CLOCK_TIME_IS_VALID (in_time)) @@ -284,33 +281,13 @@ gst_mim_dec_chain (GstPad * pad, GstBuffer * buf) else GST_BUFFER_TIMESTAMP (out_buf) = current_ts * GST_MSECOND; - mimic_get_property (mimdec->dec, "width", &width); - mimic_get_property (mimdec->dec, "height", &height); - GST_DEBUG_OBJECT (mimdec, - "got WxH %d x %d payload size %d buffer_size %d", - width, height, 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, - "red_mask", G_TYPE_INT, 16711680, - "green_mask", G_TYPE_INT, 65280, - "blue_mask", G_TYPE_INT, 255, - "framerate", GST_TYPE_FRACTION, 0, 1, - "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); - gst_buffer_set_caps (out_buf, caps); - gst_caps_unref (caps); res = gst_pad_push (mimdec->srcpad, out_buf); if (res != GST_FLOW_OK) break; } -out: - gst_object_unref (mimdec); - return res; - } static GstStateChangeReturn @@ -322,34 +299,33 @@ gst_mim_dec_change_state (GstElement * element, GstStateChange transition) mimdec = GST_MIM_DEC (element); switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: + case GST_STATE_CHANGE_READY_TO_PAUSED: + mimdec->buffer_size = -1; mimdec->dec = mimic_open (); if (!mimdec) { GST_ERROR_OBJECT (mimdec, "mimic_open failed"); return GST_STATE_CHANGE_FAILURE; } - break; - - case GST_STATE_CHANGE_READY_TO_PAUSED: - mimdec->need_newsegment = TRUE; + mimdec->need_segment = TRUE; gst_adapter_clear (mimdec->adapter); + break; default: break; } - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + ret = GST_ELEMENT_CLASS (gst_mim_dec_parent_class)->change_state (element, + transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: + case GST_STATE_CHANGE_PAUSED_TO_READY: if (mimdec->dec != NULL) { mimic_close (mimdec->dec); mimdec->dec = NULL; - mimdec->buffer_size = -1; } break; default: @@ -360,65 +336,34 @@ gst_mim_dec_change_state (GstElement * element, GstStateChange transition) } static gboolean -gst_mim_dec_sink_event (GstPad * pad, GstEvent * event) +gst_mim_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = TRUE; - GstMimDec *mimdec = GST_MIM_DEC (gst_pad_get_parent (pad)); + gboolean forward = TRUE; + GstMimDec *mimdec = GST_MIM_DEC (parent); /* - * Ignore upstream newsegment event, its EVIL, we should implement + * Ignore upstream segment event, its EVIL, we should implement * proper seeking instead */ switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, - &format, &start, &stop, &time); - - /* we need TIME and a positive rate */ - if (format != GST_FORMAT_TIME) - goto newseg_wrong_format; - - if (rate <= 0.0) - goto newseg_wrong_rate; - - mimdec->need_newsegment = FALSE; - + case GST_EVENT_SEGMENT: + forward = FALSE; break; - } + case GST_EVENT_STREAM_START: case GST_EVENT_FLUSH_STOP: - mimdec->need_newsegment = TRUE; + case GST_EVENT_EOS: + mimdec->need_segment = FALSE; gst_adapter_clear (mimdec->adapter); break; default: break; } - res = gst_pad_push_event (mimdec->srcpad, event); - -done: - - gst_object_unref (mimdec); + if (forward) + res = gst_pad_event_default (pad, parent, event); + else + gst_event_unref (event); return res; - -newseg_wrong_format: - { - GST_DEBUG_OBJECT (mimdec, "received non TIME newsegment"); - gst_event_unref (event); - goto done; - } -newseg_wrong_rate: - { - GST_DEBUG_OBJECT (mimdec, "negative rates not supported yet"); - gst_event_unref (event); - goto done; - } - - } diff --git a/ext/mimic/gstmimdec.h b/ext/mimic/gstmimdec.h index ae5c46c084..521da03aa2 100644 --- a/ext/mimic/gstmimdec.h +++ b/ext/mimic/gstmimdec.h @@ -51,7 +51,7 @@ struct _GstMimDec GstAdapter *adapter; MimCtx *dec; gint buffer_size; - gboolean need_newsegment; + gboolean need_segment; }; struct _GstMimDecClass diff --git a/ext/mimic/gstmimenc.c b/ext/mimic/gstmimenc.c index 0a3a241fd0..cabb1736a8 100644 --- a/ext/mimic/gstmimenc.c +++ b/ext/mimic/gstmimenc.c @@ -67,24 +67,13 @@ enum 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, " + GST_STATIC_CAPS ("video/x-raw, format = (string) \"RGB\", " "framerate = (fraction) [1/1, 30/1], " - "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, " + "height = (int) 240;" + "video/x-raw, format = (string) \"RGB\", " "framerate = (fraction) [1/1, 30/1], " - "red_mask = (int) 16711680, " - "green_mask = (int) 65280, " - "blue_mask = (int) 255, " "width = (int) 160, " "height = (int) 120") + "width = (int) 160, " "height = (int) 120") ); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", @@ -94,11 +83,13 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", ); -static gboolean gst_mim_enc_setcaps (GstPad * pad, GstCaps * caps); -static GstFlowReturn gst_mim_enc_chain (GstPad * pad, GstBuffer * in); -static void gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, GstBuffer * buf, - guint32 payload_size, gboolean keyframe, gboolean paused); -static gboolean gst_mim_enc_event (GstPad * pad, GstEvent * event); +static gboolean gst_mim_enc_setcaps (GstMimEnc * mimenc, GstCaps * caps); +static GstFlowReturn gst_mim_enc_chain (GstPad * pad, GstObject * parent, + GstBuffer * in); +static void gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, guint8 * p, + guint32 payload_size, GstClockTime ts, gboolean keyframe, gboolean paused); +static gboolean gst_mim_enc_event (GstPad * pad, GstObject * parent, + GstEvent * event); static GstStateChangeReturn gst_mim_enc_change_state (GstElement * element, GstStateChange transition); @@ -108,28 +99,34 @@ static void gst_mim_enc_set_property (GObject * object, guint prop_id, static void gst_mim_enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -GST_BOILERPLATE (GstMimEnc, gst_mim_enc, GstElement, GST_TYPE_ELEMENT); +G_DEFINE_TYPE (GstMimEnc, gst_mim_enc, GST_TYPE_ELEMENT); + static void -gst_mim_enc_base_init (gpointer klass) +gst_mim_enc_class_init (GstMimEncClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = gst_mim_enc_set_property; gobject_class->get_property = gst_mim_enc_get_property; + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_mim_enc_change_state); + + GST_DEBUG_CATEGORY_INIT (mimenc_debug, "mimenc", 0, "Mimic encoder plugin"); + + g_object_class_install_property (gobject_class, PROP_PAUSED_MODE, g_param_spec_boolean ("paused-mode", "Paused mode", "If enabled, empty frames will be generated every 4 seconds" " when no data is received", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gst_element_class_add_pad_template (element_class, + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sink_factory)); - gst_element_class_set_details_simple (element_class, + gst_element_class_set_details_simple (gstelement_class, "Mimic Encoder", "Codec/Encoder/Video", "MSN Messenger compatible Mimic video encoder element", @@ -138,34 +135,22 @@ gst_mim_enc_base_init (gpointer klass) } static void -gst_mim_enc_class_init (GstMimEncClass * klass) -{ - GstElementClass *gstelement_class; - - gstelement_class = (GstElementClass *) klass; - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_mim_enc_change_state); - - GST_DEBUG_CATEGORY_INIT (mimenc_debug, "mimenc", 0, "Mimic encoder plugin"); -} - -static void -gst_mim_enc_init (GstMimEnc * mimenc, GstMimEncClass * klass) +gst_mim_enc_init (GstMimEnc * mimenc) { mimenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->sinkpad); - gst_pad_set_setcaps_function (mimenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_mim_enc_setcaps)); gst_pad_set_chain_function (mimenc->sinkpad, GST_DEBUG_FUNCPTR (gst_mim_enc_chain)); gst_pad_set_event_function (mimenc->sinkpad, GST_DEBUG_FUNCPTR (gst_mim_enc_event)); + gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->sinkpad); mimenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_use_fixed_caps (mimenc->srcpad); gst_element_add_pad (GST_ELEMENT (mimenc), mimenc->srcpad); mimenc->enc = NULL; - gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); + gst_segment_init (&mimenc->segment, GST_FORMAT_TIME); mimenc->res = MIMIC_RES_HIGH; mimenc->buffer_size = -1; @@ -213,145 +198,148 @@ gst_mim_enc_get_property (GObject * object, guint prop_id, } } -static gboolean -gst_mim_enc_setcaps (GstPad * pad, GstCaps * caps) +static void +gst_mim_enc_reset_locked (GstMimEnc * mimenc) { - GstMimEnc *mimenc; - GstStructure *structure; - int ret = TRUE, height, width; + if (mimenc->enc != NULL) { + mimic_close (mimenc->enc); + mimenc->enc = NULL; + mimenc->buffer_size = -1; + mimenc->frames = 0; + mimenc->width = 0; + mimenc->height = 0; + } +} - mimenc = GST_MIM_ENC (gst_pad_get_parent (pad)); - g_return_val_if_fail (mimenc != NULL, FALSE); - g_return_val_if_fail (GST_IS_MIM_ENC (mimenc), FALSE); +static void +gst_mim_enc_reset (GstMimEnc * mimenc) +{ + GST_OBJECT_LOCK (mimenc); + gst_mim_enc_reset_locked (mimenc); + GST_OBJECT_UNLOCK (mimenc); +} + +static gboolean +gst_mim_enc_setcaps (GstMimEnc * mimenc, GstCaps * caps) +{ + GstStructure *structure; + int height, width; + gboolean ret = FALSE; structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &width); - if (!ret) { + if (!gst_structure_get_int (structure, "width", &width)) { GST_DEBUG_OBJECT (mimenc, "No width set"); - goto out; + return FALSE; } - ret = gst_structure_get_int (structure, "height", &height); - if (!ret) { + if (!gst_structure_get_int (structure, "height", &height)) { GST_DEBUG_OBJECT (mimenc, "No height set"); - goto out; + return FALSE; } GST_OBJECT_LOCK (mimenc); + if (mimenc->width == width && mimenc->height == height) { + ret = TRUE; + goto out; + } + + if (width == 320 && height == 240) mimenc->res = MIMIC_RES_HIGH; else if (width == 160 && height == 120) mimenc->res = MIMIC_RES_LOW; else { GST_WARNING_OBJECT (mimenc, "Invalid resolution %dx%d", width, height); - ret = FALSE; - GST_OBJECT_UNLOCK (mimenc); goto out; } + gst_mim_enc_reset_locked (mimenc); + mimenc->width = (guint16) width; mimenc->height = (guint16) height; GST_DEBUG_OBJECT (mimenc, "Got info from caps w : %d, h : %d", mimenc->width, mimenc->height); + mimenc->enc = mimic_open (); + if (!mimenc->enc) { + GST_ERROR_OBJECT (mimenc, "mimic_open failed"); + goto out; + } + if (!mimic_encoder_init (mimenc->enc, mimenc->res)) { GST_ERROR_OBJECT (mimenc, "mimic_encoder_init error"); - ret = FALSE; - GST_OBJECT_UNLOCK (mimenc); goto out; } if (!mimic_get_property (mimenc->enc, "buffer_size", &mimenc->buffer_size)) { GST_ERROR_OBJECT (mimenc, "mimic_get_property(buffer_size) error"); - ret = FALSE; } - GST_OBJECT_UNLOCK (mimenc); + ret = TRUE; + out: - gst_object_unref (mimenc); + GST_OBJECT_UNLOCK (mimenc); return ret; } static GstFlowReturn -gst_mim_enc_chain (GstPad * pad, GstBuffer * in) +gst_mim_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * in) { - GstMimEnc *mimenc; - GstBuffer *out_buf = NULL, *buf = NULL; - guchar *data; - gint buffer_size; + GstMimEnc *mimenc = GST_MIM_ENC (parent); + GstBuffer *out = NULL; + GstMapInfo in_map; + GstMapInfo out_map; GstFlowReturn res = GST_FLOW_OK; - GstEvent *event = NULL; gboolean keyframe; - - g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR); - mimenc = GST_MIM_ENC (gst_pad_get_parent (pad)); - - g_return_val_if_fail (GST_IS_MIM_ENC (mimenc), GST_FLOW_ERROR); + gint buffer_size; GST_OBJECT_LOCK (mimenc); - if (mimenc->segment.format == GST_FORMAT_UNDEFINED) { - GST_WARNING_OBJECT (mimenc, "No new-segment received," - " initializing segment with time 0..-1"); - gst_segment_init (&mimenc->segment, GST_FORMAT_TIME); - gst_segment_set_newsegment (&mimenc->segment, - FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); - } - if (mimenc->enc == NULL) { - } + gst_buffer_map (in, &in_map, GST_MAP_READ); - buf = in; - data = GST_BUFFER_DATA (buf); - - out_buf = gst_buffer_new_and_alloc (mimenc->buffer_size + TCP_HEADER_SIZE); - GST_BUFFER_TIMESTAMP (out_buf) = + out = gst_buffer_new_and_alloc (mimenc->buffer_size + TCP_HEADER_SIZE); + gst_buffer_map (out, &out_map, GST_MAP_READWRITE); + GST_BUFFER_TIMESTAMP (out) = gst_segment_to_running_time (&mimenc->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (buf)); - mimenc->last_buffer = GST_BUFFER_TIMESTAMP (out_buf); + GST_BUFFER_TIMESTAMP (in)); + mimenc->last_buffer = GST_BUFFER_TIMESTAMP (out); buffer_size = mimenc->buffer_size; keyframe = (mimenc->frames % MAX_INTERFRAMES) == 0 ? TRUE : FALSE; - if (!mimic_encode_frame (mimenc->enc, data, - GST_BUFFER_DATA (out_buf) + TCP_HEADER_SIZE, &buffer_size, - keyframe)) { - gst_buffer_unref (out_buf); - gst_buffer_unref (buf); + if (!mimic_encode_frame (mimenc->enc, in_map.data, + out_map.data + TCP_HEADER_SIZE, &buffer_size, keyframe)) { + gst_buffer_unmap (in, &in_map); + gst_buffer_unmap (out, &out_map); + gst_buffer_unref (out); GST_ELEMENT_ERROR (mimenc, STREAM, ENCODE, (NULL), ("mimic_encode_frame error")); res = GST_FLOW_ERROR; goto out_unlock; } - if (!keyframe) - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); + gst_buffer_unmap (in, &in_map); + + if (!keyframe) + GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); - GST_BUFFER_SIZE (out_buf) = buffer_size + TCP_HEADER_SIZE; GST_LOG_OBJECT (mimenc, "incoming buf size %d, encoded size %d", - GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (out_buf)); + gst_buffer_get_size (in), gst_buffer_get_size (out)); ++mimenc->frames; /* now let's create that tcp header */ - gst_mim_enc_create_tcp_header (mimenc, out_buf, buffer_size, keyframe, FALSE); + gst_mim_enc_create_tcp_header (mimenc, out_map.data, buffer_size, + GST_BUFFER_TIMESTAMP (out), keyframe, FALSE); - if (mimenc->need_newsegment) { - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); - mimenc->need_newsegment = FALSE; - } + gst_buffer_unmap (out, &out_map); + gst_buffer_resize (out, 0, buffer_size + TCP_HEADER_SIZE); GST_OBJECT_UNLOCK (mimenc); - if (event) { - if (!gst_pad_push_event (mimenc->srcpad, event)) - GST_WARNING_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); - } - - res = gst_pad_push (mimenc->srcpad, out_buf); + res = gst_pad_push (mimenc->srcpad, out); out: - if (buf) - gst_buffer_unref (buf); - gst_object_unref (mimenc); + gst_buffer_unref (in); return res; @@ -361,12 +349,9 @@ out_unlock: } static void -gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, GstBuffer * buf, - guint32 payload_size, gboolean keyframe, gboolean paused) +gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, guint8 * p, + guint32 payload_size, GstClockTime ts, gboolean keyframe, gboolean paused) { - /* 24 bytes */ - guchar *p = (guchar *) GST_BUFFER_DATA (buf); - p[0] = 24; p[1] = paused ? 1 : 0; GST_WRITE_UINT16_LE (p + 2, mimenc->width); @@ -376,66 +361,55 @@ gst_mim_enc_create_tcp_header (GstMimEnc * mimenc, GstBuffer * buf, GST_WRITE_UINT32_LE (p + 12, paused ? 0 : GST_MAKE_FOURCC ('M', 'L', '2', '0')); GST_WRITE_UINT32_LE (p + 16, 0); - GST_WRITE_UINT32_LE (p + 20, GST_BUFFER_TIMESTAMP (buf) / GST_MSECOND); + GST_WRITE_UINT32_LE (p + 20, ts / GST_MSECOND); } + static gboolean -gst_mim_enc_event (GstPad * pad, GstEvent * event) +gst_mim_enc_event (GstPad * pad, GstObject * parent, GstEvent * event) { - GstMimEnc *mimenc = GST_MIM_ENC (gst_pad_get_parent (pad)); + GstMimEnc *mimenc = GST_MIM_ENC (parent); gboolean ret = TRUE; gboolean forward = TRUE; switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_EOS: + gst_mim_enc_reset (mimenc); + break; + case GST_EVENT_CAPS: { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; + GstCaps *caps; + gst_event_parse_caps (event, &caps); - gst_event_parse_new_segment_full (event, &update, &rate, &arate, - &format, &start, &stop, &time); + ret = gst_mim_enc_setcaps (mimenc, caps); + + forward = FALSE; + break; + } + case GST_EVENT_SEGMENT: + { + gst_event_copy_segment (event, &mimenc->segment); /* we need time for now */ - if (format != GST_FORMAT_TIME) + if (mimenc->segment.format != GST_FORMAT_TIME) goto newseg_wrong_format; - GST_DEBUG_OBJECT (mimenc, - "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT - ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, - update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop), - GST_TIME_ARGS (time)); - - /* now configure the values, we need these to time the release of the - * buffers on the srcpad. */ - GST_OBJECT_LOCK (mimenc); - gst_segment_set_newsegment_full (&mimenc->segment, update, - rate, arate, format, start, stop, time); - GST_OBJECT_UNLOCK (mimenc); forward = FALSE; break; } break; - case GST_EVENT_FLUSH_STOP: - GST_OBJECT_LOCK (mimenc); - gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); - mimenc->need_newsegment = TRUE; - GST_OBJECT_UNLOCK (mimenc); - break; default: break; } if (forward) - ret = gst_pad_push_event (mimenc->srcpad, event); + ret = gst_pad_event_default (pad, parent, event); else gst_event_unref (event); done: - gst_object_unref (mimenc); return ret; @@ -478,27 +452,21 @@ paused_mode_task (gpointer data) if (diff > 3.95 * GST_SECOND) { GstBuffer *buffer; - GstEvent *event = NULL; + GstMapInfo out_map; buffer = gst_buffer_new_and_alloc (TCP_HEADER_SIZE); + gst_buffer_map (buffer, &out_map, GST_MAP_WRITE); GST_BUFFER_TIMESTAMP (buffer) = mimenc->last_buffer + PAUSED_MODE_INTERVAL; - gst_mim_enc_create_tcp_header (mimenc, buffer, 0, FALSE, TRUE); + gst_mim_enc_create_tcp_header (mimenc, out_map.data, 0, + GST_BUFFER_TIMESTAMP (buffer), FALSE, TRUE); + gst_buffer_unmap (buffer, &out_map); mimenc->last_buffer += PAUSED_MODE_INTERVAL; - if (mimenc->need_newsegment) { - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0); - mimenc->need_newsegment = FALSE; - } - GST_OBJECT_UNLOCK (mimenc); GST_LOG_OBJECT (mimenc, "Haven't had an incoming buffer in 4 seconds," " sending out a pause frame"); - if (event) { - if (!gst_pad_push_event (mimenc->srcpad, event)) - GST_WARNING_OBJECT (mimenc, "Failed to push NEWSEGMENT event"); - } ret = gst_pad_push (mimenc->srcpad, buffer); if (ret < 0) { GST_WARNING_OBJECT (mimenc, "Error pushing paused header: %s", @@ -545,18 +513,12 @@ gst_mim_enc_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - mimenc->enc = mimic_open (); - if (!mimenc) { - GST_ERROR_OBJECT (mimenc, "mimic_open failed"); - return GST_STATE_CHANGE_FAILURE; - } - break; + case GST_STATE_CHANGE_READY_TO_PAUSED: GST_OBJECT_LOCK (mimenc); gst_segment_init (&mimenc->segment, GST_FORMAT_UNDEFINED); mimenc->last_buffer = GST_CLOCK_TIME_NONE; - mimenc->need_newsegment = TRUE; GST_OBJECT_UNLOCK (mimenc); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: @@ -573,7 +535,8 @@ gst_mim_enc_change_state (GstElement * element, GstStateChange transition) break; } - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + ret = GST_ELEMENT_CLASS (gst_mim_enc_parent_class)->change_state (element, + transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; @@ -605,14 +568,7 @@ gst_mim_enc_change_state (GstElement * element, GstStateChange transition) } break; case GST_STATE_CHANGE_READY_TO_NULL: - GST_OBJECT_LOCK (element); - if (mimenc->enc != NULL) { - mimic_close (mimenc->enc); - mimenc->enc = NULL; - mimenc->buffer_size = -1; - mimenc->frames = 0; - } - GST_OBJECT_UNLOCK (element); + gst_mim_enc_reset (mimenc); break; default: diff --git a/ext/mimic/gstmimenc.h b/ext/mimic/gstmimenc.h index 26ad42d63e..f27d30648a 100644 --- a/ext/mimic/gstmimenc.h +++ b/ext/mimic/gstmimenc.h @@ -57,7 +57,6 @@ struct _GstMimEnc gboolean paused_mode; GstSegment segment; - gboolean need_newsegment; GstClockTime last_buffer; GstClockID clock_id; gboolean stop_paused_mode;