From 4ee8850e99a7ea961b0aa4bc9acf2e7135807e35 Mon Sep 17 00:00:00 2001
From: Andrew Esh <andrew.esh@qterics.com>
Date: Mon, 31 Oct 2016 09:22:03 -0500
Subject: [PATCH 2/3] Fix smoke with local changes

---
 ext/jpeg/gstsmokedec.c | 108 ++++++++-------------
 ext/jpeg/gstsmokeenc.c | 249 ++++++++++++++++++++++++++++++++-----------------
 ext/jpeg/smokecodec.c  |   2 +-
 3 files changed, 204 insertions(+), 155 deletions(-)

diff --git a/ext/jpeg/gstsmokedec.c b/ext/jpeg/gstsmokedec.c
index 816d954..a369e6e 100644
--- a/ext/jpeg/gstsmokedec.c
+++ b/ext/jpeg/gstsmokedec.c
@@ -46,50 +46,24 @@ enum
   PROP_0
 };
 
-static void gst_smokedec_base_init (gpointer g_class);
-static void gst_smokedec_class_init (GstSmokeDec * klass);
-static void gst_smokedec_init (GstSmokeDec * smokedec);
 static void gst_smokedec_finalize (GObject * object);
 
 static GstStateChangeReturn
 gst_smokedec_change_state (GstElement * element, GstStateChange transition);
 
-static GstFlowReturn gst_smokedec_chain (GstPad * pad, GstBuffer * buf);
-
-static GstElementClass *parent_class = NULL;
+static GstFlowReturn
+gst_smokedec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf);
 
 /*static guint gst_smokedec_signals[LAST_SIGNAL] = { 0 }; */
 
-GType
-gst_smokedec_get_type (void)
-{
-  static GType smokedec_type = 0;
-
-  if (!smokedec_type) {
-    static const GTypeInfo smokedec_info = {
-      sizeof (GstSmokeDecClass),
-      gst_smokedec_base_init,
-      NULL,
-      (GClassInitFunc) gst_smokedec_class_init,
-      NULL,
-      NULL,
-      sizeof (GstSmokeDec),
-      0,
-      (GInstanceInitFunc) gst_smokedec_init,
-    };
-
-    smokedec_type =
-        g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeDec", &smokedec_info,
-        0);
-  }
-  return smokedec_type;
-}
+#define gst_smokedec_parent_class parent_class
+G_DEFINE_TYPE (GstSmokeDec, gst_smokedec, GST_TYPE_ELEMENT);
 
 static GstStaticPadTemplate gst_smokedec_src_pad_template =
 GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
     );
 
 static GstStaticPadTemplate gst_smokedec_sink_pad_template =
@@ -102,21 +76,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     );
 
 static void
-gst_smokedec_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_smokedec_src_pad_template);
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_smokedec_sink_pad_template);
-  gst_element_class_set_static_metadata (element_class, "Smoke video decoder",
-      "Codec/Decoder/Video", "Decode video from Smoke format",
-      "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
-gst_smokedec_class_init (GstSmokeDec * klass)
+gst_smokedec_class_init (GstSmokeDecClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
@@ -128,6 +88,14 @@ gst_smokedec_class_init (GstSmokeDec * klass)
 
   gobject_class->finalize = gst_smokedec_finalize;
 
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_smokedec_src_pad_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_smokedec_sink_pad_template));
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Smoke video decoder", "Codec/Decoder/Video",
+      "Decode video from Smoke format", "Wim Taymans <wim@fluendo.com>");
+
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_smokedec_change_state);
 
@@ -143,7 +111,8 @@ gst_smokedec_init (GstSmokeDec * smokedec)
   smokedec->sinkpad =
       gst_pad_new_from_static_template (&gst_smokedec_sink_pad_template,
       "sink");
-  gst_pad_set_chain_function (smokedec->sinkpad, gst_smokedec_chain);
+  gst_pad_set_chain_function (smokedec->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_smokedec_chain));
   gst_element_add_pad (GST_ELEMENT (smokedec), smokedec->sinkpad);
 
   smokedec->srcpad =
@@ -165,11 +134,10 @@ gst_smokedec_finalize (GObject * object)
 }
 
 static GstFlowReturn
-gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
+gst_smokedec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
   GstSmokeDec *smokedec;
-  guint8 *data, *outdata;
-  gulong size, outsize;
+  gulong outsize;
   GstBuffer *outbuf;
   SmokeCodecFlags flags;
   GstClockTime time;
@@ -177,21 +145,22 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
   guint fps_num, fps_denom;
   gint smokeret;
   GstFlowReturn ret;
+  GstMapInfo infobuf, infooutbuf;
 
-  smokedec = GST_SMOKEDEC (gst_pad_get_parent (pad));
+  smokedec = GST_SMOKEDEC (parent);
 
-  data = GST_BUFFER_DATA (buf);
-  size = GST_BUFFER_SIZE (buf);
+  gst_buffer_map (buf, &infobuf, GST_MAP_WRITE);
   time = GST_BUFFER_TIMESTAMP (buf);
 
-  if (size < 1)
+  if (infobuf.size < 1)
     goto too_small;
 
-  GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", size);
+  GST_LOG_OBJECT (smokedec, "got buffer of %lu bytes", infobuf.size);
 
   /* have the ID packet. */
-  if (data[0] == SMOKECODEC_TYPE_ID) {
-    smokeret = smokecodec_parse_id (smokedec->info, data, size);
+  if (infobuf.data[0] == SMOKECODEC_TYPE_ID) {
+    smokeret = smokecodec_parse_id (smokedec->info, infobuf.data, infobuf.size);
+    gst_buffer_unmap (buf, &infobuf);
     if (smokeret != SMOKECODEC_OK)
       goto header_error;
 
@@ -200,9 +169,9 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
   }
 
   /* now handle data packets */
-  GST_DEBUG_OBJECT (smokedec, "reading header %08lx", *(gulong *) data);
-  smokecodec_parse_header (smokedec->info, data, size, &flags, &width, &height,
-      &fps_num, &fps_denom);
+  GST_DEBUG_OBJECT (smokedec, "reading header %08lx", *(gulong *) infobuf.data);
+  smokecodec_parse_header (smokedec->info, infobuf.data, infobuf.size, &flags,
+      &width, &height, &fps_num, &fps_denom);
 
   if (smokedec->height != height || smokedec->width != width ||
       smokedec->fps_num != fps_num || smokedec->fps_denom != fps_denom) {
@@ -214,8 +183,8 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
     smokedec->height = height;
     smokedec->width = width;
 
-    caps = gst_caps_new_simple ("video/x-raw-yuv",
-        "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
+    caps = gst_caps_new_simple ("video/x-raw",
+        "format", G_TYPE_STRING, "I420",
         "width", G_TYPE_INT, width,
         "height", G_TYPE_INT, height,
         "framerate", GST_TYPE_FRACTION, fps_num, fps_denom, NULL);
@@ -225,20 +194,21 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
   }
 
   if (smokedec->need_keyframe) {
-    if (!(flags & SMOKECODEC_KEYFRAME))
+    if (!(flags & SMOKECODEC_KEYFRAME)) {
+      gst_buffer_unmap (buf, &infobuf);
       goto keyframe_skip;
+    }
 
     smokedec->need_keyframe = FALSE;
   }
 
   outsize = width * height + width * height / 2;
   outbuf = gst_buffer_new_and_alloc (outsize);
-  outdata = GST_BUFFER_DATA (outbuf);
+  gst_buffer_map (outbuf, &infooutbuf, GST_MAP_WRITE);
 
   GST_BUFFER_DURATION (outbuf) =
       gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
   GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
-  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokedec->srcpad));
 
   if (time == GST_CLOCK_TIME_NONE) {
     if (GST_BUFFER_OFFSET (buf) == -1) {
@@ -253,7 +223,11 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
   else
     smokedec->next_time = -1;
 
-  smokeret = smokecodec_decode (smokedec->info, data, size, outdata);
+  smokeret =
+      smokecodec_decode (smokedec->info, infobuf.data, infobuf.size,
+      infooutbuf.data);
+  gst_buffer_unmap (buf, &infobuf);
+  gst_buffer_unmap (outbuf, &infooutbuf);
   if (smokeret != SMOKECODEC_OK)
     goto decode_error;
 
@@ -261,8 +235,6 @@ gst_smokedec_chain (GstPad * pad, GstBuffer * buf)
   ret = gst_pad_push (smokedec->srcpad, outbuf);
 
 done:
-  gst_buffer_unref (buf);
-  gst_object_unref (smokedec);
 
   return ret;
 
diff --git a/ext/jpeg/gstsmokeenc.c b/ext/jpeg/gstsmokeenc.c
index 32b0687..3590c10 100644
--- a/ext/jpeg/gstsmokeenc.c
+++ b/ext/jpeg/gstsmokeenc.c
@@ -57,17 +57,20 @@ enum
       /* FILL ME */
 };
 
-static void gst_smokeenc_base_init (gpointer g_class);
-static void gst_smokeenc_class_init (GstSmokeEnc * klass);
-static void gst_smokeenc_init (GstSmokeEnc * smokeenc);
 static void gst_smokeenc_finalize (GObject * object);
 
 static GstStateChangeReturn
 gst_smokeenc_change_state (GstElement * element, GstStateChange transition);
 
-static GstFlowReturn gst_smokeenc_chain (GstPad * pad, GstBuffer * buf);
-static GstCaps *gst_smokeenc_getcaps (GstPad * pad);
-static gboolean gst_smokeenc_setcaps (GstPad * pad, GstCaps * caps);
+static void gst_smokeenc_reset (GstSmokeEnc * smokeenc);
+
+static gboolean
+gst_smokeenc_query (GstPad * pad, GstObject * parent, GstQuery * query);
+
+static gboolean gst_smokeenc_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
+static GstFlowReturn gst_smokeenc_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buf);
 
 static gboolean gst_smokeenc_resync (GstSmokeEnc * smokeenc);
 static void gst_smokeenc_set_property (GObject * object, guint prop_id,
@@ -75,38 +78,14 @@ static void gst_smokeenc_set_property (GObject * object, guint prop_id,
 static void gst_smokeenc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_smokeenc_get_type (void)
-{
-  static GType smokeenc_type = 0;
-
-  if (!smokeenc_type) {
-    static const GTypeInfo smokeenc_info = {
-      sizeof (GstSmokeEncClass),
-      (GBaseInitFunc) gst_smokeenc_base_init,
-      NULL,
-      (GClassInitFunc) gst_smokeenc_class_init,
-      NULL,
-      NULL,
-      sizeof (GstSmokeEnc),
-      0,
-      (GInstanceInitFunc) gst_smokeenc_init,
-    };
-
-    smokeenc_type =
-        g_type_register_static (GST_TYPE_ELEMENT, "GstSmokeEnc", &smokeenc_info,
-        0);
-  }
-  return smokeenc_type;
-}
+#define gst_smokeenc_parent_class parent_class
+G_DEFINE_TYPE (GstSmokeEnc, gst_smokeenc, GST_TYPE_ELEMENT);
 
 static GstStaticPadTemplate gst_smokeenc_sink_pad_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420"))
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420"))
     );
 
 static GstStaticPadTemplate gst_smokeenc_src_pad_template =
@@ -119,21 +98,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
     );
 
 static void
-gst_smokeenc_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_smokeenc_sink_pad_template);
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_smokeenc_src_pad_template);
-  gst_element_class_set_static_metadata (element_class, "Smoke video encoder",
-      "Codec/Encoder/Video", "Encode images into the Smoke format",
-      "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
-gst_smokeenc_class_init (GstSmokeEnc * klass)
+gst_smokeenc_class_init (GstSmokeEncClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
@@ -164,6 +129,14 @@ gst_smokeenc_class_init (GstSmokeEnc * klass)
           "Insert keyframe every N frames", 1, 100000,
           DEFAULT_PROP_KEYFRAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_smokeenc_sink_pad_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_smokeenc_src_pad_template));
+  gst_element_class_set_static_metadata (gstelement_class,
+      "Smoke video encoder", "Codec/Encoder/Video",
+      "Encode images into the Smoke format", "Wim Taymans <wim@fluendo.com>");
+
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_smokeenc_change_state);
 
@@ -178,17 +151,28 @@ gst_smokeenc_init (GstSmokeEnc * smokeenc)
   smokeenc->sinkpad =
       gst_pad_new_from_static_template (&gst_smokeenc_sink_pad_template,
       "sink");
-  gst_pad_set_chain_function (smokeenc->sinkpad, gst_smokeenc_chain);
-  gst_pad_set_getcaps_function (smokeenc->sinkpad, gst_smokeenc_getcaps);
-  gst_pad_set_setcaps_function (smokeenc->sinkpad, gst_smokeenc_setcaps);
+  gst_pad_set_query_function (smokeenc->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_smokeenc_query));
+  gst_pad_set_event_function (smokeenc->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_smokeenc_sink_event));
+  gst_pad_set_chain_function (smokeenc->sinkpad,
+      GST_DEBUG_FUNCPTR (gst_smokeenc_chain));
   gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->sinkpad);
 
   smokeenc->srcpad =
       gst_pad_new_from_static_template (&gst_smokeenc_src_pad_template, "src");
-  gst_pad_set_getcaps_function (smokeenc->srcpad, gst_smokeenc_getcaps);
+  gst_pad_set_query_function (smokeenc->srcpad,
+      GST_DEBUG_FUNCPTR (gst_smokeenc_query));
   gst_pad_use_fixed_caps (smokeenc->srcpad);
   gst_element_add_pad (GST_ELEMENT (smokeenc), smokeenc->srcpad);
 
+  /* init properties */
+  gst_smokeenc_reset (smokeenc);
+}
+
+static void
+gst_smokeenc_reset (GstSmokeEnc * smokeenc)
+{
   smokeenc->min_quality = DEFAULT_PROP_MIN_QUALITY;
   smokeenc->max_quality = DEFAULT_PROP_MAX_QUALITY;
   smokeenc->threshold = DEFAULT_PROP_THRESHOLD;
@@ -207,16 +191,19 @@ gst_smokeenc_finalize (GObject * object)
 }
 
 static GstCaps *
-gst_smokeenc_getcaps (GstPad * pad)
+gst_smokeenc_getcaps (GstPad * pad, GstCaps * filter)
 {
-  GstSmokeEnc *smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+  GstSmokeEnc *smokeenc;
   GstPad *otherpad;
-  GstCaps *result, *caps;
-  const GstCaps *tcaps;
+  GstCaps *result, *caps, *ret;
+  GstCaps *tcaps;
+  GstCapsFeatures *features;
   const char *name;
-  int i;
+  gint i, n;
   GstStructure *structure = NULL;
 
+  smokeenc = GST_SMOKEENC (gst_pad_get_parent (pad));
+
   /* we want to proxy properties like width, height and framerate from the
      other end of the element */
   otherpad = (pad == smokeenc->srcpad) ? smokeenc->sinkpad : smokeenc->srcpad;
@@ -225,7 +212,7 @@ gst_smokeenc_getcaps (GstPad * pad)
   tcaps = gst_pad_get_pad_template_caps (otherpad);
 
   /* get any constraints on the peer pad */
-  caps = gst_pad_peer_get_caps (otherpad);
+  caps = gst_pad_peer_query_caps (otherpad, NULL);
 
   if (caps == NULL)
     caps = gst_caps_copy (tcaps);
@@ -233,31 +220,79 @@ gst_smokeenc_getcaps (GstPad * pad)
     caps = gst_caps_make_writable (caps);
 
   /* intersect with the template */
-  result = gst_caps_intersect (caps, tcaps);
+  result = gst_caps_intersect_full (tcaps, caps, GST_CAPS_INTERSECT_FIRST);
+  gst_caps_unref (tcaps);
   gst_caps_unref (caps);
 
   if (pad == smokeenc->srcpad) {
     name = "video/x-smoke";
   } else {
-    name = "video/x-raw-yuv";
+    name = "video/x-raw";
   }
 
   /* we can only copy width, height, framerate from one side to the other */
-  for (i = 0; i < gst_caps_get_size (result); i++) {
+  ret = gst_caps_new_empty ();
+  n = gst_caps_get_size (result);
+  for (i = 0; i < n; i++) {
     structure = gst_caps_get_structure (result, i);
+    features = gst_caps_get_features (result, i);
+
+    /* If this is already expressed by the existing caps
+     * skip this structure */
+    if (i > 0 && gst_caps_is_subset_structure_full (ret, structure, features))
+      continue;
+
+    /* make copy */
+    structure = gst_structure_copy (structure);
 
     gst_structure_set_name (structure, name);
     gst_structure_remove_field (structure, "format");
     /* ... but for the sink pad, we only do I420 anyway, so add that */
     if (pad == smokeenc->sinkpad) {
-      gst_structure_set (structure, "format", GST_TYPE_FOURCC,
-          GST_STR_FOURCC ("I420"), NULL);
+      gst_structure_set (structure, "format", G_TYPE_STRING, "I420", NULL);
     }
+
+    gst_caps_append_structure_full (ret, structure,
+        gst_caps_features_copy (features));
   }
 
   gst_object_unref (smokeenc);
 
-  return result;
+  if (filter && result) {
+    GstCaps *temp;
+
+    temp = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = temp;
+  }
+
+  gst_caps_unref (result);
+  return ret;
+}
+
+static gboolean
+gst_smokeenc_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  gboolean res;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_smokeenc_getcaps (pad, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+
+      res = TRUE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (pad, parent, query);
+      break;
+  }
+  return res;
 }
 
 static gboolean
@@ -319,6 +354,28 @@ init_failed:
 }
 
 static gboolean
+gst_smokeenc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  gboolean res;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      res = gst_smokeenc_setcaps (pad, caps);
+      gst_event_unref (event);
+      break;
+    }
+    default:
+      res = gst_pad_event_default (pad, parent, event);
+      break;
+  }
+  return res;
+}
+
+static gboolean
 gst_smokeenc_resync (GstSmokeEnc * smokeenc)
 {
   int ret;
@@ -350,52 +407,59 @@ init_failed:
 }
 
 static GstFlowReturn
-gst_smokeenc_chain (GstPad * pad, GstBuffer * buf)
+gst_smokeenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
   GstSmokeEnc *smokeenc;
-  guchar *data, *outdata;
-  gulong size;
-  gint outsize;
   guint encsize;
   GstBuffer *outbuf;
   SmokeCodecFlags flags;
   GstFlowReturn ret;
+  GstMapInfo infobuf, infooutbuf;
 
-  smokeenc = GST_SMOKEENC (GST_OBJECT_PARENT (pad));
+  smokeenc = GST_SMOKEENC (parent);
 
-  data = GST_BUFFER_DATA (buf);
-  size = GST_BUFFER_SIZE (buf);
+  gst_buffer_map (buf, &infobuf, GST_MAP_WRITE);
 
