public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Rex Dieter <rdieter@math.unl.edu>
To: git-commits@fedoraproject.org
Subject: [rpms/opencv] opencv5: backport support for GStreamer 1 (#1123078)
Date: Fri, 28 Aug 2026 13:30:24 GMT [thread overview]
Message-ID: <178792382470.1.8970455005798766005.rpms-opencv-053e3d73adc3@fedoraproject.org> (raw)
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),¤t, &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
reply other threads:[~2026-08-28 13:30 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178792382470.1.8970455005798766005.rpms-opencv-053e3d73adc3@fedoraproject.org \
--to=rdieter@math.unl.edu \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox