public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/opencv] opencv5: backport support for GStreamer 1 (#1123078)
@ 2026-08-28 13:30 Rex Dieter
  0 siblings, 0 replies; only message in thread
From: Rex Dieter @ 2026-08-28 13:30 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/opencv
Branch : opencv5
Commit : 053e3d73adc3de04632b6c23b2e0e1668a05ca7e
Author : Rex Dieter <rdieter@math.unl.edu>
Date   : 2014-07-25T07:09:56-05:00
Stats  : +2247/-1 in 6 file(s)
URL    : https://src.fedoraproject.org/rpms/opencv/c/053e3d73adc3de04632b6c23b2e0e1668a05ca7e?branch=opencv5

Log:
backport support for GStreamer 1 (#1123078)

---
diff --git a/0550-bomb-commit-of-gstreamer-videocapture-and-videowrite.patch b/0550-bomb-commit-of-gstreamer-videocapture-and-videowrite.patch
new file mode 100644
index 0000000..cda41e4
--- /dev/null
+++ b/0550-bomb-commit-of-gstreamer-videocapture-and-videowrite.patch
@@ -0,0 +1,1844 @@
+diff -up opencv-2.4.9/CMakeLists.txt.10 opencv-2.4.9/CMakeLists.txt
+--- opencv-2.4.9/CMakeLists.txt.10	2014-04-11 05:15:26.000000000 -0500
++++ opencv-2.4.9/CMakeLists.txt	2014-07-24 16:34:29.528440217 -0500
+@@ -136,6 +136,7 @@ OCV_OPTION(WITH_EIGEN          "Include
+ OCV_OPTION(WITH_VFW            "Include Video for Windows support"           ON   IF WIN32 )
+ OCV_OPTION(WITH_FFMPEG         "Include FFMPEG support"                      ON   IF (NOT ANDROID AND NOT IOS))
+ OCV_OPTION(WITH_GSTREAMER      "Include Gstreamer support"                   ON   IF (UNIX AND NOT APPLE AND NOT ANDROID) )
++OCV_OPTION(WITH_GSTREAMER_1_X  "Include Gstreamer 1.x support"               OFF)
+ OCV_OPTION(WITH_GTK            "Include GTK support"                         ON   IF (UNIX AND NOT APPLE AND NOT ANDROID) )
+ OCV_OPTION(WITH_IMAGEIO        "ImageIO support for OS X"                    OFF  IF APPLE )
+ OCV_OPTION(WITH_IPP            "Include Intel IPP support"                   OFF  IF (MSVC OR X86 OR X86_64) )
+@@ -861,10 +862,12 @@ endif(DEFINED WITH_FFMPEG)
+ if(DEFINED WITH_GSTREAMER)
+   status("    GStreamer:"      HAVE_GSTREAMER      THEN ""                                         ELSE NO)
+   if(HAVE_GSTREAMER)
+-    status("      base:"       "YES (ver ${ALIASOF_gstreamer-base-0.10_VERSION})")
+-    status("      app:"        "YES (ver ${ALIASOF_gstreamer-app-0.10_VERSION})")
+-    status("      video:"      "YES (ver ${ALIASOF_gstreamer-video-0.10_VERSION})")
+-  endif()
++    status("      base:"       "YES (ver ${GSTREAMER_BASE_VERSION})")
++    status("      video:"      "YES (ver ${GSTREAMER_VIDEO_VERSION})")
++    status("      app:"        "YES (ver ${GSTREAMER_APP_VERSION})")
++    status("      riff:"       "YES (ver ${GSTREAMER_RIFF_VERSION})")
++    status("      pbutils:"    "YES (ver ${GSTREAMER_PBUTILS_VERSION})")
++  endif(HAVE_GSTREAMER)
+ endif(DEFINED WITH_GSTREAMER)
+ 
+ if(DEFINED WITH_OPENNI)
+diff -up opencv-2.4.9/cmake/OpenCVFindLibsVideo.cmake.10 opencv-2.4.9/cmake/OpenCVFindLibsVideo.cmake
+--- opencv-2.4.9/cmake/OpenCVFindLibsVideo.cmake.10	2014-04-11 05:15:26.000000000 -0500
++++ opencv-2.4.9/cmake/OpenCVFindLibsVideo.cmake	2014-07-24 16:30:53.272087384 -0500
+@@ -12,15 +12,44 @@ endif(WITH_VFW)
+ 
+ # --- GStreamer ---
+ ocv_clear_vars(HAVE_GSTREAMER)
+-if(WITH_GSTREAMER)
+-  CHECK_MODULE(gstreamer-base-0.10 HAVE_GSTREAMER)
+-  if(HAVE_GSTREAMER)
+-    CHECK_MODULE(gstreamer-app-0.10 HAVE_GSTREAMER)
++# try to find gstreamer 0.10 first
++if(WITH_GSTREAMER AND NOT WITH_GSTREAMER_1_X)
++  CHECK_MODULE(gstreamer-base-0.10 HAVE_GSTREAMER_BASE)
++  CHECK_MODULE(gstreamer-video-0.10 HAVE_GSTREAMER_VIDEO)
++  CHECK_MODULE(gstreamer-app-0.10 HAVE_GSTREAMER_APP)
++  CHECK_MODULE(gstreamer-riff-0.10 HAVE_GSTREAMER_RIFF)
++  CHECK_MODULE(gstreamer-pbutils-0.10 HAVE_GSTREAMER_PBUTILS)
++
++  if(HAVE_GSTREAMER_BASE AND HAVE_GSTREAMER_VIDEO AND HAVE_GSTREAMER_APP AND HAVE_GSTREAMER_RIFF AND HAVE_GSTREAMER_PBUTILS)
++      set(HAVE_GSTREAMER TRUE)
++      set(GSTREAMER_BASE_VERSION ${ALIASOF_gstreamer-base-0.10_VERSION})
++      set(GSTREAMER_VIDEO_VERSION ${ALIASOF_gstreamer-video-0.10_VERSION})
++      set(GSTREAMER_APP_VERSION ${ALIASOF_gstreamer-app-0.10_VERSION})
++      set(GSTREAMER_RIFF_VERSION ${ALIASOF_gstreamer-riff-0.10_VERSION})
++      set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-0.10_VERSION})
+   endif()
+-  if(HAVE_GSTREAMER)
+-    CHECK_MODULE(gstreamer-video-0.10 HAVE_GSTREAMER)
++  
++endif(WITH_GSTREAMER AND NOT WITH_GSTREAMER_1_X)
++
++# if gstreamer 0.10 was not found, or we specified we wanted 1.x, try to find it
++if(WITH_GSTREAMER_1_X OR NOT HAVE_GSTREAMER)
++  #check for 1.x
++  CHECK_MODULE(gstreamer-base-1.0 HAVE_GSTREAMER_BASE)
++  CHECK_MODULE(gstreamer-video-1.0 HAVE_GSTREAMER_VIDEO)
++  CHECK_MODULE(gstreamer-app-1.0 HAVE_GSTREAMER_APP)
++  CHECK_MODULE(gstreamer-riff-1.0 HAVE_GSTREAMER_RIFF)
++  CHECK_MODULE(gstreamer-pbutils-1.0 HAVE_GSTREAMER_PBUTILS)
++  
++  if(HAVE_GSTREAMER_BASE AND HAVE_GSTREAMER_VIDEO AND HAVE_GSTREAMER_APP AND HAVE_GSTREAMER_RIFF AND HAVE_GSTREAMER_PBUTILS)
++      set(HAVE_GSTREAMER TRUE)
++      set(GSTREAMER_BASE_VERSION ${ALIASOF_gstreamer-base-1.0_VERSION})
++      set(GSTREAMER_VIDEO_VERSION ${ALIASOF_gstreamer-video-1.0_VERSION})
++      set(GSTREAMER_APP_VERSION ${ALIASOF_gstreamer-app-1.0_VERSION})
++      set(GSTREAMER_RIFF_VERSION ${ALIASOF_gstreamer-riff-1.0_VERSION})
++      set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-1.0_VERSION})
+   endif()
+-endif(WITH_GSTREAMER)
++  
++endif(WITH_GSTREAMER_1_X OR NOT HAVE_GSTREAMER)
+ 
+ # --- unicap ---
+ ocv_clear_vars(HAVE_UNICAP)
+diff -up opencv-2.4.9/modules/highgui/src/cap_gstreamer.cpp.10 opencv-2.4.9/modules/highgui/src/cap_gstreamer.cpp
+--- opencv-2.4.9/modules/highgui/src/cap_gstreamer.cpp.10	2014-04-11 05:15:26.000000000 -0500
++++ opencv-2.4.9/modules/highgui/src/cap_gstreamer.cpp	2014-07-24 16:30:53.273087371 -0500
+@@ -39,25 +39,27 @@
+ //
+ //M*/
+ 
+-// Author: Nils Hasler <hasler@mpi-inf.mpg.de>
+-//
+-//         Max-Planck-Institut Informatik
+-//
+-// this implementation was inspired by gnash's gstreamer interface
+-
+-//
+-// use GStreamer to read a video
+-//
+-
++/*!
++ * \file cap_gstreamer.cpp
++ * \author Nils Hasler <hasler@mpi-inf.mpg.de>
++ *         Max-Planck-Institut Informatik
++ * \author Dirk Van Haerenborgh <vhdirk@gmail.com>
++ *
++ * \brief Use GStreamer to read/write video
++ */
+ #include "precomp.hpp"
+ #include <unistd.h>
+ #include <string.h>
+-#include <map>
+ #include <gst/gst.h>
++#include <gst/gstbuffer.h>
+ #include <gst/video/video.h>
+ #include <gst/app/gstappsink.h>
+ #include <gst/app/gstappsrc.h>
+ #include <gst/riff/riff-media.h>
++#include <gst/pbutils/encoding-profile.h>
++#include <gst/pbutils/missing-plugins.h>
++//#include <gst/base/gsttypefindhelper.h>
++
+ 
+ #ifdef NDEBUG
+ #define CV_WARN(message)
+@@ -65,9 +67,23 @@
+ #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
+ #endif
+ 
++#if GST_VERSION_MAJOR > 0
++#define COLOR_ELEM "videoconvert"
++#else
++#define COLOR_ELEM "ffmpegcolorspace"
++#endif
++
++
++void toFraction(double decimal, double &numerator, double &denominator);
++void handleMessage(GstElement * pipeline);
++
++
+ static cv::Mutex gst_initializer_mutex;
+ 
+-class gst_initializer
++/*!
++ * \brief The gst_initializer class
++ * Initializes gstreamer once in the whole process
++ */class gst_initializer
+ {
+ public:
+     static void init()
+@@ -80,9 +96,16 @@ private:
+     gst_initializer()
+     {
+         gst_init(NULL, NULL);
++//        gst_debug_set_active(TRUE);
++//        gst_debug_set_colored(TRUE);
++//        gst_debug_set_default_threshold(GST_LEVEL_INFO);
+     }
+ };
+ 
++/*!
++ * \brief The CvCapture_GStreamer class
++ * Use GStreamer to capture video
++ */
+ class CvCapture_GStreamer : public CvCapture
+ {
+ public:
+@@ -100,259 +123,486 @@ public:
+ protected:
+     void init();
+     bool reopen();
+-    void handleMessage();
++    bool isPipelinePlaying();
++    void startPipeline();
++    void stopPipeline();
+     void restartPipeline();
+-    void setFilter(const char*, int, int, int);
++    void setFilter(const char* prop, int type, int v1, int v2 = NULL);
+     void removeFilter(const char *filter);
+-    void static newPad(GstElement *myelement,
+-                             GstPad     *pad,
+-                             gpointer    data);
+-    GstElement           *pipeline;
+-    GstElement           *uridecodebin;
+-    GstElement           *color;
+-    GstElement           *sink;
+-
+-    GstBuffer           *buffer;
+-    GstCaps            *caps;
+-    IplImage           *frame;
++    static void newPad(GstElement *myelement,
++                       GstPad     *pad,
++                       gpointer    data);
++    GstElement*   pipeline;
++    GstElement*   uridecodebin;
++    GstElement*   color;
++    GstElement*   sink;
++#if GST_VERSION_MAJOR > 0
++    GstSample*    sample;
++    GstMapInfo*   info;
++#endif
++    GstBuffer*    buffer;
++    GstCaps*      caps;
++    GstCaps*      buffer_caps;
++    IplImage*     frame;
+ };
+ 
++/*!
++ * \brief CvCapture_GStreamer::init
++ * inits the class
++ */
+ void CvCapture_GStreamer::init()
+ {
+-    pipeline=0;
+-    frame=0;
+-    buffer=0;
+-    frame=0;
+-
++    pipeline = NULL;
++    frame = NULL;
++    buffer = NULL;
++    buffer_caps = NULL;
++#if GST_VERSION_MAJOR > 0
++    sample = NULL;
++    info = new GstMapInfo;
++#endif
+ }
+ 
+-void CvCapture_GStreamer::handleMessage()
++/*!
++ * \brief CvCapture_GStreamer::close
++ * Closes the pipeline and destroys all instances
++ */
++void CvCapture_GStreamer::close()
+ {
+-    GstBus* bus = gst_element_get_bus(pipeline);
+-
+-    while(gst_bus_have_pending(bus)) {
+-        GstMessage* msg = gst_bus_pop(bus);
+-
+-//        printf("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg));
+-
+-        switch (GST_MESSAGE_TYPE (msg)) {
+-        case GST_MESSAGE_STATE_CHANGED:
+-            GstState oldstate, newstate, pendstate;
+-            gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate);
+-//            printf("state changed from %d to %d (%d)\n", oldstate, newstate, pendstate);
+-            break;
+-        case GST_MESSAGE_ERROR: {
+-            GError *err;
+-            gchar *debug;
+-            gst_message_parse_error(msg, &err, &debug);
+-
+-            fprintf(stderr, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s\n",
+-                  gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
+-
+-            g_error_free(err);
+-            g_free(debug);
+-
+-            gst_element_set_state(pipeline, GST_STATE_NULL);
+-
+-            break;
+-            }
+-        case GST_MESSAGE_EOS:
+-//            CV_WARN("NetStream has reached the end of the stream.");
+-
+-            break;
+-        default:
+-//            CV_WARN("unhandled message\n");
+-            break;
+-        }
++    if (isPipelinePlaying())
++        this->stopPipeline();
+ 
+-        gst_message_unref(msg);
++    if(pipeline) {
++        gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
++        gst_object_unref(GST_OBJECT(pipeline));
++    }
++    if(uridecodebin){
++        gst_object_unref(GST_OBJECT(uridecodebin));
++    }
++    if(color){
++        gst_object_unref(GST_OBJECT(color));
++    }
++    if(sink){
++        gst_object_unref(GST_OBJECT(sink));
++    }
++    if(buffer)
++        gst_buffer_unref(buffer);
++    if(frame) {
++        frame->imageData = 0;
++        cvReleaseImage(&frame);
++    }
++    if(caps){
++        gst_caps_unref(caps);
+     }
++    if(buffer_caps){
++        gst_caps_unref(buffer_caps);
++    }
++#if GST_VERSION_MAJOR > 0
++    if(sample){
++        gst_sample_unref(sample);
++    }
++#endif
+ 
+-    gst_object_unref(GST_OBJECT(bus));
+ }
+ 
+-//
+-// start the pipeline, grab a buffer, and pause again
+-//
++/*!
++ * \brief CvCapture_GStreamer::grabFrame
++ * \return
++ * Grabs a sample from the pipeline, awaiting consumation by retreiveFrame.
++ * The pipeline is started if it was not running yet
++ */
+ bool CvCapture_GStreamer::grabFrame()
+ {
+-
+     if(!pipeline)
+         return false;
+ 
++    // start the pipeline if it was not in playing state yet
++    if(!this->isPipelinePlaying())
++        this->startPipeline();
++
++    // bail out if EOS
+     if(gst_app_sink_is_eos(GST_APP_SINK(sink)))
+         return false;
+ 
++#if GST_VERSION_MAJOR == 0
+     if(buffer)
+         gst_buffer_unref(buffer);
+-    handleMessage();
+ 
+     buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink));
++#else
++    if(sample)
++        gst_sample_unref(sample);
++
++    sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
++
++    if(!sample)
++        return false;
++
++    buffer = gst_sample_get_buffer(sample);
++#endif
++
+     if(!buffer)
+         return false;
+ 
+     return true;
+ }
+ 
+-//
+-// decode buffer
+-//
++/*!
++ * \brief CvCapture_GStreamer::retrieveFrame
++ * \return IplImage pointer. [Transfer Full]
++ *  Retreive the previously grabbed buffer, and wrap it in an IPLImage structure
++ */
+ IplImage * CvCapture_GStreamer::retrieveFrame(int)
+ {
+     if(!buffer)
+         return 0;
+ 
+-    if(!frame) {
++    //construct a frame header if we did not have any yet
++    if(!frame)
++    {
+         gint height, width;
+-        GstCaps *buff_caps = gst_buffer_get_caps(buffer);
+-        assert(gst_caps_get_size(buff_caps) == 1);
+-        GstStructure* structure = gst_caps_get_structure(buff_caps, 0);
+ 
++        //reuse the caps ptr
++        if (buffer_caps)
++            gst_caps_unref(buffer_caps);
++
++#if GST_VERSION_MAJOR == 0
++        buffer_caps = gst_buffer_get_caps(buffer);
++#else
++        buffer_caps = gst_sample_get_caps(sample);
++#endif
++        // bail out in no caps
++        assert(gst_caps_get_size(buffer_caps) == 1);
++        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);
++
++        // bail out if width or height are 0
+         if(!gst_structure_get_int(structure, "width", &width) ||
+-           !gst_structure_get_int(structure, "height", &height))
++                !gst_structure_get_int(structure, "height", &height))
++        {
++            return 0;
++        }
++
++
++        int depth = 3;
++#if GST_VERSION_MAJOR > 0
++        depth = 0;
++        const gchar* name = gst_structure_get_name(structure);
++        const gchar* format = gst_structure_get_string(structure, "format");
++
++        if (!name || !format)
+             return 0;
+ 
+-        frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, 3);
+-        gst_caps_unref(buff_caps);
++        // we support 3 types of data:
++        //     video/x-raw, format=BGR   -> 8bit, 3 channels
++        //     video/x-raw, format=GRAY8 -> 8bit, 1 channel
++        //     video/x-bayer             -> 8bit, 1 channel
++        // bayer data is never decoded, the user is responsible for that
++        // everything is 8 bit, so we just test the caps for bit depth
++
++        if (strcasecmp(name, "video/x-raw") == 0)
++        {
++            if (strcasecmp(format, "BGR") == 0) {
++                depth = 3;
++            }
++            else if(strcasecmp(format, "GRAY8") == 0){
++                depth = 1;
++            }
++        }
++        else if (strcasecmp(name, "video/x-bayer") == 0)
++        {
++            depth = 1;
++        }
++#endif
++        if (depth > 0) {
++            frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, depth);
++        }else{
++            return 0;
++        }
+     }
+ 
+-    // no need to memcpy, just use gstreamer's buffer :-)
++    // gstreamer expects us to handle the memory at this point
++    // so we can just wrap the raw buffer and be done with it
++#if GST_VERSION_MAJOR == 0
+     frame->imageData = (char *)GST_BUFFER_DATA(buffer);
+-    //memcpy (frame->imageData, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE (buffer));
+-    //gst_buffer_unref(buffer);
+-    //buffer = 0;
++#else
++    // the data ptr in GstMapInfo is only valid throughout the mapifo objects life.
++    // TODO: check if reusing the mapinfo object is ok.
++
++    gboolean success = gst_buffer_map(buffer,info, (GstMapFlags)GST_MAP_READ);
++    if (!success){
++        //something weird went wrong here. abort. abort.
++        //fprintf(stderr,"GStreamer: unable to map buffer");
++        return 0;
++    }
++    frame->imageData = (char*)info->data;
++    gst_buffer_unmap(buffer,info);
++#endif
++
+     return frame;
+ }
+ 
+-void CvCapture_GStreamer::restartPipeline()
++
++/*!
++ * \brief CvCapture_GStreamer::isPipelinePlaying
++ * \return if the pipeline is currently playing.
++ */
++bool CvCapture_GStreamer::isPipelinePlaying()
++{
++    GstState current, pending;
++    GstClockTime timeout = 5*GST_SECOND;
++    if(!GST_IS_ELEMENT(pipeline)){
++        return false;
++    }
++
++    GstStateChangeReturn ret = gst_element_get_state(GST_ELEMENT(pipeline),&current, &pending, timeout);
++    if (!ret){
++        //fprintf(stderr, "GStreamer: unable to query pipeline state\n");
++        return false;
++    }
++
++    return current == GST_STATE_PLAYING;
++}
++
++/*!
++ * \brief CvCapture_GStreamer::startPipeline
++ * Start the pipeline by setting it to the playing state
++ */
++void CvCapture_GStreamer::startPipeline()
+ {
+-    CV_FUNCNAME("icvRestartPipeline");
++    CV_FUNCNAME("icvStartPipeline");
+ 
+     __BEGIN__;
+ 
+-    printf("restarting pipeline, going to ready\n");
+-
+-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY) ==
+-       GST_STATE_CHANGE_FAILURE) {
++    //fprintf(stderr, "relinked, pausing\n");
++    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) ==
++            GST_STATE_CHANGE_FAILURE) {
+         CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n");
++        gst_object_unref(pipeline);
+         return;
+     }
+ 
+-    printf("ready, relinking\n");
++    //printf("state now playing\n");
++    handleMessage(pipeline);
++    __END__;
++}
++
+ 
+-    gst_element_unlink(uridecodebin, color);
+-    printf("filtering with %s\n", gst_caps_to_string(caps));
+-    gst_element_link_filtered(uridecodebin, color, caps);
++/*!
++ * \brief CvCapture_GStreamer::stopPipeline
++ * Stop the pipeline by setting it to NULL
++ */
++void CvCapture_GStreamer::stopPipeline()
++{
++    CV_FUNCNAME("icvStopPipeline");
+ 
+-    printf("relinked, pausing\n");
++    __BEGIN__;
+ 
+-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) ==
+-       GST_STATE_CHANGE_FAILURE) {
+-        CV_ERROR(CV_StsError, "GStreamer: unable to start pipeline\n");
++    //fprintf(stderr, "restarting pipeline, going to ready\n");
++    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL) ==
++            GST_STATE_CHANGE_FAILURE) {
++        CV_ERROR(CV_StsError, "GStreamer: unable to stop pipeline\n");
++        gst_object_unref(pipeline);
+         return;
+     }
++    __END__;
++}
+ 
+-    printf("state now paused\n");
++/*!
++ * \brief CvCapture_GStreamer::restartPipeline
++ * Restart the pipeline
++ */
++void CvCapture_GStreamer::restartPipeline()
++{
++    handleMessage(pipeline);
+ 
+-     __END__;
++    this->stopPipeline();
++    this->startPipeline();
+ }
+ 
+-void CvCapture_GStreamer::setFilter(const char *property, int type, int v1, int v2)
+-{
+ 
+-    if(!caps) {
+-        if(type == G_TYPE_INT)
+-            caps = gst_caps_new_simple("video/x-raw-rgb", property, type, v1, NULL);
+-        else
+-            caps = gst_caps_new_simple("video/x-raw-rgb", property, type, v1, v2, NULL);
+-    } else {
+-        //printf("caps before setting %s\n", gst_caps_to_string(caps));
++/*!
++ * \brief CvCapture_GStreamer::setFilter
++ * \param prop the property name
++ * \param type glib property type
++ * \param v1 the value
++ * \param v2 second value of property type requires it, else NULL
++ * Filter the output formats by setting appsink caps properties
++ */
++void CvCapture_GStreamer::setFilter(const char *prop, int type, int v1, int v2)
++{
++    //printf("GStreamer: setFilter \n");
++    if(!caps || !( GST_IS_CAPS (caps) ))
++    {
+         if(type == G_TYPE_INT)
+-            gst_caps_set_simple(caps, "video/x-raw-rgb", property, type, v1, NULL);
++        {
++#if GST_VERSION_MAJOR == 0
++            caps = gst_caps_new_simple("video/x-raw-rgb", prop, type, v1, NULL);
++#else
++            caps = gst_caps_new_simple("video/x-raw","format",G_TYPE_STRING,"BGR", prop, type, v1, NULL);
++#endif
++        }
+         else
+-            gst_caps_set_simple(caps, "video/x-raw-rgb", property, type, v1, v2, NULL);
++        {
++#if GST_VERSION_MAJOR == 0
++            caps = gst_caps_new_simple("video/x-raw-rgb", prop, type, v1, v2, NULL);
++#else
++            caps = gst_caps_new_simple("video/x-raw","format",G_TYPE_STRING,"BGR", prop, type, v1, v2, NULL);
++#endif
++        }
++    }
++    else
++    {
++#if GST_VERSION_MAJOR > 0
++        if (! gst_caps_is_writable(caps))
++            caps = gst_caps_make_writable (caps);
++#endif
++        if(type == G_TYPE_INT){
++            gst_caps_set_simple(caps, prop, type, v1, NULL);
++        }else{
++            gst_caps_set_simple(caps, prop, type, v1, v2, NULL);
++        }
+     }
+ 
+-    restartPipeline();
++#if GST_VERSION_MAJOR > 0
++    caps = gst_caps_fixate(caps);
++#endif
++
++    gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
++    //printf("filtering with %s\n", gst_caps_to_string(caps));
+ }
+ 
++
++/*!
++ * \brief CvCapture_GStreamer::removeFilter
++ * \param filter filter to remove
++ * remove the specified filter from the appsink template caps
++ */
+ void CvCapture_GStreamer::removeFilter(const char *filter)
+ {
+     if(!caps)
+         return;
+ 
++#if GST_VERSION_MAJOR > 0
++    if (! gst_caps_is_writable(caps))
++        caps = gst_caps_make_writable (caps);
++#endif
++
+     GstStructure *s = gst_caps_get_structure(caps, 0);
+     gst_structure_remove_field(s, filter);
+ 
+-    restartPipeline();
++    gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
+ }
+ 
+-
+-//
+-// connect uridecodebin dynamically created source pads to colourconverter
+-//
+-void CvCapture_GStreamer::newPad(GstElement * /*uridecodebin*/,
+-                             GstPad     *pad,
+-                             gpointer    data)
++/*!
++ * \brief CvCapture_GStreamer::newPad link dynamic padd
++ * \param pad
++ * \param data
++ * decodebin creates pads based on stream information, which is not known upfront
++ * on receiving the pad-added signal, we connect it to the colorspace conversion element
++ */
++void CvCapture_GStreamer::newPad(GstElement * /*elem*/,
++                                 GstPad     *pad,
++                                 gpointer    data)
+ {
+     GstPad *sinkpad;
+     GstElement *color = (GstElement *) data;
+ 
+-
+     sinkpad = gst_element_get_static_pad (color, "sink");
+-
+-//  printf("linking dynamic pad to colourconverter %p %p\n", uridecodebin, pad);
++    if (!sinkpad){
++        //fprintf(stderr, "Gstreamer: no pad named sink\n");
++        return;
++    }
+ 
+     gst_pad_link (pad, sinkpad);
+-
+     gst_object_unref (sinkpad);
+ }
+ 
++/*!
++ * \brief CvCapture_GStreamer::open Open the given file with gstreamer
++ * \param type CvCapture type. One of CV_CAP_GSTREAMER_*
++ * \param filename Filename to open in case of CV_CAP_GSTREAMER_FILE
++ * \return boolean. Specifies if opening was succesful.
++ *
++ * In case of CV_CAP_GSTREAMER_V4L(2), a pipelin is constructed as follows:
++ *    v4l2src ! autoconvert ! appsink
++ *
++ *
++ * The 'filename' parameter is not limited to filesystem paths, and may be one of the following:
++ *
++ *  - a normal filesystem path:
++ *        e.g. video.avi or /path/to/video.avi or C:\\video.avi
++ *  - an uri:
++ *        e.g. file:///path/to/video.avi or rtsp:///path/to/stream.asf
++ *  - a gstreamer pipeline description:
++ *        e.g. videotestsrc ! videoconvert ! appsink
++ *        the appsink name should be either 'appsink0' (the default) or 'opencvsink'
++ *
++ *  When dealing with a file, CvCapture_GStreamer will not drop frames if the grabbing interval
++ *  larger than the framerate period. (Unlike the uri or manual pipeline description, which assume
++ *  a live source)
++ *
++ *  The pipeline will only be started whenever the first frame is grabbed. Setting pipeline properties
++ *  is really slow if we need to restart the pipeline over and over again.
++ *
++ *  TODO: the 'type' parameter is imo unneeded. for v4l2, filename 'v4l2:///dev/video0' can be used.
++ *  I expect this to be the same for CV_CAP_GSTREAMER_1394. Is anyone actually still using v4l (v1)?
++ *
++ */
+ bool CvCapture_GStreamer::open( int type, const char* filename )
+ {
+-    close();
+     CV_FUNCNAME("cvCaptureFromCAM_GStreamer");
+ 
+     __BEGIN__;
+ 
+     gst_initializer::init();
+ 
+-//    if(!isInited) {
+-//        printf("gst_init\n");
+-//        gst_init (NULL, NULL);
+-
+-//        gst_debug_set_active(TRUE);
+-//        gst_debug_set_colored(TRUE);
+-//        gst_debug_set_default_threshold(GST_LEVEL_WARNING);
+-
+-//        isInited = true;
+-//    }
+     bool stream = false;
+     bool manualpipeline = false;
+     char *uri = NULL;
+     uridecodebin = NULL;
+-    if(type != CV_CAP_GSTREAMER_FILE) {
+-        close();
+-        return false;
++    GstElementFactory * testfac;
++
++    if (type == CV_CAP_GSTREAMER_V4L){
++        testfac = gst_element_factory_find("v4lsrc");
++        if (!testfac){
++            return false;
++        }
++        g_object_unref(G_OBJECT(testfac));
++        filename = "v4lsrc ! "COLOR_ELEM" ! appsink";
+     }
++    if (type == CV_CAP_GSTREAMER_V4L2){
++        testfac = gst_element_factory_find("v4l2src");
++        if (!testfac){
++            return false;
++        }
++        g_object_unref(G_OBJECT(testfac));
++        filename = "v4l2src ! "COLOR_ELEM" ! appsink";
++    }
++
+ 
+-    if(!gst_uri_is_valid(filename)) {
++    // test if we have a valid uri. If so, open it with an uridecodebin
++    // else, we might have a file or a manual pipeline.
++    // if gstreamer cannot parse the manual pipeline, we assume we were given and
++    // ordinary file path.
++    if(!gst_uri_is_valid(filename))
++    {
+         uri = realpath(filename, NULL);
+-        stream=false;
+-        if(uri) {
++        stream = false;
++        if(uri)
++        {
+             uri = g_filename_to_uri(uri, NULL, NULL);
+             if(!uri) {
+                 CV_WARN("GStreamer: Error opening file\n");
+                 close();
+                 return false;
+             }
+-        } else {
++        }
++        else
++        {
+             GError *err = NULL;
+-            //uridecodebin = gst_parse_bin_from_description(filename, FALSE, &err);
+             uridecodebin = gst_parse_launch(filename, &err);
+             if(!uridecodebin) {
+-                CV_WARN("GStreamer: Error opening bin\n");
+-                close();
++                //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message);
++                //close();
+                 return false;
+             }
+             stream = true;
+@@ -363,32 +613,75 @@ bool CvCapture_GStreamer::open( int type
+         uri = g_strdup(filename);
+     }
+ 
+-    if(!uridecodebin) {
+-        uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
+-        g_object_set(G_OBJECT(uridecodebin),"uri",uri, NULL);
++    bool element_from_uri = false;
++    if(!uridecodebin)
++    {
++        // At this writing, the v4l2 element (and maybe others too) does not support caps renegotiation.
++        // This means that we cannot use an uridecodebin when dealing with v4l2, since setting
++        // capture properties will not work.
++        // The solution (probably only until gstreamer 1.2) is to make an element from uri when dealing with v4l2.
++        gchar * protocol = gst_uri_get_protocol(uri);
++        if (!strcasecmp(protocol , "v4l2"))
++        {
++#if GST_VERSION_MAJOR == 0
++            uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src");
++#else
++            uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src", NULL);
++#endif
++            element_from_uri = true;
++        }else{
++            uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
++            g_object_set(G_OBJECT(uridecodebin),"uri",uri, NULL);
++        }
++        g_free(protocol);
++
+         if(!uridecodebin) {
+-            CV_WARN("GStreamer: Failed to create uridecodebin\n");
++            //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message);
+             close();
+             return false;
+         }
+     }
+ 
+-    if(manualpipeline) {
++    if(manualpipeline)
++    {
++#if GST_VERSION_MAJOR == 0
+         GstIterator *it = gst_bin_iterate_sinks(GST_BIN(uridecodebin));
+         if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) {
+-        CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
+-        return false;
++            CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
++            return false;
++        }
++#else
++        sink = gst_bin_get_by_name(GST_BIN(uridecodebin), "opencvsink");
++        if (!sink){
++            sink = gst_bin_get_by_name(GST_BIN(uridecodebin), "appsink0");
+         }
+ 
+-    pipeline = uridecodebin;
+-    } else {
+-    pipeline = gst_pipeline_new (NULL);
+-
+-        color = gst_element_factory_make("ffmpegcolorspace", NULL);
++        if (!sink){
++            CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
++            return false;
++        }
++#endif
++        pipeline = uridecodebin;
++    }
++    else
++    {
++        pipeline = gst_pipeline_new (NULL);
++        // videoconvert (in 0.10: ffmpegcolorspace) automatically selects the correct colorspace
++        // conversion based on caps.
++        color = gst_element_factory_make(COLOR_ELEM, NULL);
+         sink = gst_element_factory_make("appsink", NULL);
+ 
+         gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL);
+-        g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color);
++
++        if(element_from_uri) {
++            if(!gst_element_link(uridecodebin, color)) {
++                CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n");
++                gst_object_unref(pipeline);
++                return false;
++            }
++        }else{
++            g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color);
++        }
+ 
+         if(!gst_element_link(color, sink)) {
+             CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n");
+@@ -397,266 +690,131 @@ bool CvCapture_GStreamer::open( int type
+         }
+     }
+ 
++    //TODO: is 1 single buffer really high enough?
+     gst_app_sink_set_max_buffers (GST_APP_SINK(sink), 1);
+     gst_app_sink_set_drop (GST_APP_SINK(sink), stream);
++    //do not emit signals: all calls will be synchronous and blocking
++    gst_app_sink_set_emit_signals (GST_APP_SINK(sink), FALSE);
++
++#if GST_VERSION_MAJOR == 0
+     caps = gst_caps_new_simple("video/x-raw-rgb",
+                                "red_mask",   G_TYPE_INT, 0x0000FF,
+                                "green_mask", G_TYPE_INT, 0x00FF00,
+                                "blue_mask",  G_TYPE_INT, 0xFF0000,
+                                NULL);
++#else
++    // support 1 and 3 channel 8 bit data, as well as bayer (also  1 channel, 8bit)
++    caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}");
++#endif
+     gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
+     gst_caps_unref(caps);
+ 
+-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_READY) ==
+-       GST_STATE_CHANGE_FAILURE) {
+-        CV_WARN("GStreamer: unable to set pipeline to ready\n");
+-        gst_object_unref(pipeline);
+-        return false;
+-    }
+-
+-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) ==
+-       GST_STATE_CHANGE_FAILURE) {
+-        gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
+-        CV_WARN("GStreamer: unable to set pipeline to playing\n");
+-        gst_object_unref(pipeline);
+-        return false;
+-    }
+-
+-
+-
+-    handleMessage();
+-
++    //we do not start recording here just yet.
++    // the user probably wants to set capture properties first, so start recording whenever the first frame is requested
+     __END__;
+ 
+     return true;
+ }
+ 
+-//
+-//
+-// gstreamer image sequence writer
+-//
+-//
+-class CvVideoWriter_GStreamer : public CvVideoWriter
++/*!
++ * \brief CvCapture_GStreamer::getProperty retreive the requested property from the pipeline
++ * \param propId requested property
++ * \return property value
++ *
++ * There are two ways the properties can be retreived. For seek-based properties we can query the pipeline.
++ * For frame-based properties, we use the caps of the lasst receivef sample. This means that some properties
++ * are not available until a first frame was received
++ */
++double CvCapture_GStreamer::getProperty( int propId )
+ {
+-public:
+-    CvVideoWriter_GStreamer() { init(); }
+-    virtual ~CvVideoWriter_GStreamer() { close(); }
++    GstFormat format;
++    gint64 value;
++    gboolean status;
+ 
+-    virtual bool open( const char* filename, int fourcc,
+-                       double fps, CvSize frameSize, bool isColor );
+-    virtual void close();
+-    virtual bool writeFrame( const IplImage* image );
+-protected:
+-    void init();
+-    std::map<int, char*> encs;
+-    GstElement* source;
+-    GstElement* file;
+-    GstElement* enc;
+-    GstElement* mux;
+-    GstElement* color;
+-    GstBuffer* buffer;
+-    GstElement* pipeline;
+-    int input_pix_fmt;
+-};
++#if GST_VERSION_MAJOR == 0
++#define FORMAT &format
++#else
++#define FORMAT format
++#endif
+ 
+-void CvVideoWriter_GStreamer::init()
+-{
+-    encs[CV_FOURCC('D','R','A','C')]=(char*)"diracenc";
+-    encs[CV_FOURCC('H','F','Y','U')]=(char*)"ffenc_huffyuv";
+-    encs[CV_FOURCC('J','P','E','G')]=(char*)"jpegenc";
+-    encs[CV_FOURCC('M','J','P','G')]=(char*)"jpegenc";
+-    encs[CV_FOURCC('M','P','1','V')]=(char*)"mpeg2enc";
+-    encs[CV_FOURCC('M','P','2','V')]=(char*)"mpeg2enc";
+-    encs[CV_FOURCC('T','H','E','O')]=(char*)"theoraenc";
+-    encs[CV_FOURCC('V','P','8','0')]=(char*)"vp8enc";
+-    encs[CV_FOURCC('H','2','6','4')]=(char*)"x264enc";
+-    encs[CV_FOURCC('X','2','6','4')]=(char*)"x264enc";
+-    encs[CV_FOURCC('X','V','I','D')]=(char*)"xvidenc";
+-    encs[CV_FOURCC('F','F','Y','U')]=(char*)"y4menc";
+-    //encs[CV_FOURCC('H','F','Y','U')]=(char*)"y4menc";
+-    pipeline=0;
+-    buffer=0;
+-}
+-void CvVideoWriter_GStreamer::close()
+-{
+-    if (pipeline) {
+-        gst_app_src_end_of_stream(GST_APP_SRC(source));
+-        gst_element_set_state (pipeline, GST_STATE_NULL);
+-        gst_object_unref (GST_OBJECT (pipeline));
++    if(!pipeline) {
++        CV_WARN("GStreamer: no pipeline");
++        return false;
+     }
+-}
+-bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+-        double fps, CvSize frameSize, bool is_color )
+-{
+-    CV_FUNCNAME("CvVideoWriter_GStreamer::open");
+-
+-    __BEGIN__;
+-    //actually doesn't support fourcc parameter and encode an avi with jpegenc
+-    //we need to find a common api between backend to support fourcc for avi
+-    //but also to choose in a common way codec and container format (ogg,dirac,matroska)
+-    // check arguments
+ 
+-    assert (filename);
+-    assert (fps > 0);
+-    assert (frameSize.width > 0  &&  frameSize.height > 0);
+-    std::map<int,char*>::iterator encit;
+-    encit=encs.find(fourcc);
+-    if (encit==encs.end())
+-        CV_ERROR( CV_StsUnsupportedFormat,"Gstreamer Opencv backend doesn't support this codec acutally.");
+-//    if(!isInited) {
+-//        gst_init (NULL, NULL);
+-//        isInited = true;
+-//    }
+-    gst_initializer::init();
+-    close();
+-    source=gst_element_factory_make("appsrc",NULL);
+-    file=gst_element_factory_make("filesink", NULL);
+-    enc=gst_element_factory_make(encit->second, NULL);
+-    mux=gst_element_factory_make("avimux", NULL);
+-    color = gst_element_factory_make("ffmpegcolorspace", NULL);
+-    if (!enc)
+-        CV_ERROR( CV_StsUnsupportedFormat, "Your version of Gstreamer doesn't support this codec acutally or needed plugin missing.");
+-    g_object_set(G_OBJECT(file), "location", filename, NULL);
+-    pipeline = gst_pipeline_new (NULL);
+-    GstCaps* caps;
+-    if (is_color) {
+-        input_pix_fmt=1;
+-        caps= gst_video_format_new_caps(GST_VIDEO_FORMAT_BGR,
+-                                        frameSize.width,
+-                                        frameSize.height,
+-                                        (int) (fps * 1000),
+-                                        1000,
+-                                        1,
+-                                        1);
+-    }
+-    else  {
+-        input_pix_fmt=0;
+-        caps= gst_caps_new_simple("video/x-raw-gray",
+-                                  "width", G_TYPE_INT, frameSize.width,
+-                                  "height", G_TYPE_INT, frameSize.height,
+-                                  "framerate", GST_TYPE_FRACTION, int(fps),1,
+-                                  "bpp",G_TYPE_INT,8,
+-                                  "depth",G_TYPE_INT,8,
+-                                  NULL);
+-    }
+-    gst_app_src_set_caps(GST_APP_SRC(source), caps);
+-    if (fourcc==CV_FOURCC_DEFAULT) {
+-        gst_bin_add_many(GST_BIN(pipeline), source, color,mux, file, NULL);
+-        if(!gst_element_link_many(source,color,enc,mux,file,NULL)) {
+-            CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n");
+-        }
+-    }
+-    else {
+-        gst_bin_add_many(GST_BIN(pipeline), source, color,enc,mux, file, NULL);
+-        if(!gst_element_link_many(source,color,enc,mux,file,NULL)) {
+-            CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n");
+-        }
+-    }
+-
+-
+-    if(gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING) ==
+-        GST_STATE_CHANGE_FAILURE) {
+-            CV_ERROR(CV_StsError, "GStreamer: cannot put pipeline to play\n");
+-    }
+-    __END__;
+-    return true;
+-}
+-bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
+-{
+-
+-    CV_FUNCNAME("CvVideoWriter_GStreamer::writerFrame");
+-
+-    __BEGIN__;
+-    if (input_pix_fmt == 1) {
+-        if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) {
+-            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
+-        }
+-    }
+-    else if (input_pix_fmt == 0) {
+-        if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) {
+-            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1.");
+-        }
+-    }
+-    else {
+-        assert(false);
+-    }
+-    int size;
+-    size = image->imageSize;
+-    buffer = gst_buffer_new_and_alloc (size);
+-    //gst_buffer_set_data (buffer,(guint8*)image->imageData, size);
+-    memcpy (GST_BUFFER_DATA(buffer),image->imageData, size);
+-    gst_app_src_push_buffer(GST_APP_SRC(source),buffer);
+-    //gst_buffer_unref(buffer);
+-    //buffer = 0;
+-    __END__;
+-    return true;
+-}
+-CvVideoWriter* cvCreateVideoWriter_GStreamer(const char* filename, int fourcc, double fps,
+-                                           CvSize frameSize, int isColor )
+-{
+-    CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer;
+-    if( wrt->open(filename, fourcc, fps,frameSize, isColor))
+-        return wrt;
+-
+-    delete wrt;
+-    return 0;
+-}
+-
+-void CvCapture_GStreamer::close()
+-{
+-    if(pipeline) {
+-        gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
+-        gst_object_unref(GST_OBJECT(pipeline));
+-    }
+-    if(buffer)
+-        gst_buffer_unref(buffer);
+-    if(frame) {
+-        frame->imageData = 0;
+-        cvReleaseImage(&frame);
+-    }
+-}
+-
+-double CvCapture_GStreamer::getProperty( int propId )
+-{
+-    GstFormat format;
+-    //GstQuery q;
+-    gint64 value;
+-
+-    if(!pipeline) {
+-        CV_WARN("GStreamer: no pipeline");
+-        return false;
+-    }
+-
+-    switch(propId) {
+-    case CV_CAP_PROP_POS_MSEC:
+-        format = GST_FORMAT_TIME;
+-        if(!gst_element_query_position(sink, &format, &value)) {
+-            CV_WARN("GStreamer: unable to query position of stream");
+-            return false;
++    switch(propId) {
++    case CV_CAP_PROP_POS_MSEC:
++        format = GST_FORMAT_TIME;
++        status = gst_element_query_position(sink, FORMAT, &value);
++        if(!status) {
++            CV_WARN("GStreamer: unable to query position of stream");
++            return false;
+         }
+         return value * 1e-6; // nano seconds to milli seconds
+     case CV_CAP_PROP_POS_FRAMES:
+         format = GST_FORMAT_DEFAULT;
+-        if(!gst_element_query_position(sink, &format, &value)) {
++        status = gst_element_query_position(sink, FORMAT, &value);
++        if(!status) {
+             CV_WARN("GStreamer: unable to query position of stream");
+             return false;
+         }
+         return value;
+     case CV_CAP_PROP_POS_AVI_RATIO:
+         format = GST_FORMAT_PERCENT;
+-        if(!gst_element_query_position(pipeline, &format, &value)) {
++        status = gst_element_query_position(sink, FORMAT, &value);
++        if(!status) {
+             CV_WARN("GStreamer: unable to query position of stream");
+             return false;
+         }
+         return ((double) value) / GST_FORMAT_PERCENT_MAX;
+-    case CV_CAP_PROP_FRAME_WIDTH:
+-    case CV_CAP_PROP_FRAME_HEIGHT:
+-    case CV_CAP_PROP_FPS:
++    case CV_CAP_PROP_FRAME_WIDTH: {
++        if (!buffer_caps){
++            CV_WARN("GStreamer: unable to query width of frame; no frame grabbed yet");
++            return 0;
++        }
++        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);
++        gint width = 0;
++        if(!gst_structure_get_int(structure, "width", &width)){
++            CV_WARN("GStreamer: unable to query width of frame");
++            return 0;
++        }
++        return width;
++        break;
++    }
++    case CV_CAP_PROP_FRAME_HEIGHT: {
++        if (!buffer_caps){
++            CV_WARN("GStreamer: unable to query height of frame; no frame grabbed yet");
++            return 0;
++        }
++        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);
++        gint height = 0;
++        if(!gst_structure_get_int(structure, "height", &height)){
++            CV_WARN("GStreamer: unable to query height of frame");
++            return 0;
++        }
++        return height;
++        break;
++    }
++    case CV_CAP_PROP_FPS: {
++        if (!buffer_caps){
++            CV_WARN("GStreamer: unable to query framerate of stream; no frame grabbed yet");
++            return 0;
++        }
++        GstStructure* structure = gst_caps_get_structure(buffer_caps, 0);
++        gint num = 0, denom=1;
++        if(!gst_structure_get_fraction(structure, "framerate", &num, &denom)){
++            CV_WARN("GStreamer: unable to query framerate of stream");
++            return 0;
++        }
++        return (double)num/(double)denom;
++        break;
++    }
+     case CV_CAP_PROP_FOURCC:
+         break;
+     case CV_CAP_PROP_FRAME_COUNT:
+         format = GST_FORMAT_DEFAULT;
+-        if(!gst_element_query_duration(pipeline, &format, &value)) {
++        status = gst_element_query_position(sink, FORMAT, &value);
++        if(!status) {
+             CV_WARN("GStreamer: unable to query position of stream");
+             return false;
+         }
+@@ -672,20 +830,31 @@ double CvCapture_GStreamer::getProperty(
+         break;
+     case CV_CAP_GSTREAMER_QUEUE_LENGTH:
+         if(!sink) {
+-                CV_WARN("GStreamer: there is no sink yet");
+-                return false;
++            CV_WARN("GStreamer: there is no sink yet");
++            return false;
+         }
+         return gst_app_sink_get_max_buffers(GST_APP_SINK(sink));
+     default:
+         CV_WARN("GStreamer: unhandled property");
+         break;
+     }
++
++#undef FORMAT
++
+     return false;
+ }
+ 
++/*!
++ * \brief CvCapture_GStreamer::setProperty
++ * \param propId
++ * \param value
++ * \return success
++ * Sets the desired property id with val. If the pipeline is running,
++ * it is briefly stopped and started again after the property was set
++ */
+ bool CvCapture_GStreamer::setProperty( int propId, double value )
+ {
+-       GstFormat format;
++    GstFormat format;
+     GstSeekFlags flags;
+ 
+     if(!pipeline) {
+@@ -693,12 +862,17 @@ bool CvCapture_GStreamer::setProperty( i
+         return false;
+     }
+ 
++    bool wasPlaying = this->isPipelinePlaying();
++    if (wasPlaying)
++        this->stopPipeline();
++
++
+     switch(propId) {
+     case CV_CAP_PROP_POS_MSEC:
+         format = GST_FORMAT_TIME;
+         flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
+         if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
+-                        flags, (gint64) (value * GST_MSECOND))) {
++                                    flags, (gint64) (value * GST_MSECOND))) {
+             CV_WARN("GStreamer: unable to seek");
+         }
+         break;
+@@ -706,7 +880,7 @@ bool CvCapture_GStreamer::setProperty( i
+         format = GST_FORMAT_DEFAULT;
+         flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
+         if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
+-                        flags, (gint64) value)) {
++                                    flags, (gint64) value)) {
+             CV_WARN("GStreamer: unable to seek");
+         }
+         break;
+@@ -714,7 +888,7 @@ bool CvCapture_GStreamer::setProperty( i
+         format = GST_FORMAT_PERCENT;
+         flags = (GstSeekFlags) (GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE);
+         if(!gst_element_seek_simple(GST_ELEMENT(pipeline), format,
+-                        flags, (gint64) (value * GST_FORMAT_PERCENT_MAX))) {
++                                    flags, (gint64) (value * GST_FORMAT_PERCENT_MAX))) {
+             CV_WARN("GStreamer: unable to seek");
+         }
+         break;
+@@ -732,15 +906,9 @@ bool CvCapture_GStreamer::setProperty( i
+         break;
+     case CV_CAP_PROP_FPS:
+         if(value > 0) {
+-            int num, denom;
+-            num = (int) value;
+-            if(value != num) { // FIXME this supports only fractions x/1 and x/2
+-                num = (int) (value * 2);
+-                denom = 2;
+-            } else
+-                denom = 1;
+-
+-            setFilter("framerate", GST_TYPE_FRACTION, num, denom);
++            double num=0, denom = 1;
++            toFraction(value, num,  denom);
++            setFilter("framerate", GST_TYPE_FRACTION, value, denom);
+         } else
+             removeFilter("framerate");
+         break;
+@@ -763,8 +931,19 @@ bool CvCapture_GStreamer::setProperty( i
+     default:
+         CV_WARN("GStreamer: unhandled property");
+     }
++
++    if (wasPlaying)
++        this->startPipeline();
++
+     return false;
+ }
++
++/*!
++ * \brief cvCreateCapture_GStreamer
++ * \param type
++ * \param filename
++ * \return
++ */
+ CvCapture* cvCreateCapture_GStreamer(int type, const char* filename )
+ {
+     CvCapture_GStreamer* capture = new CvCapture_GStreamer;
+@@ -775,3 +954,498 @@ CvCapture* cvCreateCapture_GStreamer(int
+     delete capture;
+     return 0;
+ }
++
++
++/*!
++ * \brief The CvVideoWriter_GStreamer class
++ * Use Gstreamer to write video
++ */
++class CvVideoWriter_GStreamer : public CvVideoWriter
++{
++public:
++    CvVideoWriter_GStreamer() { init(); }
++    virtual ~CvVideoWriter_GStreamer() { close(); }
++
++    virtual bool open( const char* filename, int fourcc,
++                       double fps, CvSize frameSize, bool isColor );
++    virtual void close();
++    virtual bool writeFrame( const IplImage* image );
++protected:
++    void init();
++    const char* filenameToMimetype(const char* filename);
++    GstElement* pipeline;
++    GstElement* source;
++    GstElement* encodebin;
++    GstElement* file;
++
++    GstBuffer* buffer;
++    int input_pix_fmt;
++    int num_frames;
++    double framerate;
++};
++
++/*!
++ * \brief CvVideoWriter_GStreamer::init
++ * initialise all variables
++ */
++void CvVideoWriter_GStreamer::init()
++{
++    pipeline = NULL;
++    source = NULL;
++    encodebin = NULL;
++    file = NULL;
++    buffer = NULL;
++
++    num_frames = 0;
++    framerate = 0;
++}
++
++/*!
++ * \brief CvVideoWriter_GStreamer::close
++ * ends the pipeline by sending EOS and destroys the pipeline and all
++ * elements afterwards
++ */
++void CvVideoWriter_GStreamer::close()
++{
++    if (pipeline) {
++        GstFlowReturn ret;
++        ret = gst_app_src_end_of_stream(GST_APP_SRC(source));
++
++        //wait for EOS to trickle down the pipeline. This will let all elements finish properly
++        GstBus* bus = gst_element_get_bus(pipeline);
++        GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
++        if(msg != NULL){
++            gst_message_unref(msg);
++            g_object_unref(G_OBJECT(bus));
++        }
++
++        gst_element_set_state (pipeline, GST_STATE_NULL);
++        handleMessage(pipeline);
++
++        gst_object_unref (GST_OBJECT (pipeline));
++    }
++}
++
++
++/*!
++ * \brief CvVideoWriter_GStreamer::filenameToMimetype
++ * \param filename
++ * \return mimetype
++ * Resturns a container mime type for a given filename by looking at it's extension
++ */
++const char* CvVideoWriter_GStreamer::filenameToMimetype(const char *filename)
++{
++    //get extension
++    const char *ext = strrchr(filename, '.');
++    if(!ext || ext == filename) return NULL;
++    ext += 1; //exclude the dot
++
++    // return a container mime based on the given extension.
++    // gstreamer's function returns too much possibilities, which is not useful to us
++
++    //return the appropriate mime
++    if (strncasecmp(ext,"avi", 3) == 0)
++        return (const char*)"video/x-msvideo";
++
++    if (strncasecmp(ext,"mkv", 3) == 0 || strncasecmp(ext,"mk3d",4) == 0  || strncasecmp(ext,"webm",4) == 0 )
++        return (const char*)"video/x-matroska";
++
++    if (strncasecmp(ext,"wmv", 3) == 0)
++        return (const char*)"video/x-ms-asf";
++
++    if (strncasecmp(ext,"mov", 3) == 0)
++        return (const char*)"video/x-quicktime";
++
++    if (strncasecmp(ext,"ogg", 3) == 0 || strncasecmp(ext,"ogv", 3) == 0)
++        return (const char*)"application/ogg";
++
++    if (strncasecmp(ext,"rm", 3) == 0)
++        return (const char*)"vnd.rn-realmedia";
++
++    if (strncasecmp(ext,"swf", 3) == 0)
++        return (const char*)"application/x-shockwave-flash";
++
++    if (strncasecmp(ext,"mp4", 3) == 0)
++        return (const char*)"video/x-quicktime, variant=(string)iso";
++
++    //default to avi
++    return (const char*)"video/x-msvideo";
++}
++
++
++/*!
++ * \brief CvVideoWriter_GStreamer::open
++ * \param filename filename to output to
++ * \param fourcc desired codec fourcc
++ * \param fps desired framerate
++ * \param frameSize the size of the expected frames
++ * \param is_color color or grayscale
++ * \return success
++ *
++ * We support 2 modes of operation. Either the user enters a filename and a fourcc
++ * code, or enters a manual pipeline description like in CvVideoCapture_Gstreamer.
++ * In the latter case, we just push frames on the appsink with appropriate caps.
++ * In the former case, we try to deduce the correct container from the filename,
++ * and the correct encoder from the fourcc profile.
++ *
++ * If the file extension did was not recognize, an avi container is used
++ *
++ */
++bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
++                                    double fps, CvSize frameSize, bool is_color )
++{
++    CV_FUNCNAME("CvVideoWriter_GStreamer::open");
++
++    // check arguments
++    assert (filename);
++    assert (fps > 0);
++    assert (frameSize.width > 0  &&  frameSize.height > 0);
++
++    // init gstreamer
++    gst_initializer::init();
++
++    // init vars
++    bool manualpipeline = true;
++    int  bufsize = 0;
++    GError *err = NULL;
++    const char* mime = NULL;
++    GstStateChangeReturn stateret;
++
++    GstCaps* caps = NULL;
++    GstCaps* videocaps = NULL;
++    GstCaps* containercaps = NULL;
++    GstEncodingContainerProfile* containerprofile = NULL;
++    GstEncodingVideoProfile* videoprofile = NULL;
++
++#if GST_VERSION_MAJOR == 0
++    GstIterator *it = NULL;
++#endif
++
++    // we first try to construct a pipeline from the given string.
++    // if that fails, we assume it is an ordinary filename
++
++    __BEGIN__;
++
++    encodebin = gst_parse_launch(filename, &err);
++    if(!encodebin) {
++        manualpipeline = false;
++    }
++
++    if(manualpipeline)
++    {
++#if GST_VERSION_MAJOR == 0
++        it = gst_bin_iterate_sources(GST_BIN(encodebin));
++        if(gst_iterator_next(it, (gpointer *)&source) != GST_ITERATOR_OK) {
++            CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
++            return false;
++        }
++#else
++        source = gst_bin_get_by_name(GST_BIN(encodebin), "opencvsrc");
++        if (!source){
++            source = gst_bin_get_by_name(GST_BIN(encodebin), "appsrc0");
++        }
++
++        if (!source){
++            CV_ERROR(CV_StsError, "GStreamer: cannot find appsrc in manual pipeline\n");
++            return false;
++        }
++#endif
++        pipeline = encodebin;
++    }
++    else
++    {
++        pipeline = gst_pipeline_new (NULL);
++
++        // we just got a filename and a fourcc code.
++        // first, try to guess the container from the filename
++        //encodebin = gst_element_factory_make("encodebin", NULL);
++
++        //proxy old non existing fourcc ids. These were used in previous opencv versions,
++        //but do not even exist in gstreamer any more
++        if (fourcc == CV_FOURCC('M','P','1','V')) fourcc = CV_FOURCC('M', 'P', 'G' ,'1');
++        if (fourcc == CV_FOURCC('M','P','2','V')) fourcc = CV_FOURCC('M', 'P', 'G' ,'2');
++        if (fourcc == CV_FOURCC('D','R','A','C')) fourcc = CV_FOURCC('d', 'r', 'a' ,'c');
++
++        //create encoder caps from fourcc
++        videocaps = gst_riff_create_video_caps(fourcc, NULL, NULL, NULL, NULL, NULL);
++        if (!videocaps){
++            CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer Opencv backend does not support this codec.");
++        }
++
++        //create container caps from file extension
++        mime = filenameToMimetype(filename);
++        if (!mime) {
++            CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer Opencv backend does not support this file type.");
++        }
++        containercaps = gst_caps_from_string(mime);
++
++        //create encodebin profile
++        containerprofile = gst_encoding_container_profile_new("container", "container", containercaps, NULL);
++        videoprofile = gst_encoding_video_profile_new(videocaps, NULL, NULL, 1);
++        gst_encoding_container_profile_add_profile(containerprofile, (GstEncodingProfile *) videoprofile);
++
++        //create pipeline elements
++        encodebin = gst_element_factory_make("encodebin", NULL);
++        g_object_set(G_OBJECT(encodebin), "profile", containerprofile, NULL);
++        source = gst_element_factory_make("appsrc", NULL);
++        file = gst_element_factory_make("filesink", NULL);
++        g_object_set(G_OBJECT(file), "location", filename, NULL);
++    }
++
++    if (is_color)
++    {
++        input_pix_fmt = GST_VIDEO_FORMAT_BGR;
++        bufsize = frameSize.width * frameSize.height * 3;
++
++#if GST_VERSION_MAJOR == 0
++        caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_BGR,
++                                         frameSize.width,
++                                         frameSize.height,
++                                         int(fps), 1,
++                                         1, 1);
++#else
++        caps = gst_caps_new_simple("video/x-raw",
++                                   "format", G_TYPE_STRING, "BGR",
++                                   "width", G_TYPE_INT, frameSize.width,
++                                   "height", G_TYPE_INT, frameSize.height,
++                                   "framerate", GST_TYPE_FRACTION, int(fps), 1,
++                                   NULL);
++        caps = gst_caps_fixate(caps);
++
++#endif
++
++    }
++    else
++    {
++        input_pix_fmt = GST_VIDEO_FORMAT_GRAY8;
++        bufsize = frameSize.width * frameSize.height;
++
++#if GST_VERSION_MAJOR == 0
++        caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_GRAY8,
++                                         frameSize.width,
++                                         frameSize.height,
++                                         int(fps), 1,
++                                         1, 1);
++#else
++        caps = gst_caps_new_simple("video/x-raw",
++                                   "format", G_TYPE_STRING, "GRAY8",
++                                   "width", G_TYPE_INT, frameSize.width,
++                                   "height", G_TYPE_INT, frameSize.height,
++                                   "framerate", GST_TYPE_FRACTION, int(fps), 1,
++                                   NULL);
++        caps = gst_caps_fixate(caps);
++#endif
++    }
++
++    gst_app_src_set_caps(GST_APP_SRC(source), caps);
++    gst_app_src_set_stream_type(GST_APP_SRC(source), GST_APP_STREAM_TYPE_STREAM);
++    gst_app_src_set_size (GST_APP_SRC(source), -1);
++
++    g_object_set(G_OBJECT(source), "format", GST_FORMAT_TIME, NULL);
++    g_object_set(G_OBJECT(source), "block", TRUE, NULL);
++    g_object_set(G_OBJECT(source), "is-live", FALSE, NULL);
++    g_object_set(G_OBJECT(source), "emit-signals", TRUE, NULL);
++
++    if(!manualpipeline)
++    {
++        g_object_set(G_OBJECT(file), "buffer-size", bufsize, NULL);
++        gst_bin_add_many(GST_BIN(pipeline), source, encodebin, file, NULL);
++        if(!gst_element_link_many(source, encodebin, file, NULL)) {
++            CV_ERROR(CV_StsError, "GStreamer: cannot link elements\n");
++        }
++    }
++
++    stateret = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
++    if(stateret  == GST_STATE_CHANGE_FAILURE) {
++        CV_ERROR(CV_StsError, "GStreamer: cannot put pipeline to play\n");
++    }
++    handleMessage(pipeline);
++
++    framerate = fps;
++    num_frames = 0;
++
++    __END__;
++
++    return true;
++}
++
++
++/*!
++ * \brief CvVideoWriter_GStreamer::writeFrame
++ * \param image
++ * \return
++ * Pushes the given frame on the pipeline.
++ * The timestamp for the buffer is generated from the framerate set in open
++ * and ensures a smooth video
++ */
++bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
++{
++
++    CV_FUNCNAME("CvVideoWriter_GStreamer::writerFrame");
++
++    GstClockTime duration, timestamp;
++    GstFlowReturn ret;
++    int size;
++
++    __BEGIN__;
++    handleMessage(pipeline);
++
++    if (input_pix_fmt == GST_VIDEO_FORMAT_BGR) {
++        if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) {
++            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
++        }
++    }
++    else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY8) {
++        if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) {
++            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1.");
++        }
++    }
++    else {
++        assert(false);
++    }
++
++    size = image->imageSize;
++    duration = ((double)1/framerate) * GST_SECOND;
++    timestamp = num_frames * duration;
++
++    //gst_app_src_push_buffer takes ownership of the buffer, so we need to supply it a copy
++#if GST_VERSION_MAJOR == 0
++    buffer = gst_buffer_new_and_alloc (size);
++    memcpy(GST_BUFFER_DATA (buffer), (guint8*)image->imageData, size);
++    GST_BUFFER_DURATION(buffer) = duration;
++    GST_BUFFER_TIMESTAMP(buffer) = timestamp;
++#else
++    buffer = gst_buffer_new_allocate (NULL, size, NULL);
++    GstMapInfo info;
++    gst_buffer_map(buffer, &info, (GstMapFlags)GST_MAP_READ);
++    memcpy(info.data, (guint8*)image->imageData, size);
++    gst_buffer_unmap(buffer, &info);
++    GST_BUFFER_DURATION(buffer) = duration;
++    GST_BUFFER_PTS(buffer) = timestamp;
++    GST_BUFFER_DTS(buffer) = timestamp;
++#endif
++    //set the current number in the frame
++    GST_BUFFER_OFFSET(buffer) =  num_frames;
++
++    ret = gst_app_src_push_buffer(GST_APP_SRC(source), buffer);
++    if (ret != GST_FLOW_OK) {
++        /* something wrong, stop pushing */
++        assert(false);
++    }
++    //gst_debug_bin_to_dot_file (GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");
++    ++num_frames;
++
++    __END__;
++    return true;
++}
++
++/*!
++ * \brief cvCreateVideoWriter_GStreamer
++ * \param filename
++ * \param fourcc
++ * \param fps
++ * \param frameSize
++ * \param isColor
++ * \return
++ * Constructor
++ */
++CvVideoWriter* cvCreateVideoWriter_GStreamer(const char* filename, int fourcc, double fps,
++                                             CvSize frameSize, int isColor )
++{
++    CvVideoWriter_GStreamer* wrt = new CvVideoWriter_GStreamer;
++    if( wrt->open(filename, fourcc, fps,frameSize, isColor))
++        return wrt;
++
++    delete wrt;
++    return 0;
++}
++
++// utility functions
++
++/*!
++ * \brief toFraction
++ * \param decimal
++ * \param numerator
++ * \param denominator
++ * Split a floating point value into numerator and denominator
++ */
++void toFraction(double decimal, double &numerator, double &denominator)
++{
++    double dummy;
++    double whole;
++    decimal = modf (decimal, &whole);
++    for (denominator = 1; denominator<=100; denominator++){
++        if (modf(denominator * decimal, &dummy) < 0.001f)
++            break;
++    }
++    numerator = denominator * decimal;
++}
++
++
++/*!
++ * \brief handleMessage
++ * Handles gstreamer bus messages. Mainly for debugging purposes and ensuring clean shutdown on error
++ */
++void handleMessage(GstElement * pipeline)
++{
++    CV_FUNCNAME("handlemessage");
++
++    GError *err = NULL;
++    gchar *debug = NULL;
++    GstBus* bus = NULL;
++    GstStreamStatusType tp;
++    GstElement * elem = NULL;
++    GstMessage* msg  = NULL;
++
++    __BEGIN__;
++    bus = gst_element_get_bus(pipeline);
++
++    while(gst_bus_have_pending(bus)) {
++        msg = gst_bus_pop(bus);
++
++        //printf("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg));
++
++        if(gst_is_missing_plugin_message(msg))
++        {
++            CV_ERROR(CV_StsError, "GStreamer: your gstreamer installation is missing a required plugin\n");
++        }
++        else
++        {
++            switch (GST_MESSAGE_TYPE (msg)) {
++            case GST_MESSAGE_STATE_CHANGED:
++                GstState oldstate, newstate, pendstate;
++                gst_message_parse_state_changed(msg, &oldstate, &newstate, &pendstate);
++                //fprintf(stderr, "state changed from %s to %s (pending: %s)\n", gst_element_state_get_name(oldstate),
++                //                gst_element_state_get_name(newstate), gst_element_state_get_name(pendstate));
++                break;
++            case GST_MESSAGE_ERROR:
++                gst_message_parse_error(msg, &err, &debug);
++
++                //fprintf(stderr, "GStreamer Plugin: Embedded video playback halted; module %s reported: %s\n",
++                //                gst_element_get_name(GST_MESSAGE_SRC (msg)), err->message);
++
++                g_error_free(err);
++                g_free(debug);
++
++                gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
++                break;
++            case GST_MESSAGE_EOS:
++                //fprintf(stderr, "reached the end of the stream.");
++                break;
++            case GST_MESSAGE_STREAM_STATUS:
++
++                gst_message_parse_stream_status(msg,&tp,&elem);
++                //fprintf(stderr, "stream status: elem %s, %i\n", GST_ELEMENT_NAME(elem), tp);
++                break;
++            default:
++                //fprintf(stderr, "unhandled message\n");
++                break;
++            }
++        }
++        gst_message_unref(msg);
++    }
++
++    gst_object_unref(GST_OBJECT(bus));
++
++    __END__
++}

diff --git a/0552-eliminated-warnings.patch b/0552-eliminated-warnings.patch
new file mode 100644
index 0000000..21097df
--- /dev/null
+++ b/0552-eliminated-warnings.patch
@@ -0,0 +1,39 @@
+From 921675c4e233d8f9e78786550d549e9e05ffeb2a Mon Sep 17 00:00:00 2001
+From: Dirk Van Haerenborgh <vhdirk@gmail.com>
+Date: Thu, 21 Mar 2013 16:11:53 +0100
+Subject: [PATCH 0552/3152] eliminated warnings
+
+---
+ modules/highgui/src/cap_gstreamer.cpp | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp
+index b1a2ca0..9ef0a3f 100644
+--- a/modules/highgui/src/cap_gstreamer.cpp
++++ b/modules/highgui/src/cap_gstreamer.cpp
+@@ -83,7 +83,8 @@ static cv::Mutex gst_initializer_mutex;
+ /*!
+  * \brief The gst_initializer class
+  * Initializes gstreamer once in the whole process
+- */class gst_initializer
++ */
++class gst_initializer
+ {
+ public:
+     static void init()
+@@ -1007,9 +1008,9 @@ void CvVideoWriter_GStreamer::init()
+  */
+ void CvVideoWriter_GStreamer::close()
+ {
+-    if (pipeline) {
+-        GstFlowReturn ret;
+-        ret = gst_app_src_end_of_stream(GST_APP_SRC(source));
++    if (pipeline)
++    {
++        gst_app_src_end_of_stream(GST_APP_SRC(source));
+ 
+         //wait for EOS to trickle down the pipeline. This will let all elements finish properly
+         GstBus* bus = gst_element_get_bus(pipeline);
+-- 
+1.9.3
+

diff --git a/0587-Fix-build-with-gstreamer-0.10.28.patch b/0587-Fix-build-with-gstreamer-0.10.28.patch
new file mode 100644
index 0000000..eb8d627
--- /dev/null
+++ b/0587-Fix-build-with-gstreamer-0.10.28.patch
@@ -0,0 +1,100 @@
+From 6377922716f37b00e4f8f5eab87a8fbcb16422e5 Mon Sep 17 00:00:00 2001
+From: Andrey Kamaev <andrey.kamaev@itseez.com>
+Date: Tue, 26 Mar 2013 12:27:39 +0400
+Subject: [PATCH 0587/3152] Fix build with gstreamer 0.10.28
+
+---
+ modules/highgui/src/cap_gstreamer.cpp | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp
+index 9ef0a3f..b8c7f4f 100644
+--- a/modules/highgui/src/cap_gstreamer.cpp
++++ b/modules/highgui/src/cap_gstreamer.cpp
+@@ -56,9 +56,15 @@
+ #include <gst/app/gstappsink.h>
+ #include <gst/app/gstappsrc.h>
+ #include <gst/riff/riff-media.h>
+-#include <gst/pbutils/encoding-profile.h>
+ #include <gst/pbutils/missing-plugins.h>
++
++#define VERSION_NUM(major, minor, micro) (major * 1000000 + minor * 1000 + micro)
++#define FULL_GST_VERSION VERSION_NUM(GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO)
++
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
++#include <gst/pbutils/encoding-profile.h>
+ //#include <gst/base/gsttypefindhelper.h>
++#endif
+ 
+ 
+ #ifdef NDEBUG
+@@ -1114,9 +1120,12 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+ 
+     GstCaps* caps = NULL;
+     GstCaps* videocaps = NULL;
++
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
+     GstCaps* containercaps = NULL;
+     GstEncodingContainerProfile* containerprofile = NULL;
+     GstEncodingVideoProfile* videoprofile = NULL;
++#endif
+ 
+ #if GST_VERSION_MAJOR == 0
+     GstIterator *it = NULL;
+@@ -1178,16 +1187,21 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+         if (!mime) {
+             CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer Opencv backend does not support this file type.");
+         }
++
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
+         containercaps = gst_caps_from_string(mime);
+ 
+         //create encodebin profile
+         containerprofile = gst_encoding_container_profile_new("container", "container", containercaps, NULL);
+         videoprofile = gst_encoding_video_profile_new(videocaps, NULL, NULL, 1);
+         gst_encoding_container_profile_add_profile(containerprofile, (GstEncodingProfile *) videoprofile);
++#endif
+ 
+         //create pipeline elements
+         encodebin = gst_element_factory_make("encodebin", NULL);
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,32)
+         g_object_set(G_OBJECT(encodebin), "profile", containerprofile, NULL);
++#endif
+         source = gst_element_factory_make("appsrc", NULL);
+         file = gst_element_factory_make("filesink", NULL);
+         g_object_set(G_OBJECT(file), "location", filename, NULL);
+@@ -1218,6 +1232,7 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+     }
+     else
+     {
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,29)
+         input_pix_fmt = GST_VIDEO_FORMAT_GRAY8;
+         bufsize = frameSize.width * frameSize.height;
+ 
+@@ -1236,6 +1251,9 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+                                    NULL);
+         caps = gst_caps_fixate(caps);
+ #endif
++#else
++        CV_Assert(!"Gstreamer 0.10.29 or newer is required for grayscale input");
++#endif
+     }
+ 
+     gst_app_src_set_caps(GST_APP_SRC(source), caps);
+@@ -1296,11 +1314,13 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
+             CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
+         }
+     }
++#if FULL_GST_VERSION >= VERSION_NUM(0,10,29)
+     else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY8) {
+         if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) {
+             CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1.");
+         }
+     }
++#endif
+     else {
+         assert(false);
+     }
+-- 
+1.9.3
+

diff --git a/0865-gstreamer-cleaning-up-resources.patch b/0865-gstreamer-cleaning-up-resources.patch
new file mode 100644
index 0000000..8ef07ec
--- /dev/null
+++ b/0865-gstreamer-cleaning-up-resources.patch
@@ -0,0 +1,72 @@
+From 6d66d11046bb526d508e9543ecc37cfee91f4435 Mon Sep 17 00:00:00 2001
+From: Dirk Van Haerenborgh <dirk.vanhaerenborgh@hogent.be>
+Date: Wed, 12 Jun 2013 16:58:16 +0200
+Subject: [PATCH 0865/3152] gstreamer: cleaning up resources
+
+---
+ modules/highgui/src/cap_gstreamer.cpp | 42 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp
+index b8f4eb8..a347a74 100644
+--- a/modules/highgui/src/cap_gstreamer.cpp
++++ b/modules/highgui/src/cap_gstreamer.cpp
+@@ -1030,6 +1030,19 @@ void CvVideoWriter_GStreamer::close()
+         handleMessage(pipeline);
+ 
+         gst_object_unref (GST_OBJECT (pipeline));
++
++        if (source)
++          gst_object_unref (GST_OBJECT (source));
++
++        if (encodebin)
++          gst_object_unref (GST_OBJECT (encodebin));
++
++        if (file)
++          gst_object_unref (GST_OBJECT (file));
++
++        if (buffer)
++          gst_object_unref (GST_OBJECT (buffer));
++
+     }
+ }
+ 
+@@ -1155,6 +1168,35 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+             source = gst_bin_get_by_name(GST_BIN(encodebin), "appsrc0");
+         }
+ 
++//        GstIterator *it = gst_bin_iterate_sources (GST_BIN(encodebin));
++
++
++//        gboolean done = FALSE;
++//        GstElement *item = NULL;
++
++//        while (!done) {
++//          switch (gst_iterator_next (it, &item)) {
++//            case GST_ITERATOR_OK:
++//              source = item;
++//              gst_object_unref (item);
++//              done = TRUE;
++//              break;
++//            case GST_ITERATOR_RESYNC:
++//              gst_iterator_resync (it);
++//              break;
++//            case GST_ITERATOR_ERROR:
++//              done = TRUE;
++//              break;
++//            case GST_ITERATOR_DONE:
++//              done = TRUE;
++//              break;
++//          }
++//        }
++//        gst_iterator_free (it);
++
++
++
++
+         if (!source){
+             CV_ERROR(CV_StsError, "GStreamer: cannot find appsrc in manual pipeline\n");
+             return false;
+-- 
+1.9.3
+

diff --git a/0871-allow-for-arbitraty-number-of-sources-and-sinks.patch b/0871-allow-for-arbitraty-number-of-sources-and-sinks.patch
new file mode 100644
index 0000000..a264a11
--- /dev/null
+++ b/0871-allow-for-arbitraty-number-of-sources-and-sinks.patch
@@ -0,0 +1,165 @@
+From 30f7f9717f1f0a8c11ba88d4f04b0c7cf26bba70 Mon Sep 17 00:00:00 2001
+From: Dirk Van Haerenborgh <dirk.vanhaerenborgh@hogent.be>
+Date: Thu, 13 Jun 2013 11:16:33 +0200
+Subject: [PATCH 0871/3152] allow for arbitraty number of sources and sinks
+
+---
+ modules/highgui/src/cap_gstreamer.cpp | 110 ++++++++++++++++++++--------------
+ 1 file changed, 65 insertions(+), 45 deletions(-)
+
+diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp
+index a347a74..4d4dc71 100644
+--- a/modules/highgui/src/cap_gstreamer.cpp
++++ b/modules/highgui/src/cap_gstreamer.cpp
+@@ -651,17 +651,47 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
+ 
+     if(manualpipeline)
+     {
++        GstIterator *it = NULL;
+ #if GST_VERSION_MAJOR == 0
+-        GstIterator *it = gst_bin_iterate_sinks(GST_BIN(uridecodebin));
++        it = gst_bin_iterate_sinks(GST_BIN(uridecodebin));
+         if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) {
+             CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
+             return false;
+         }
+ #else
+-        sink = gst_bin_get_by_name(GST_BIN(uridecodebin), "opencvsink");
+-        if (!sink){
+-            sink = gst_bin_get_by_name(GST_BIN(uridecodebin), "appsink0");
++        it = gst_bin_iterate_sinks (GST_BIN(uridecodebin));
++
++        gboolean done = FALSE;
++        GstElement *element = NULL;
++        gchar* name = NULL;
++        GValue value = G_VALUE_INIT;
++
++        while (!done) {
++          switch (gst_iterator_next (it, &value)) {
++            case GST_ITERATOR_OK:
++              element = GST_ELEMENT (g_value_get_object (&value));
++              name = gst_element_get_name(element);
++              if (name){
++                if(strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) {
++                  sink = GST_ELEMENT ( gst_object_ref (element) );
++                  done = TRUE;
++                }
++                g_free(name);
++              }
++              g_value_unset (&value);
++
++              break;
++            case GST_ITERATOR_RESYNC:
++              gst_iterator_resync (it);
++              break;
++            case GST_ITERATOR_ERROR:
++            case GST_ITERATOR_DONE:
++              done = TRUE;
++              break;
++          }
+         }
++        gst_iterator_free (it);
++
+ 
+         if (!sink){
+             CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n");
+@@ -1034,15 +1064,8 @@ void CvVideoWriter_GStreamer::close()
+         if (source)
+           gst_object_unref (GST_OBJECT (source));
+ 
+-        if (encodebin)
+-          gst_object_unref (GST_OBJECT (encodebin));
+-
+         if (file)
+           gst_object_unref (GST_OBJECT (file));
+-
+-        if (buffer)
+-          gst_object_unref (GST_OBJECT (buffer));
+-
+     }
+ }
+ 
+@@ -1140,9 +1163,7 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+     GstEncodingVideoProfile* videoprofile = NULL;
+ #endif
+ 
+-#if GST_VERSION_MAJOR == 0
+     GstIterator *it = NULL;
+-#endif
+ 
+     // we first try to construct a pipeline from the given string.
+     // if that fails, we assume it is an ordinary filename
+@@ -1163,39 +1184,38 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
+             return false;
+         }
+ #else
+-        source = gst_bin_get_by_name(GST_BIN(encodebin), "opencvsrc");
+-        if (!source){
+-            source = gst_bin_get_by_name(GST_BIN(encodebin), "appsrc0");
++        it = gst_bin_iterate_sources (GST_BIN(encodebin));
++
++        gboolean done = FALSE;
++        GstElement *element = NULL;
++        gchar* name = NULL;
++        GValue value = G_VALUE_INIT;
++
++        while (!done) {
++          switch (gst_iterator_next (it, &value)) {
++            case GST_ITERATOR_OK:
++              element = GST_ELEMENT (g_value_get_object (&value));
++              name = gst_element_get_name(element);
++              if (name){
++                if(strstr(name, "opencvsrc") != NULL || strstr(name, "appsrc") != NULL) {
++                  source = GST_ELEMENT ( gst_object_ref (element) );
++                  done = TRUE;
++                }
++                g_free(name);
++              }
++              g_value_unset (&value);
++
++              break;
++            case GST_ITERATOR_RESYNC:
++              gst_iterator_resync (it);
++              break;
++            case GST_ITERATOR_ERROR:
++            case GST_ITERATOR_DONE:
++              done = TRUE;
++              break;
++          }
+         }
+-
+-//        GstIterator *it = gst_bin_iterate_sources (GST_BIN(encodebin));
+-
+-
+-//        gboolean done = FALSE;
+-//        GstElement *item = NULL;
+-
+-//        while (!done) {
+-//          switch (gst_iterator_next (it, &item)) {
+-//            case GST_ITERATOR_OK:
+-//              source = item;
+-//              gst_object_unref (item);
+-//              done = TRUE;
+-//              break;
+-//            case GST_ITERATOR_RESYNC:
+-//              gst_iterator_resync (it);
+-//              break;
+-//            case GST_ITERATOR_ERROR:
+-//              done = TRUE;
+-//              break;
+-//            case GST_ITERATOR_DONE:
+-//              done = TRUE;
+-//              break;
+-//          }
+-//        }
+-//        gst_iterator_free (it);
+-
+-
+-
++        gst_iterator_free (it);
+ 
+         if (!source){
+             CV_ERROR(CV_StsError, "GStreamer: cannot find appsrc in manual pipeline\n");
+-- 
+1.9.3
+

diff --git a/opencv.spec b/opencv.spec
index 3e8a1c3..0bec970 100644
--- a/opencv.spec
+++ b/opencv.spec
@@ -2,7 +2,7 @@
 
 Name:           opencv
 Version:        2.4.9
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Collection of algorithms for computer vision
 Group:          Development/Libraries
 # This is normal three clause BSD.
@@ -24,6 +24,17 @@ Patch3:         opencv-2.4.9-ts_static.patch
 # https://bugzilla.redhat.com/1031312
 Patch4:         opencv-2.4.7-cmake_paths.patch
 
+# relevant gst1-related patches from upstream master branch
+%if 0%{?fedora} > 20
+%global gst1 1
+%endif
+# 0550 needed slight rebasing -- rex
+Patch10: 0550-bomb-commit-of-gstreamer-videocapture-and-videowrite.patch
+Patch11: 0552-eliminated-warnings.patch
+Patch12: 0587-Fix-build-with-gstreamer-0.10.28.patch
+Patch13: 0865-gstreamer-cleaning-up-resources.patch
+Patch14: 0871-allow-for-arbitraty-number-of-sources-and-sinks.patch
+
 BuildRequires:  libtool
 BuildRequires:  cmake >= 2.6.3
 BuildRequires:  chrpath
@@ -63,7 +74,11 @@ BuildRequires:  python2-devel
 BuildRequires:  numpy, swig >= 1.3.24
 BuildRequires:  python-sphinx
 %{?_with_ffmpeg:BuildRequires:  ffmpeg-devel >= 0.4.9}
+%if 0%{?gst1}
+%{!?_without_gstreamer:BuildRequires:  gstreamer1-devel gstreamer1-plugins-base-devel}
+%else
 %{!?_without_gstreamer:BuildRequires:  gstreamer-devel gstreamer-plugins-base-devel}
+%endif
 %{?_with_xine:BuildRequires:  xine-lib-devel}
 BuildRequires:  opencl-headers
 
@@ -120,6 +135,14 @@ This package contains Python bindings for the OpenCV library.
 %patch3 -p1 -b .ts_static
 %patch4 -p1 -b .cmake_paths
 
+%if 0%{?gst1}
+%patch10 -p1 -b .10
+%patch11 -p1 -b .11
+%patch12 -p1 -b .12
+%patch13 -p1 -b .13
+%patch14 -p1 -b .14
+%endif
+
 # fix dos end of lines
 sed -i 's|\r||g'  samples/c/adaptiveskindetector.cpp
 
@@ -250,6 +273,9 @@ popd
 %{python2_sitearch}/cv2.so
 
 %changelog
+* Fri Jul 25 2014 Rex Dieter <rdieter@fedoraproject.org> 2.4.9-2
+- backport support for GStreamer 1 (#1123078)
+
 * Thu Jul 03 2014 Nicolas Chauvet <kwizart@gmail.com> - 2.4.9-1
 - Update to 2.4.9
 

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-28 13:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-28 13:30 [rpms/opencv] opencv5: backport support for GStreamer 1 (#1123078) Rex Dieter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox