From 03752eb501c93c679f70dc419d9fa329b5d3fce7 Mon Sep 17 00:00:00 2001
From: Andrew Esh <andrew.esh@qterics.com>
Date: Wed, 17 May 2017 13:44:05 -0500
Subject: [PATCH 10/25] _common_ Update smoke with local changes

---
 recipes/gst-plugins-good-1.0.recipe                |  31 +-
 .../gst-plugins-good-1.0/0001-Enable-smoke.patch   |  73 +++
 .../0002-Fix-smoke-with-local-changes.patch        | 658 +++++++++++++++++++++
 .../0003-Add-tests-for-smoke.patch                 | 469 +++++++++++++++
 4 files changed, 1227 insertions(+), 4 deletions(-)
 create mode 100644 recipes/gst-plugins-good-1.0/0001-Enable-smoke.patch
 create mode 100644 recipes/gst-plugins-good-1.0/0002-Fix-smoke-with-local-changes.patch
 create mode 100644 recipes/gst-plugins-good-1.0/0003-Add-tests-for-smoke.patch

diff --git a/recipes/gst-plugins-good-1.0.recipe b/recipes/gst-plugins-good-1.0.recipe
index c1c20e2..1918a0b 100644
--- a/recipes/gst-plugins-good-1.0.recipe
+++ b/recipes/gst-plugins-good-1.0.recipe
@@ -6,11 +6,33 @@ class Recipe(custom.GStreamer):
     config_sh = 'sh ./autogen.sh --noconfigure && ./configure'
     configure_options = '--disable-examples --disable-oss4 --disable-oss --disable-dv1394 --disable-aalib --disable-libcaca --disable-jack --disable-shout2 '
     remotes = {'origin': 'git://anongit.freedesktop.org/gstreamer/gst-plugins-good'}
-    deps = ['gstreamer-1.0', 'gst-plugins-base-1.0', 'libjpeg-turbo', 'libpng',
-            'speex', 'gdk-pixbuf', 'libsoup',
-            'orc', 'wavpack', 'flac', 'taglib', 'bzip2', 'zlib',
-            'libvpx', 'libdv', 'cairo']
+    deps = ['gstreamer-1.0', 'gst-plugins-base-1.0', 'libjpeg-turbo',
+            'gdk-pixbuf', 
+            'wavpack', 'taglib', 'zlib',
+            'cairo']
+    # Explicitly disable unneeded plugins
+    configure_options += ' \
+      --disable-alpha --disable-apetag --disable-audiofx --disable-audioparsers --disable-auparse \
+      --disable-autodetect --disable-avi --disable-cutter --disable-debugutils --disable-deinterlace \
+      --disable-dtmf --disable-effectv --disable-equalizer --disable-flv --disable-flx \
+      --disable-goom --disable-goom2k1 --disable-icydemux --disable-id3demux --disable-imagefreeze \
+      --disable-interleave --disable-isomp4 --disable-law --disable-level --disable-matroska \
+      --disable-monoscope --disable-multifile --disable-replaygain --disable-rtp \
+      --disable-rtpmanager --disable-rtsp --disable-shapewipe --disable-smpte --disable-spectrum \
+      --disable-udp --disable-videobox --disable-videofilter --disable-videomixer \
+      --disable-wavenc --disable-wavparse --disable-y4m --disable-directsound --disable-waveform \
+      --disable-oss --disable-oss4 --disable-sunaudio --disable-osx_audio --disable-osx_video \
+      --disable-gst_v4l2 --disable-x --disable-aalib --disable-aalibtest --disable-cairo \
+      --disable-flac --disable-gdk_pixbuf --disable-jack --disable-libcaca --disable-libdv \
+      --disable-libpng --disable-pulse --disable-dv1394 --disable-shout2 --disable-soup \
+      --disable-speex --disable-taglib --disable-vpx --disable-wavpack --disable-zlib --disable-bz2 \
+    '
+    # Explicitly enable plugins
+    configure_options += ' --enable-jpeg --enable-videocrop --enable-multipart'
 
+    patches = ['gst-plugins-good-1.0/0001-Enable-smoke.patch',
+               'gst-plugins-good-1.0/0002-Fix-smoke-with-local-changes.patch',
+               'gst-plugins-good-1.0/0003-Add-tests-for-smoke.patch']
 
     files_lang = ['gst-plugins-good-1.0']
 
@@ -75,6 +97,7 @@ class Recipe(custom.GStreamer):
              'lib/gstreamer-1.0/libgstrtsp%(mext)s',
              'lib/gstreamer-1.0/libgstrtp%(mext)s',
              'lib/gstreamer-1.0/libgstrtpmanager%(mext)s',
+             'lib/gstreamer-1.0/libgstsouphttpsrc%(mext)s',
              'lib/gstreamer-1.0/libgstsoup%(mext)s',
              'lib/gstreamer-1.0/libgstudp%(mext)s',
     ]
diff --git a/recipes/gst-plugins-good-1.0/0001-Enable-smoke.patch b/recipes/gst-plugins-good-1.0/0001-Enable-smoke.patch
new file mode 100644
index 0000000..dd24073
--- /dev/null
+++ b/recipes/gst-plugins-good-1.0/0001-Enable-smoke.patch
@@ -0,0 +1,73 @@
+From b8d937c9729803bf5a14c198224185780ccb05ab Mon Sep 17 00:00:00 2001
+From: Andrew Esh <andrew.esh@qterics.com>
+Date: Fri, 28 Oct 2016 10:54:16 -0500
+Subject: [PATCH 1/3] Enable smoke
+
+---
+ ext/jpeg/Makefile.am | 14 ++++++++++----
+ ext/jpeg/gstjpeg.c   |  4 ----
+ 2 files changed, 10 insertions(+), 8 deletions(-)
+
+diff --git a/ext/jpeg/Makefile.am b/ext/jpeg/Makefile.am
+index f394efb..6c0509e 100644
+--- a/ext/jpeg/Makefile.am
++++ b/ext/jpeg/Makefile.am
+@@ -3,8 +3,10 @@ plugin_LTLIBRARIES = libgstjpeg.la
+ libgstjpeg_la_SOURCES = \
+ 	gstjpeg.c \
+ 	gstjpegenc.c \
+-	gstjpegdec.c
+-# deprected gstsmokeenc.c smokecodec.c gstsmokedec.c
++	gstjpegdec.c \
++	gstsmokeenc.c \
++	smokecodec.c \
++	gstsmokedec.c
+ 
+ libgstjpeg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+ libgstjpeg_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS) -lgstvideo-$(GST_API_VERSION) \
+@@ -14,5 +16,9 @@ libgstjpeg_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+ 
+ noinst_HEADERS = \
+ 	gstjpeg.h \
+-	gstjpegdec.h gstjpegenc.h
+-# deprecated gstsmokeenc.h gstsmokedec.h smokecodec.h smokeformat.h
++	gstjpegdec.h \
++	gstjpegenc.h \
++	gstsmokeenc.h \
++	gstsmokedec.h \
++	smokecodec.h \
++	smokeformat.h
+diff --git a/ext/jpeg/gstjpeg.c b/ext/jpeg/gstjpeg.c
+index 9ecdd5d..3fcf1b7 100644
+--- a/ext/jpeg/gstjpeg.c
++++ b/ext/jpeg/gstjpeg.c
+@@ -27,10 +27,8 @@
+ #include "gstjpeg.h"
+ #include "gstjpegdec.h"
+ #include "gstjpegenc.h"
+-#if 0
+ #include "gstsmokeenc.h"
+ #include "gstsmokedec.h"
+-#endif
+ 
+ GType
+ gst_idct_method_get_type (void)
+@@ -61,7 +59,6 @@ plugin_init (GstPlugin * plugin)
+           GST_TYPE_JPEG_DEC))
+     return FALSE;
+ 
+-#if 0
+   if (!gst_element_register (plugin, "smokeenc", GST_RANK_PRIMARY,
+           GST_TYPE_SMOKEENC))
+     return FALSE;
+@@ -69,7 +66,6 @@ plugin_init (GstPlugin * plugin)
+   if (!gst_element_register (plugin, "smokedec", GST_RANK_PRIMARY,
+           GST_TYPE_SMOKEDEC))
+     return FALSE;
+-#endif
+ 
+   return TRUE;
+ }
+-- 
+2.10.1
+
diff --git a/recipes/gst-plugins-good-1.0/0002-Fix-smoke-with-local-changes.patch b/recipes/gst-plugins-good-1.0/0002-Fix-smoke-with-local-changes.patch
new file mode 100644
index 0000000..233bfc6
--- /dev/null
+++ b/recipes/gst-plugins-good-1.0/0002-Fix-smoke-with-local-changes.patch
@@ -0,0 +1,658 @@
+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
+
diff --git a/recipes/gst-plugins-good-1.0/0003-Add-tests-for-smoke.patch b/recipes/gst-plugins-good-1.0/0003-Add-tests-for-smoke.patch
new file mode 100644
index 0000000..bf7e231
--- /dev/null
+++ b/recipes/gst-plugins-good-1.0/0003-Add-tests-for-smoke.patch
@@ -0,0 +1,469 @@
+From ce447f126f61442610d67b234307f8e9ee450e0c Mon Sep 17 00:00:00 2001
+From: Andrew Esh <andrew.esh@qterics.com>
+Date: Mon, 31 Oct 2016 09:22:58 -0500
+Subject: [PATCH 3/3] Add tests for smoke
+
+---
+ tests/check/Makefile.am         |   6 +
+ tests/check/elements/jpegdec.c  |   1 +
+ tests/check/elements/smokedec.c | 157 +++++++++++++++++++++++++
+ tests/check/elements/smokeenc.c | 254 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 418 insertions(+)
+ create mode 100644 tests/check/elements/smokedec.c
+ create mode 100644 tests/check/elements/smokeenc.c
+
+diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am
+index aa40c70..4c80653 100644
+--- a/tests/check/Makefile.am
++++ b/tests/check/Makefile.am
+@@ -513,6 +513,12 @@ elements_jpegdec_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) -l
+ elements_jpegenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
+ elements_jpegenc_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
+ 
++elements_smokedec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GIO_CFLAGS) $(AM_CFLAGS)
++elements_smokedec_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) -lgstpbutils-$(GST_API_VERSION) $(GST_BASE_LIBS) $(GIO_LIBS) $(LDADD)
++
++elements_smokeenc_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS)
++elements_smokeenc_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstapp-$(GST_API_VERSION) $(GST_BASE_LIBS) $(LDADD)
++
+ elements_matroskamux_LDADD = $(GST_BASE_LIBS) $(LDADD) $(LIBM)
+ 
+ elements_mulawdec_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+diff --git a/tests/check/elements/jpegdec.c b/tests/check/elements/jpegdec.c
+index f6ac523..8413dc4 100644
+--- a/tests/check/elements/jpegdec.c
++++ b/tests/check/elements/jpegdec.c
+@@ -36,6 +36,7 @@ GST_START_TEST (test_jpegdec_explicit)
+   pipeline = gst_pipeline_new (NULL);
+   source = gst_element_factory_make ("filesrc", NULL);
+   dec = gst_element_factory_make ("jpegdec", NULL);
++  fail_unless (dec != NULL);
+   sink = gst_element_factory_make ("appsink", NULL);
+ 
+   gst_bin_add_many (GST_BIN (pipeline), source, dec, sink, NULL);
+diff --git a/tests/check/elements/smokedec.c b/tests/check/elements/smokedec.c
+new file mode 100644
+index 0000000..01afbb6
+--- /dev/null
++++ b/tests/check/elements/smokedec.c
+@@ -0,0 +1,157 @@
++/* GStreamer
++ * unit test for smokedec
++ * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@collabora.co.uk>
++ * Copyright (C) <2012> Mathias Hasselmann <mathias@openismus.com>
++ *
++ * 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., 51 Franklin St, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include <unistd.h>
++
++#include <gio/gio.h>
++#include <gst/check/gstcheck.h>
++#include <gst/app/gstappsink.h>
++#include <gst/pbutils/gstdiscoverer.h>
++
++/* Verify smokedec is working when explictly requested by a pipeline. */
++GST_START_TEST (test_smokedec_explicit)
++{
++  GstElement *pipeline, *source, *dec, *sink;
++  GstSample *sample;
++
++  /* construct a pipeline that explicitly uses smokedec */
++  pipeline = gst_pipeline_new (NULL);
++  source = gst_element_factory_make ("filesrc", NULL);
++  dec = gst_element_factory_make ("smokedec", NULL);
++  fail_unless (dec != NULL);
++  sink = gst_element_factory_make ("appsink", NULL);
++
++  gst_bin_add_many (GST_BIN (pipeline), source, dec, sink, NULL);
++  gst_element_link_many (source, dec, sink, NULL);
++
++  /* point that pipeline to our test image */
++  {
++    char *filename = g_build_filename (GST_TEST_FILES_PATH, "image.jpg", NULL);
++    g_object_set (G_OBJECT (source), "location", filename, NULL);
++    g_free (filename);
++  }
++
++  gst_element_set_state (pipeline, GST_STATE_PLAYING);
++
++  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
++  fail_unless (GST_IS_SAMPLE (sample));
++
++  /* do some basic checks to verify image decoding */
++  {
++    GstCaps *decoded;
++    GstCaps *expected;
++
++    decoded = gst_sample_get_caps (sample);
++    expected = gst_caps_from_string ("video/x-raw, width=120, height=160");
++
++    fail_unless (gst_caps_is_always_compatible (decoded, expected));
++
++    gst_caps_unref (expected);
++  }
++  gst_sample_unref (sample);
++
++  /* wait for EOS */
++  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
++  fail_unless (sample == NULL);
++  fail_unless (gst_app_sink_is_eos (GST_APP_SINK (sink)));
++
++  gst_element_set_state (pipeline, GST_STATE_NULL);
++  gst_object_unref (pipeline);
++}
++
++GST_END_TEST;
++
++/* Verify JPEG discovery is working. Right now smokedec would be used,
++ * but I have no idea how to actually verify this. */
++GST_START_TEST (test_smokedec_discover)
++{
++  GstDiscoverer *disco;
++  GError *error = NULL;
++  char *uri;
++  GstDiscovererInfo *info;
++  GstDiscovererVideoInfo *video;
++
++  disco = gst_discoverer_new (5 * GST_SECOND, &error);
++
++  fail_unless (GST_IS_DISCOVERER (disco));
++  fail_unless (error == NULL, "%s", (error ? error->message : ""));
++
++  {
++    GFile *testdir = g_file_new_for_path (GST_TEST_FILES_PATH);
++    GFile *testfile = g_file_resolve_relative_path (testdir, "image.jpg");
++    uri = g_file_get_uri (testfile);
++    g_object_unref (testfile);
++    g_object_unref (testdir);
++  }
++
++  info = gst_discoverer_discover_uri (disco, uri, &error);
++  fail_unless (GST_IS_DISCOVERER_INFO (info));
++  fail_unless (error == NULL, "%s: %s", uri, (error ? error->message : ""));
++
++  fail_unless_equals_string (gst_discoverer_info_get_uri (info), uri);
++  fail_unless_equals_int (gst_discoverer_info_get_result (info),
++      GST_DISCOVERER_OK);
++
++  video =
++      GST_DISCOVERER_VIDEO_INFO (gst_discoverer_info_get_stream_info (info));
++  fail_unless (video != NULL);
++
++  fail_unless (gst_discoverer_video_info_is_image (video));
++  fail_unless_equals_int (gst_discoverer_video_info_get_width (video), 120);
++  fail_unless_equals_int (gst_discoverer_video_info_get_height (video), 160);
++
++  gst_discoverer_info_unref (video);
++  gst_discoverer_info_unref (info);
++  g_free (uri);
++  g_object_unref (disco);
++}
++
++GST_END_TEST;
++
++static Suite *
++smokedec_suite (void)
++{
++  Suite *s = suite_create ("smokedec");
++  TCase *tc_chain = tcase_create ("general");
++
++  suite_add_tcase (s, tc_chain);
++  tcase_add_test (tc_chain, test_smokedec_explicit);
++  tcase_add_test (tc_chain, test_smokedec_discover);
++
++  return s;
++}
++
++int
++main (int argc, char **argv)
++{
++  int nf;
++
++  Suite *s = smokedec_suite ();
++  SRunner *sr = srunner_create (s);
++
++  gst_check_init (&argc, &argv);
++
++  srunner_run_all (sr, CK_NORMAL);
++  nf = srunner_ntests_failed (sr);
++  srunner_free (sr);
++
++  return nf;
++}
+diff --git a/tests/check/elements/smokeenc.c b/tests/check/elements/smokeenc.c
+new file mode 100644
+index 0000000..e567bc1
+--- /dev/null
++++ b/tests/check/elements/smokeenc.c
+@@ -0,0 +1,254 @@
++/* GStreamer
++ *
++ * unit test for smokeenc
++ *
++ * Copyright (C) <2010> Thiago Santos <thiago.sousa.santos@collabora.co.uk>
++ *
++ * 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., 51 Franklin St, Fifth Floor,
++ * Boston, MA 02110-1301, USA.
++ */
++
++#include <unistd.h>
++
++#include <gst/check/gstcheck.h>
++#include <gst/app/gstappsink.h>
++
++/* For ease of programming we use globals to keep refs for our floating
++ * sink pads we create; otherwise we always have to do get_pad,
++ * get_peer, and then remove references in every test function */
++static GstPad *mysinkpad;
++static GstPad *mysrcpad;
++
++#define JPEG_CAPS_STRING "image/jpeg"
++
++#define JPEG_CAPS_RESTRICTIVE "image/jpeg, " \
++    "width = (int) [100, 200], " \
++    "framerate = (fraction) 25/1, " \
++    "extraparameter = (string) { abc, def }"
++
++static GstStaticPadTemplate jpeg_sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
++    GST_PAD_SINK,
++    GST_PAD_ALWAYS,
++    GST_STATIC_CAPS (JPEG_CAPS_STRING));
++
++static GstStaticPadTemplate any_sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
++    GST_PAD_SINK,
++    GST_PAD_ALWAYS,
++    GST_STATIC_CAPS_ANY);
++
++static GstStaticPadTemplate jpeg_restrictive_sinktemplate =
++GST_STATIC_PAD_TEMPLATE ("sink",
++    GST_PAD_SINK,
++    GST_PAD_ALWAYS,
++    GST_STATIC_CAPS (JPEG_CAPS_RESTRICTIVE));
++
++static GstStaticPadTemplate any_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
++    GST_PAD_SRC,
++    GST_PAD_ALWAYS,
++    GST_STATIC_CAPS_ANY);
++
++
++static GstElement *
++setup_smokeenc (GstStaticPadTemplate * sinktemplate)
++{
++  GstElement *smokeenc;
++
++  GST_DEBUG ("setup_smokeenc");
++  smokeenc = gst_check_setup_element ("smokeenc");
++  mysinkpad = gst_check_setup_sink_pad (smokeenc, sinktemplate);
++  mysrcpad = gst_check_setup_src_pad (smokeenc, &any_srctemplate);
++  gst_pad_set_active (mysrcpad, TRUE);
++  gst_pad_set_active (mysinkpad, TRUE);
++
++  return smokeenc;
++}
++
++static void
++cleanup_smokeenc (GstElement * smokeenc)
++{
++  GST_DEBUG ("cleanup_smokeenc");
++  gst_element_set_state (smokeenc, GST_STATE_NULL);
++
++  gst_pad_set_active (mysrcpad, FALSE);
++  gst_pad_set_active (mysinkpad, FALSE);
++  gst_check_teardown_sink_pad (smokeenc);
++  gst_check_teardown_src_pad (smokeenc);
++  gst_check_teardown_element (smokeenc);
++}
++
++static GstBuffer *
++create_video_buffer (GstCaps * caps)
++{
++  GstElement *pipeline;
++  GstElement *cf;
++  GstElement *sink;
++  GstSample *sample;
++  GstBuffer *buffer;
++
++  pipeline =
++      gst_parse_launch
++      ("videotestsrc num-buffers=1 ! capsfilter name=cf ! appsink name=sink",
++      NULL);
++  g_assert (pipeline != NULL);
++
++  cf = gst_bin_get_by_name (GST_BIN (pipeline), "cf");
++  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
++
++  g_object_set (G_OBJECT (cf), "caps", caps, NULL);
++
++  gst_element_set_state (pipeline, GST_STATE_PLAYING);
++
++  sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
++
++  gst_element_set_state (pipeline, GST_STATE_NULL);
++  gst_object_unref (pipeline);
++  gst_object_unref (sink);
++  gst_object_unref (cf);
++
++  buffer = gst_sample_get_buffer (sample);
++  gst_buffer_ref (buffer);
++
++  gst_sample_unref (sample);
++
++  return buffer;
++}
++
++
++GST_START_TEST (test_smokeenc_getcaps)
++{
++  GstElement *smokeenc;
++  GstPad *sinkpad;
++  GstCaps *caps;
++  GstStructure *structure;
++  gint fps_n;
++  gint fps_d;
++  const GValue *value;
++
++  /* we are going to do some get caps to confirm it doesn't return non-subset
++   * caps */
++
++  smokeenc = setup_smokeenc (&any_sinktemplate);
++  sinkpad = gst_element_get_static_pad (smokeenc, "sink");
++  /* this should assert if non-subset */
++  caps = gst_pad_query_caps (sinkpad, NULL);
++  gst_caps_unref (caps);
++  gst_object_unref (sinkpad);
++  cleanup_smokeenc (smokeenc);
++
++  smokeenc = setup_smokeenc (&jpeg_sinktemplate);
++  sinkpad = gst_element_get_static_pad (smokeenc, "sink");
++  /* this should assert if non-subset */
++  caps = gst_pad_query_caps (sinkpad, NULL);
++  gst_caps_unref (caps);
++  gst_object_unref (sinkpad);
++  cleanup_smokeenc (smokeenc);
++
++  /* now use a more restricted one and check the resulting caps */
++  smokeenc = setup_smokeenc (&jpeg_restrictive_sinktemplate);
++  sinkpad = gst_element_get_static_pad (smokeenc, "sink");
++  /* this should assert if non-subset */
++  caps = gst_pad_query_caps (sinkpad, NULL);
++  structure = gst_caps_get_structure (caps, 0);
++
++  /* check the width */
++  value = gst_structure_get_value (structure, "width");
++  fail_unless (gst_value_get_int_range_min (value) == 100);
++  fail_unless (gst_value_get_int_range_max (value) == 200);
++
++  fail_unless (gst_structure_get_fraction (structure, "framerate", &fps_n,
++          &fps_d));
++  fail_unless (fps_n == 25);
++  fail_unless (fps_d == 1);
++
++  gst_caps_unref (caps);
++  gst_object_unref (sinkpad);
++  cleanup_smokeenc (smokeenc);
++}
++
++GST_END_TEST;
++
++
++GST_START_TEST (test_smokeenc_different_caps)
++{
++  GstElement *smokeenc;
++  GstBuffer *buffer;
++  GstCaps *caps;
++  GstCaps *allowed_caps;
++
++  /* now use a more restricted one and check the resulting caps */
++  smokeenc = setup_smokeenc (&any_sinktemplate);
++  gst_element_set_state (smokeenc, GST_STATE_PLAYING);
++
++  /* push first buffer with 800x600 resolution */
++  caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
++      800, "height", G_TYPE_INT, 600, "framerate",
++      GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, "I420", NULL);
++  gst_check_setup_events (mysrcpad, smokeenc, caps, GST_FORMAT_TIME);
++  fail_unless ((buffer = create_video_buffer (caps)) != NULL);
++  gst_caps_unref (caps);
++  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
++
++  /* check the allowed caps to see if a second buffer with a different
++   * caps could be negotiated */
++  allowed_caps = gst_pad_get_allowed_caps (mysrcpad);
++
++  /* the caps we want to negotiate to */
++  caps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
++      640, "height", G_TYPE_INT, 480, "framerate",
++      GST_TYPE_FRACTION, 1, 1, "format", G_TYPE_STRING, "I420", NULL);
++  fail_unless (gst_caps_can_intersect (allowed_caps, caps));
++  fail_unless (gst_pad_set_caps (mysrcpad, caps));
++
++  /* push second buffer with 640x480 resolution */
++  buffer = create_video_buffer (caps);
++  gst_caps_unref (caps);
++  fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
++
++  gst_caps_unref (allowed_caps);
++  gst_element_set_state (smokeenc, GST_STATE_NULL);
++  cleanup_smokeenc (smokeenc);
++}
++
++GST_END_TEST;
++
++static Suite *
++smokeenc_suite (void)
++{
++  Suite *s = suite_create ("smokeenc");
++  TCase *tc_chain = tcase_create ("general");
++
++  suite_add_tcase (s, tc_chain);
++  tcase_add_test (tc_chain, test_smokeenc_getcaps);
++  tcase_add_test (tc_chain, test_smokeenc_different_caps);
++
++  return s;
++}
++
++int
++main (int argc, char **argv)
++{
++  int nf;
++
++  Suite *s = smokeenc_suite ();
++  SRunner *sr = srunner_create (s);
++
++  gst_check_init (&argc, &argv);
++
++  srunner_run_all (sr, CK_NORMAL);
++  nf = srunner_ntests_failed (sr);
++  srunner_free (sr);
++
++  return nf;
++}
+-- 
+2.10.1
+
-- 
2.15.0