-  GST_LOG_OBJECT (smokeenc, "got buffer of %lu bytes", size);
+  GST_DEBUG_OBJECT (smokeenc, "got buffer of size %lu bytes", infobuf.size);
 
   if (smokeenc->need_header) {
     outbuf = gst_buffer_new_and_alloc (256);
-    outdata = GST_BUFFER_DATA (outbuf);
+    GST_TRACE ("create outbuf 256 %p", outbuf);
+    gst_buffer_map (outbuf, &infooutbuf, GST_MAP_WRITE);
 
-    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+    GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
     GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
 
-    smokecodec_encode_id (smokeenc->info, outdata, &encsize);
+    if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
 
-    GST_BUFFER_SIZE (outbuf) = encsize;
-    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
+    GST_LOG_OBJECT (smokeenc, "smoke encoding buffer with ts=%" GST_TIME_FORMAT,
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+
+    smokecodec_encode_id (smokeenc->info, infooutbuf.data, &encsize);
+    gst_buffer_unmap (outbuf, &infooutbuf);
+
+    gst_buffer_set_size (outbuf, encsize);
 
     ret = gst_pad_push (smokeenc->srcpad, outbuf);
-    if (ret != GST_FLOW_OK)
+
+    if (ret != GST_FLOW_OK) {
+      gst_buffer_unmap (buf, &infobuf);
       goto done;
+    }
 
     smokeenc->need_header = FALSE;
   }
 
-  encsize = outsize = smokeenc->width * smokeenc->height * 3;
-  outbuf = gst_buffer_new_and_alloc (outsize);
-  outdata = GST_BUFFER_DATA (outbuf);
+  encsize = smokeenc->width * smokeenc->height * 3;
+  outbuf = gst_buffer_new_and_alloc (encsize);
+  GST_TRACE ("create outbuf %d %p", encsize, outbuf);
+  gst_buffer_map (outbuf, &infooutbuf, GST_MAP_WRITE);
 
-  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+  GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
   GST_BUFFER_DURATION (outbuf) =
       gst_util_uint64_scale_int (GST_SECOND, smokeenc->fps_denom,
       smokeenc->fps_num);
-  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (smokeenc->srcpad));
 
   flags = 0;
   if ((smokeenc->frame % smokeenc->keyframe) == 0) {
@@ -404,19 +468,32 @@ gst_smokeenc_chain (GstPad * pad, GstBuffer * buf)
   smokecodec_set_quality (smokeenc->info, smokeenc->min_quality,
       smokeenc->max_quality);
   smokecodec_set_threshold (smokeenc->info, smokeenc->threshold);
-  smokecodec_encode (smokeenc->info, data, flags, outdata, &encsize);
-  gst_buffer_unref (buf);
+  smokecodec_encode (smokeenc->info, infobuf.data, flags, infooutbuf.data,
+      &encsize);
 
-  GST_BUFFER_SIZE (outbuf) = encsize;
+  gst_buffer_set_size (outbuf, encsize);
+  infooutbuf.size = encsize;
   GST_BUFFER_OFFSET (outbuf) = smokeenc->frame;
   GST_BUFFER_OFFSET_END (outbuf) = smokeenc->frame + 1;
 
+  gst_buffer_ref (outbuf);
+  gst_buffer_unmap (outbuf, &infooutbuf);
+  GST_TRACE ("unmapped outbuf %d %p", encsize, outbuf);
+  gst_buffer_unmap (buf, &infobuf);
+  GST_TRACE ("unmapped buf %p", buf);
+
   ret = gst_pad_push (smokeenc->srcpad, outbuf);
+  GST_TRACE ("pad pushed outbuf %p size %d of count %d ", outbuf, encsize,
+      smokeenc->frame);
+  gst_buffer_unref (outbuf);
+  GST_TRACE ("unreffed outbuf %p", outbuf);
 
   smokeenc->frame++;
 
 done:
 
+  GST_TRACE ("unreffing buf %p", buf);
+  gst_buffer_unref (buf);
   return ret;
 }
 
diff --git a/ext/jpeg/smokecodec.c b/ext/jpeg/smokecodec.c
index a13152d..0302f9c 100644
--- a/ext/jpeg/smokecodec.c
+++ b/ext/jpeg/smokecodec.c
@@ -465,7 +465,7 @@ smokecodec_encode (SmokeCodecInfo * info,
   STORE16 (out, IDX_NUM_BLOCKS, blocks);
   out[IDX_FLAGS] = (flags & 0xff);
 
-  GST_DEBUG ("blocks %d, encoding %d", blocks, encoding);
+  GST_DEBUG ("blocks %d, encoding %d, insize %d", blocks, encoding, *outsize);
 
   info->jdest.next_output_byte = &out[blocks * 2 + OFFS_PICT];
   info->jdest.free_in_buffer = (*outsize) - OFFS_PICT;
-- 
2.10.1

