From 79767831cc71d8b062adf429f6b9e0d270bcac2a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 28 Feb 2011 18:33:13 +0100 Subject: [PATCH 01/20] Automatic update of common submodule From 1de7f6a to 6aec6b9 --- common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common b/common index 1de7f6ab2d..6aec6b9716 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178 +Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd From ef7cad4176bfb429dda5c1b2923353a732b466fe Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 28 Feb 2011 19:58:41 +0100 Subject: [PATCH 02/20] configure.ac: export plugin description more platform independent Fixes #642504. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6b4bf57945..1901d026e9 100644 --- a/configure.ac +++ b/configure.ac @@ -1701,7 +1701,7 @@ AC_SUBST(GST_LIB_LDFLAGS) dnl this really should only contain flags, not libs - they get added before dnl whatevertarget_LIBS and -L flags here affect the rest of the linking -GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc\$\$' $GST_ALL_LDFLAGS" +GST_PLUGIN_LDFLAGS="-module -avoid-version -export-symbols-regex '^[_]*gst_plugin_desc.*' $GST_ALL_LDFLAGS" AC_SUBST(GST_PLUGIN_LDFLAGS) dnl *** output files *** From e4331322f2ea775e1b55aed99d3f964dbe324bb8 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 28 Feb 2011 20:19:53 +0100 Subject: [PATCH 03/20] configure.ac: cygwin/mingw; enable plugin linking to static lib Useful for DirectX plugin(s). Fixes #642507. --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 1901d026e9..b88f328561 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,8 @@ dnl we override it here if we need to for the release candidate of new series GST_MAJORMINOR=0.10 AC_SUBST(GST_MAJORMINOR) +AG_GST_LIBTOOL_PREPARE + dnl FIXME: this macro doesn't actually work; dnl the generated libtool script has no support for the listed tags. dnl So this needs to be fixed first if we want to use this From b2be3e2f1a79066518eda791ef45194beceddb52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 25 Feb 2011 14:24:17 +0000 Subject: [PATCH 04/20] jp2kdec: post proper error when the image's colour space is not supported https://bugzilla.gnome.org/show_bug.cgi?id=643115 --- ext/jp2k/gstjasperdec.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ext/jp2k/gstjasperdec.c b/ext/jp2k/gstjasperdec.c index 595134c461..159eb95c8f 100644 --- a/ext/jp2k/gstjasperdec.c +++ b/ext/jp2k/gstjasperdec.c @@ -256,12 +256,13 @@ refuse_caps: } } -static gboolean +static GstFlowReturn gst_jasper_dec_negotiate (GstJasperDec * dec, jas_image_t * image) { + GstFlowReturn flow_ret = GST_FLOW_OK; gint width, height, channels; gint i, j; - gboolean negotiate = FALSE, ret = TRUE; + gboolean negotiate = FALSE; jas_clrspc_t clrspc; GstCaps *allowed_caps, *caps; @@ -316,7 +317,7 @@ gst_jasper_dec_negotiate (GstJasperDec * dec, jas_image_t * image) goto done; /* clear and refresh to new state */ - ret = FALSE; + flow_ret = GST_FLOW_NOT_NEGOTIATED; dec->format = GST_VIDEO_FORMAT_UNKNOWN; dec->width = width; dec->height = height; @@ -419,24 +420,30 @@ gst_jasper_dec_negotiate (GstJasperDec * dec, jas_image_t * image) GST_DEBUG_OBJECT (dec, "Set format to %d, size to %dx%d", dec->format, dec->width, dec->height); - ret = gst_pad_set_caps (dec->srcpad, caps); + + if (!gst_pad_set_caps (dec->srcpad, caps)) + flow_ret = GST_FLOW_NOT_NEGOTIATED; + else + flow_ret = GST_FLOW_OK; + gst_caps_unref (caps); } done: - return ret; + return flow_ret; /* ERRORS */ fail_image: { GST_DEBUG_OBJECT (dec, "Failed to process decoded image."); - ret = FALSE; + flow_ret = GST_FLOW_NOT_NEGOTIATED; goto done; } not_supported: { GST_DEBUG_OBJECT (dec, "Decoded image has unsupported colour space."); - ret = FALSE; + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Unsupported colorspace")); + flow_ret = GST_FLOW_ERROR; goto done; } } @@ -460,7 +467,8 @@ gst_jasper_dec_get_picture (GstJasperDec * dec, guint8 * data, if (!(image = jas_image_decode (stream, dec->fmt, (char *) ""))) goto fail_decode; - if (!gst_jasper_dec_negotiate (dec, image)) + ret = gst_jasper_dec_negotiate (dec, image); + if (ret != GST_FLOW_OK) goto fail_negotiate; ret = gst_pad_alloc_buffer_and_set_caps (dec->srcpad, @@ -548,7 +556,6 @@ no_buffer: fail_negotiate: { GST_DEBUG_OBJECT (dec, "Failed to determine output caps."); - ret = GST_FLOW_NOT_NEGOTIATED; goto done; } } From 16b79f6f2dd28db49fa5693a06da045132cb69d6 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Sat, 26 Feb 2011 20:20:33 +0000 Subject: [PATCH 05/20] curl: add libcurl-based sink element Sink acts as a client and can connect to servers to upload media. https://bugzilla.gnome.org/show_bug.cgi?id=641496 --- ext/curl/Makefile.am | 15 + ext/curl/gstcurl.c | 40 ++ ext/curl/gstcurlsink.c | 1301 ++++++++++++++++++++++++++++++++++++++++ ext/curl/gstcurlsink.h | 106 ++++ 4 files changed, 1462 insertions(+) create mode 100644 ext/curl/Makefile.am create mode 100644 ext/curl/gstcurl.c create mode 100644 ext/curl/gstcurlsink.c create mode 100644 ext/curl/gstcurlsink.h diff --git a/ext/curl/Makefile.am b/ext/curl/Makefile.am new file mode 100644 index 0000000000..77b237385a --- /dev/null +++ b/ext/curl/Makefile.am @@ -0,0 +1,15 @@ +plugin_LTLIBRARIES = libgstcurl.la + +libgstcurl_la_SOURCES = gstcurl.c gstcurlsink.c +libgstcurl_la_CFLAGS = \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(CURL_CFLAGS) +libgstcurl_la_LIBADD = \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(CURL_LIBS) +libgstcurl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstcurl_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstcurlsink.h diff --git a/ext/curl/gstcurl.c b/ext/curl/gstcurl.c new file mode 100644 index 0000000000..39c214d759 --- /dev/null +++ b/ext/curl/gstcurl.c @@ -0,0 +1,40 @@ +/* GStreamer + * Copyright (C) 2011 Axis Communications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstcurlsink.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + if (!gst_element_register (plugin, "curlsink", GST_RANK_NONE, + GST_TYPE_CURL_SINK)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "curl", + "libcurl-based elements", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/curl/gstcurlsink.c b/ext/curl/gstcurlsink.c new file mode 100644 index 0000000000..8a4c7643f3 --- /dev/null +++ b/ext/curl/gstcurlsink.c @@ -0,0 +1,1301 @@ +/* GStreamer + * Copyright (C) 2011 Axis Communications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstcurlsink.h" + +/* Default values */ +#define GST_CAT_DEFAULT gst_curl_sink_debug +#define DEFAULT_URL "localhost:5555" +#define DEFAULT_TIMEOUT 30 +#define DEFAULT_PROXY_PORT 3128 +#define DEFAULT_QOS_DSCP 0 +#define DEFAULT_ACCEPT_SELF_SIGNED FALSE +#define DEFAULT_USE_CONTENT_LENGTH FALSE + +#define DSCP_MIN 0 +#define DSCP_MAX 63 +#define RESPONSE_100_CONTINUE 100 +#define RESPONSE_CONNECT_PROXY 200 + +/* Plugin specific settings */ +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC (gst_curl_sink_debug); + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_USER_NAME, + PROP_USER_PASSWD, + PROP_PROXY, + PROP_PROXY_PORT, + PROP_PROXY_USER_NAME, + PROP_PROXY_USER_PASSWD, + PROP_FILE_NAME, + PROP_TIMEOUT, + PROP_QOS_DSCP, + PROP_ACCEPT_SELF_SIGNED, + PROP_USE_CONTENT_LENGTH, + PROP_CONTENT_TYPE +}; +static gboolean proxy_auth = FALSE; +static gboolean proxy_conn_established = FALSE; + +/* Object class function declarations */ +static void gst_curl_sink_finalize (GObject * gobject); +static void gst_curl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_curl_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +/* BaseSink class function declarations */ +static GstFlowReturn gst_curl_sink_render (GstBaseSink * bsink, + GstBuffer * buf); +static gboolean gst_curl_sink_event (GstBaseSink * bsink, GstEvent * event); +static gboolean gst_curl_sink_start (GstBaseSink * bsink); +static gboolean gst_curl_sink_stop (GstBaseSink * bsink); +static gboolean gst_curl_sink_unlock (GstBaseSink * bsink); +static gboolean gst_curl_sink_unlock_stop (GstBaseSink * bsink); + +/* private functions */ +static gboolean gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink); +static gboolean gst_curl_sink_transfer_set_options_unlocked (GstCurlSink + * sink); +static gboolean gst_curl_sink_transfer_start_unlocked (GstCurlSink * sink); +static void gst_curl_sink_transfer_cleanup (GstCurlSink * sink); +static size_t gst_curl_sink_transfer_read_cb (void *ptr, size_t size, + size_t nmemb, void *stream); +static size_t gst_curl_sink_transfer_write_cb (void *ptr, size_t size, + size_t nmemb, void *stream); +static GstFlowReturn gst_curl_sink_handle_transfer (GstCurlSink * sink); +static int gst_curl_sink_transfer_socket_cb (void *clientp, + curl_socket_t curlfd, curlsocktype purpose); +static gpointer gst_curl_sink_transfer_thread_func (gpointer data); +static CURLcode gst_curl_sink_transfer_check (GstCurlSink * sink); +static gint gst_curl_sink_setup_dscp_unlocked (GstCurlSink * sink); + +static gboolean gst_curl_sink_wait_for_data_unlocked (GstCurlSink * sink); +static void gst_curl_sink_new_file_notify_unlocked (GstCurlSink * sink); +static void gst_curl_sink_transfer_thread_notify_unlocked (GstCurlSink * sink); +static void gst_curl_sink_transfer_thread_close_unlocked (GstCurlSink * sink); +static void gst_curl_sink_wait_for_transfer_thread_to_send_unlocked (GstCurlSink + * sink); +static void gst_curl_sink_data_sent_notify_unlocked (GstCurlSink * sink); + +static void +_do_init (GType type) +{ + GST_DEBUG_CATEGORY_INIT (gst_curl_sink_debug, "curlsink", 0, + "curl sink element"); +} + +GST_BOILERPLATE_FULL (GstCurlSink, gst_curl_sink, GstBaseSink, + GST_TYPE_BASE_SINK, _do_init); + +static void +gst_curl_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sinktemplate)); + gst_element_class_set_details_simple (element_class, + "Curl sink", + "Sink/Network", + "Send over network using curl", "Patricia Muscalu "); +} + +static void +gst_curl_sink_class_init (GstCurlSinkClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass; + GParamSpec *loc_prspec = g_param_spec_string ("location", + "Location", + "URI location to write to", + NULL, + G_PARAM_READWRITE); + GParamSpec *user_prspec = g_param_spec_string ("user", + "User nanme)", + "User name to use for server authentication", + NULL, + G_PARAM_READWRITE); + GParamSpec *passwd_prspec = g_param_spec_string ("passwd", + "User password)", + "User password to use for server authentication", + NULL, + G_PARAM_READWRITE); + GParamSpec *proxy_prspec = g_param_spec_string ("proxy", + "proxy", + "HTTP proxy server URI", + NULL, + G_PARAM_READWRITE); + + GParamSpec *proxy_port_prspec = g_param_spec_int ("proxy-port", + "proxy port", + "HTTP proxy server port", + 0, + G_MAXINT, + DEFAULT_PROXY_PORT, + G_PARAM_READWRITE); + GParamSpec *proxy_user_prspec = g_param_spec_string ("proxy-user", + "Proxy user name)", + "Proxy user name to use for proxy authentication", + NULL, + G_PARAM_READWRITE); + GParamSpec *proxy_passwd_prspec = g_param_spec_string ("proxy-passwd", + "Prpxu user password)", + "Proxy user password to use for proxy authentication", + NULL, + G_PARAM_READWRITE); + GParamSpec *file_name_prspec = g_param_spec_string ("file-name", + "Base file name", + "The base file name for the uploaded images", + NULL, + G_PARAM_READWRITE); + + GParamSpec *timeout_prspec = g_param_spec_int ("timeout", + "timeout", + "Number of seconds waiting to write before timeout", + 0, + G_MAXINT, + DEFAULT_TIMEOUT, + G_PARAM_READWRITE); + GParamSpec *qos_dscp_prspec = g_param_spec_int ("qos-dscp", + "QoS diff srv code point", + "Quality of Service, differentiated services code point (0 default)", + DSCP_MIN, + DSCP_MAX, + DEFAULT_QOS_DSCP, + G_PARAM_READWRITE); + GParamSpec *self_cert_prspec = g_param_spec_boolean ("accept-self-signed", + "Accept self-signed certificates", + "Accept self-signed SSL/TLS certificates", + DEFAULT_ACCEPT_SELF_SIGNED, + G_PARAM_READWRITE); + GParamSpec *content_lngth_prspec = g_param_spec_boolean ("use-content-length", + "Use content length header", + "Use the Content-Length HTTP header instead of Transfer-Encoding header", + DEFAULT_USE_CONTENT_LENGTH, + G_PARAM_READWRITE); + GParamSpec *content_type_prspec = g_param_spec_string ("content-type", + "Content type header)", + "The mime type of the body of the request", + NULL, + G_PARAM_READWRITE); + + GST_DEBUG_OBJECT (klass, "class_init"); + + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_curl_sink_event); + gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_curl_sink_render); + gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_curl_sink_start); + gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_curl_sink_stop); + gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_curl_sink_unlock); + gstbasesink_class->unlock_stop = + GST_DEBUG_FUNCPTR (gst_curl_sink_unlock_stop); + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_curl_sink_finalize); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_curl_sink_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_curl_sink_get_property); + g_object_class_install_property (gobject_class, PROP_LOCATION, loc_prspec); + g_object_class_install_property (gobject_class, PROP_USER_NAME, user_prspec); + g_object_class_install_property (gobject_class, PROP_USER_PASSWD, + passwd_prspec); + g_object_class_install_property (gobject_class, PROP_PROXY, proxy_prspec); + g_object_class_install_property (gobject_class, PROP_PROXY_PORT, + proxy_port_prspec); + g_object_class_install_property (gobject_class, PROP_PROXY_USER_NAME, + proxy_user_prspec); + g_object_class_install_property (gobject_class, PROP_PROXY_USER_PASSWD, + proxy_passwd_prspec); + g_object_class_install_property (gobject_class, PROP_FILE_NAME, + file_name_prspec); + g_object_class_install_property (gobject_class, PROP_TIMEOUT, timeout_prspec); + g_object_class_install_property (gobject_class, PROP_QOS_DSCP, + qos_dscp_prspec); + g_object_class_install_property (gobject_class, PROP_ACCEPT_SELF_SIGNED, + self_cert_prspec); + g_object_class_install_property (gobject_class, PROP_USE_CONTENT_LENGTH, + content_lngth_prspec); + g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE, + content_type_prspec); + + g_type_class_add_private (klass, sizeof (GstCurlSinkPrivate)); +} + +static void +gst_curl_sink_init (GstCurlSink * sink, GstCurlSinkClass * klass) +{ + sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink, GST_TYPE_CURL_SINK, + GstCurlSinkPrivate); + + sink->priv->transfer_buf = g_malloc (sizeof (TransferBuffer)); + sink->priv->transfer_cond = g_malloc (sizeof (TransferCondition)); + sink->priv->transfer_cond->cond = g_cond_new (); + sink->priv->transfer_cond->data_sent = FALSE; + sink->priv->transfer_cond->data_available = FALSE; + sink->priv->timeout = DEFAULT_TIMEOUT; + sink->priv->proxy_port = DEFAULT_PROXY_PORT; + sink->priv->qos_dscp = DEFAULT_QOS_DSCP; + sink->priv->url = g_strdup (DEFAULT_URL); + sink->priv->header_list = NULL; + sink->priv->accept_self_signed = DEFAULT_ACCEPT_SELF_SIGNED; + sink->priv->use_content_length = DEFAULT_USE_CONTENT_LENGTH; + sink->priv->transfer_thread_close = FALSE; + sink->priv->new_file = TRUE; + sink->priv->proxy_headers_set = FALSE; + sink->priv->content_type = NULL; +} + +static void +gst_curl_sink_finalize (GObject * gobject) +{ + GstCurlSink *this = GST_CURL_SINK (gobject); + + GST_DEBUG ("finalizing curlsink"); + if (this->priv->transfer_thread != NULL) { + g_thread_join (this->priv->transfer_thread); + } + + gst_curl_sink_transfer_cleanup (this); + g_cond_free (this->priv->transfer_cond->cond); + g_free (this->priv->transfer_cond); + + g_free (this->priv->transfer_buf); + + g_free (this->priv->url); + g_free (this->priv->user); + g_free (this->priv->passwd); + g_free (this->priv->proxy); + g_free (this->priv->proxy_user); + g_free (this->priv->proxy_passwd); + g_free (this->priv->file_name); + g_free (this->priv->content_type); + + if (this->priv->header_list) { + curl_slist_free_all (this->priv->header_list); + this->priv->header_list = NULL; + } + + if (this->priv->fdset != NULL) { + gst_poll_free (this->priv->fdset); + this->priv->fdset = NULL; + } + G_OBJECT_CLASS (parent_class)->finalize (gobject); +} + +static GstFlowReturn +gst_curl_sink_render (GstBaseSink * bsink, GstBuffer * buf) +{ + GstCurlSink *sink = GST_CURL_SINK (bsink); + guint8 *data; + size_t size; + GstFlowReturn ret; + + GST_LOG ("enter render"); + + sink = GST_CURL_SINK (bsink); + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + if (sink->priv->content_type == NULL) { + GstCaps *caps; + GstStructure *structure; + const gchar *mime_type; + + caps = buf->caps; + structure = gst_caps_get_structure (caps, 0); + mime_type = gst_structure_get_name (structure); + sink->priv->content_type = g_strdup (mime_type); + } + + GST_OBJECT_LOCK (sink); + + /* check if the transfer thread has encountered problems while the + * pipeline thread was working elsewhere */ + if (sink->priv->flow_ret != GST_FLOW_OK) { + goto done; + } + + g_assert (sink->priv->transfer_cond->data_available == FALSE); + + /* if there is no transfer thread created, lets create one */ + if (sink->priv->transfer_thread == NULL) { + if (!gst_curl_sink_transfer_start_unlocked (sink)) { + sink->priv->flow_ret = GST_FLOW_ERROR; + goto done; + } + } + + /* make data available for the transfer thread and notify */ + sink->priv->transfer_buf->ptr = data; + sink->priv->transfer_buf->len = size; + sink->priv->transfer_buf->offset = 0; + gst_curl_sink_transfer_thread_notify_unlocked (sink); + + /* wait for the transfer thread to send the data. This will be notified + * either when transfer is completed by the curl read callback or by + * the thread function if an error has occured. */ + gst_curl_sink_wait_for_transfer_thread_to_send_unlocked (sink); + +done: + ret = sink->priv->flow_ret; + GST_OBJECT_UNLOCK (sink); + + GST_LOG ("exit render"); + + return ret; +} + +static gboolean +gst_curl_sink_event (GstBaseSink * bsink, GstEvent * event) +{ + GstCurlSink *sink = GST_CURL_SINK (bsink); + + switch (event->type) { + case GST_EVENT_EOS: + GST_DEBUG_OBJECT (sink, "received EOS"); + GST_OBJECT_LOCK (sink); + gst_curl_sink_transfer_thread_close_unlocked (sink); + GST_OBJECT_UNLOCK (sink); + if (sink->priv->transfer_thread != NULL) { + g_thread_join (sink->priv->transfer_thread); + sink->priv->transfer_thread = NULL; + } + break; + default: + break; + } + return TRUE; +} + +static gboolean +gst_curl_sink_start (GstBaseSink * bsink) +{ + GstCurlSink *sink; + + sink = GST_CURL_SINK (bsink); + + if ((sink->priv->fdset = gst_poll_new (TRUE)) == NULL) { + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, + ("gst_poll_new failed: %s", g_strerror (errno)), (NULL)); + return FALSE; + } + + return TRUE; +} + +static gboolean +gst_curl_sink_stop (GstBaseSink * bsink) +{ + GstCurlSink *sink = GST_CURL_SINK (bsink); + + GST_OBJECT_LOCK (sink); + gst_curl_sink_transfer_thread_close_unlocked (sink); + GST_OBJECT_UNLOCK (sink); + if (sink->priv->fdset != NULL) { + gst_poll_free (sink->priv->fdset); + sink->priv->fdset = NULL; + } + + return TRUE; +} + +static gboolean +gst_curl_sink_unlock (GstBaseSink * bsink) +{ + GstCurlSink *sink; + + sink = GST_CURL_SINK (bsink); + + GST_LOG_OBJECT (sink, "Flushing"); + gst_poll_set_flushing (sink->priv->fdset, TRUE); + + return TRUE; +} + +static gboolean +gst_curl_sink_unlock_stop (GstBaseSink * bsink) +{ + GstCurlSink *sink; + + sink = GST_CURL_SINK (bsink); + + GST_LOG_OBJECT (sink, "No longer flushing"); + gst_poll_set_flushing (sink->priv->fdset, FALSE); + + return TRUE; +} + +static void +gst_curl_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstCurlSink *sink; + GstState cur_state; + + g_return_if_fail (GST_IS_CURL_SINK (object)); + sink = GST_CURL_SINK (object); + + gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); + if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) { + GST_OBJECT_LOCK (sink); + + switch (prop_id) { + case PROP_LOCATION: + g_free (sink->priv->url); + sink->priv->url = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "url set to %s", sink->priv->url); + break; + case PROP_USER_NAME: + g_free (sink->priv->user); + sink->priv->user = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "user set to %s", sink->priv->user); + break; + case PROP_USER_PASSWD: + g_free (sink->priv->passwd); + sink->priv->passwd = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->priv->passwd); + break; + case PROP_PROXY: + g_free (sink->priv->proxy); + sink->priv->proxy = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy set to %s", sink->priv->proxy); + break; + case PROP_PROXY_PORT: + sink->priv->proxy_port = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "proxy port set to %d", sink->priv->proxy_port); + break; + case PROP_PROXY_USER_NAME: + g_free (sink->priv->proxy_user); + sink->priv->proxy_user = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy user set to %s", sink->priv->proxy_user); + break; + case PROP_PROXY_USER_PASSWD: + g_free (sink->priv->proxy_passwd); + sink->priv->proxy_passwd = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy password set to %s", + sink->priv->proxy_passwd); + break; + case PROP_FILE_NAME: + g_free (sink->priv->file_name); + sink->priv->file_name = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->priv->file_name); + break; + case PROP_TIMEOUT: + sink->priv->timeout = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->priv->timeout); + break; + case PROP_QOS_DSCP: + sink->priv->qos_dscp = g_value_get_int (value); + gst_curl_sink_setup_dscp_unlocked (sink); + GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->priv->qos_dscp); + break; + case PROP_ACCEPT_SELF_SIGNED: + sink->priv->accept_self_signed = g_value_get_boolean (value); + GST_DEBUG_OBJECT (sink, "accept_self_signed set to %d", + sink->priv->accept_self_signed); + break; + case PROP_USE_CONTENT_LENGTH: + sink->priv->use_content_length = g_value_get_boolean (value); + GST_DEBUG_OBJECT (sink, "use_content_length set to %d", + sink->priv->use_content_length); + break; + case PROP_CONTENT_TYPE: + g_free (sink->priv->content_type); + sink->priv->content_type = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "content type set to %s", + sink->priv->content_type); + break; + default: + GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id); + break; + } + + GST_OBJECT_UNLOCK (sink); + + return; + } + + /* in PLAYING or PAUSED state */ + GST_OBJECT_LOCK (sink); + + switch (prop_id) { + case PROP_FILE_NAME: + g_free (sink->priv->file_name); + sink->priv->file_name = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->priv->file_name); + gst_curl_sink_new_file_notify_unlocked (sink); + break; + case PROP_TIMEOUT: + sink->priv->timeout = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->priv->timeout); + break; + case PROP_QOS_DSCP: + sink->priv->qos_dscp = g_value_get_int (value); + gst_curl_sink_setup_dscp_unlocked (sink); + GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->priv->qos_dscp); + break; + case PROP_CONTENT_TYPE: + g_free (sink->priv->content_type); + sink->priv->content_type = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "content type set to %s", + sink->priv->content_type); + break; + default: + GST_WARNING_OBJECT (sink, "cannot set property when PLAYING"); + break; + } + + GST_OBJECT_UNLOCK (sink); +} + +static void +gst_curl_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstCurlSink *sink; + + g_return_if_fail (GST_IS_CURL_SINK (object)); + sink = GST_CURL_SINK (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, sink->priv->url); + break; + case PROP_USER_NAME: + g_value_set_string (value, sink->priv->user); + break; + case PROP_USER_PASSWD: + g_value_set_string (value, sink->priv->passwd); + break; + case PROP_PROXY: + g_value_set_string (value, sink->priv->proxy); + break; + case PROP_PROXY_PORT: + g_value_set_int (value, sink->priv->proxy_port); + break; + case PROP_PROXY_USER_NAME: + g_value_set_string (value, sink->priv->proxy_user); + break; + case PROP_PROXY_USER_PASSWD: + g_value_set_string (value, sink->priv->proxy_passwd); + break; + case PROP_FILE_NAME: + g_value_set_string (value, sink->priv->file_name); + break; + case PROP_TIMEOUT: + g_value_set_int (value, sink->priv->timeout); + break; + case PROP_QOS_DSCP: + g_value_set_int (value, sink->priv->qos_dscp); + break; + case PROP_ACCEPT_SELF_SIGNED: + g_value_set_boolean (value, sink->priv->accept_self_signed); + break; + case PROP_USE_CONTENT_LENGTH: + g_value_set_boolean (value, sink->priv->use_content_length); + break; + case PROP_CONTENT_TYPE: + g_value_set_string (value, sink->priv->content_type); + break; + default: + GST_DEBUG_OBJECT (sink, "invalid property id"); + break; + } +} + +static void +gst_curl_sink_set_http_header_unlocked (GstCurlSink * sink) +{ + gchar *tmp; + + if (sink->priv->header_list) { + curl_slist_free_all (sink->priv->header_list); + sink->priv->header_list = NULL; + } + + if (proxy_auth && !sink->priv->proxy_headers_set && !proxy_conn_established) { + sink->priv->header_list = + curl_slist_append (sink->priv->header_list, "Content-Length: 0"); + sink->priv->proxy_headers_set = TRUE; + goto set_headers; + } + if (sink->priv->use_content_length) { + /* if content length is used we assume that every buffer is one + * entire file, which is the case when uploading several jpegs */ + tmp = + g_strdup_printf ("Content-Length: %d", + (int) sink->priv->transfer_buf->len); + sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + g_free (tmp); + } else { + /* when sending a POST request to a HTTP 1.1 server, you can send data + * without knowing the size before starting the POST if you use chunked + * encoding */ + sink->priv->header_list = curl_slist_append (sink->priv->header_list, + "Transfer-Encoding: chunked"); + } + + tmp = g_strdup_printf ("Content-Type: %s", sink->priv->content_type); + sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + g_free (tmp); + +set_headers: + + tmp = g_strdup_printf ("Content-Disposition: attachment; filename=" + "\"%s\"", sink->priv->file_name); + sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + g_free (tmp); + curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPHEADER, + sink->priv->header_list); +} + +static gboolean +gst_curl_sink_transfer_set_options_unlocked (GstCurlSink * sink) +{ +#ifdef DEBUG + curl_easy_setopt (sink->priv->curl, CURLOPT_VERBOSE, 1); +#endif + + curl_easy_setopt (sink->priv->curl, CURLOPT_URL, sink->priv->url); + curl_easy_setopt (sink->priv->curl, CURLOPT_CONNECTTIMEOUT, + sink->priv->timeout); + + curl_easy_setopt (sink->priv->curl, CURLOPT_SOCKOPTDATA, sink); + curl_easy_setopt (sink->priv->curl, CURLOPT_SOCKOPTFUNCTION, + gst_curl_sink_transfer_socket_cb); + + if (sink->priv->user != NULL && strlen (sink->priv->user)) { + curl_easy_setopt (sink->priv->curl, CURLOPT_USERNAME, sink->priv->user); + curl_easy_setopt (sink->priv->curl, CURLOPT_PASSWORD, sink->priv->passwd); + curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + } + + if (sink->priv->accept_self_signed && g_str_has_prefix (sink->priv->url, + "https")) { + /* TODO verify the authenticity of the peer's certificate */ + curl_easy_setopt (sink->priv->curl, CURLOPT_SSL_VERIFYPEER, 0L); + /* TODO check the servers's claimed identity */ + curl_easy_setopt (sink->priv->curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + + /* proxy settings */ + if (sink->priv->proxy != NULL && strlen (sink->priv->proxy)) { + if (curl_easy_setopt (sink->priv->curl, CURLOPT_PROXY, sink->priv->proxy) + != CURLE_OK) { + return FALSE; + } + if (curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYPORT, + sink->priv->proxy_port) + != CURLE_OK) { + return FALSE; + } + if (sink->priv->proxy_user != NULL && + strlen (sink->priv->proxy_user) && + sink->priv->proxy_passwd != NULL && strlen (sink->priv->proxy_passwd)) { + curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYUSERNAME, + sink->priv->proxy_user); + curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYPASSWORD, + sink->priv->proxy_passwd); + curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + proxy_auth = TRUE; + } + /* tunnel all operations through a given HTTP proxy */ + if (curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPPROXYTUNNEL, 1L) + != CURLE_OK) { + return FALSE; + } + } + + /* POST options */ + curl_easy_setopt (sink->priv->curl, CURLOPT_POST, 1L); + + curl_easy_setopt (sink->priv->curl, CURLOPT_READFUNCTION, + gst_curl_sink_transfer_read_cb); + curl_easy_setopt (sink->priv->curl, CURLOPT_READDATA, sink); + curl_easy_setopt (sink->priv->curl, CURLOPT_WRITEFUNCTION, + gst_curl_sink_transfer_write_cb); + + return TRUE; +} + +static size_t +gst_curl_sink_transfer_read_cb (void *curl_ptr, size_t size, size_t nmemb, + void *stream) +{ + GstCurlSink *sink; + GstCurlSinkPrivate *pr; + TransferBuffer *buffer; + size_t max_bytes_to_send; + guint buf_len; + + sink = (GstCurlSink *) stream; + + /* wait for data to come available, if new file or thread close is set + * then zero will be returned to indicate end of current transfer */ + GST_OBJECT_LOCK (sink); + if (gst_curl_sink_wait_for_data_unlocked (sink) == FALSE) { + GST_LOG ("returning 0, no more data to send in this file"); + GST_OBJECT_UNLOCK (sink); + return 0; + } + GST_OBJECT_UNLOCK (sink); + + + max_bytes_to_send = size * nmemb; + pr = sink->priv; + buffer = pr->transfer_buf; + + buf_len = buffer->len; + GST_LOG ("write buf len=%d, offset=%d", buffer->len, buffer->offset); + + /* more data in buffer */ + if (buffer->len > 0) { + size_t bytes_to_send = MIN (max_bytes_to_send, buf_len); + + memcpy ((guint8 *) curl_ptr, buffer->ptr + buffer->offset, bytes_to_send); + + buffer->offset = buffer->offset + bytes_to_send; + buffer->len = buffer->len - bytes_to_send; + + /* the last data chunk */ + if (bytes_to_send == buf_len) { + buffer->ptr = NULL; + buffer->offset = 0; + buffer->len = 0; + GST_OBJECT_LOCK (sink); + gst_curl_sink_data_sent_notify_unlocked (sink); + GST_OBJECT_UNLOCK (sink); + } + + GST_LOG ("sent : %d (%x)", bytes_to_send, bytes_to_send); + + return bytes_to_send; + } else { + GST_WARNING ("got zero-length buffer"); + return 0; + } +} + +static size_t +gst_curl_sink_transfer_write_cb (void G_GNUC_UNUSED * ptr, size_t size, + size_t nmemb, void G_GNUC_UNUSED * stream) +{ + size_t realsize = size * nmemb; + + GST_DEBUG ("response %s", (gchar *) ptr); + return realsize; +} + +static CURLcode +gst_curl_sink_transfer_check (GstCurlSink * sink) +{ + CURLcode code = CURLE_OK; + CURL *easy; + CURLMsg *msg; + gint msgs_left; + gchar *eff_url = NULL; + + do { + easy = NULL; + while ((msg = curl_multi_info_read (sink->priv->multi_handle, &msgs_left))) { + if (msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + code = msg->data.result; + break; + } + } + if (easy) { + curl_easy_getinfo (easy, CURLINFO_EFFECTIVE_URL, &eff_url); + GST_DEBUG ("transfer done %s (%s-%d)\n", eff_url, + curl_easy_strerror (code), code); + } + } while (easy); + + return code; +} + +static GstFlowReturn +gst_curl_sink_handle_transfer (GstCurlSink * sink) +{ + gint retval; + gint running_handles; + gint timeout; + CURLMcode m_code; + CURLcode e_code; + glong resp = -1; + glong resp_proxy = -1; + + GST_OBJECT_LOCK (sink); + timeout = sink->priv->timeout; + GST_OBJECT_UNLOCK (sink); + + /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data + available to send or receive - call simply curl_multi_perform before + poll() on more actions */ + do { + m_code = curl_multi_perform (sink->priv->multi_handle, &running_handles); + } while (m_code == CURLM_CALL_MULTI_PERFORM); + + while (running_handles && (m_code == CURLM_OK)) { + if (!proxy_conn_established && (resp_proxy != RESPONSE_CONNECT_PROXY) + && proxy_auth) { + curl_easy_getinfo (sink->priv->curl, CURLINFO_HTTP_CONNECTCODE, + &resp_proxy); + if ((resp_proxy == RESPONSE_CONNECT_PROXY)) { + GST_LOG ("received HTTP/1.0 200 Connection Established"); + /* Workaround: redefine HTTP headers before connecting to HTTP server. + * When talking to proxy, the Content-Length: 0 is send with the request. + */ + curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + gst_curl_sink_set_http_header_unlocked (sink); + curl_multi_add_handle (sink->priv->multi_handle, sink->priv->curl); + proxy_conn_established = TRUE; + } + } + + retval = gst_poll_wait (sink->priv->fdset, timeout * GST_SECOND); + if (G_UNLIKELY (retval == -1)) { + if (errno == EAGAIN || errno == EINTR) { + GST_DEBUG_OBJECT (sink, "interrupted by signal"); + } else if (errno == EBUSY) { + goto poll_stopped; + } else { + goto poll_error; + } + } else if (G_UNLIKELY (retval == 0)) { + GST_DEBUG ("timeout"); + goto poll_timeout; + } + + /* readable/writable sockets */ + do { + m_code = curl_multi_perform (sink->priv->multi_handle, &running_handles); + } while (m_code == CURLM_CALL_MULTI_PERFORM); + + if (resp != RESPONSE_100_CONTINUE) { + curl_easy_getinfo (sink->priv->curl, CURLINFO_RESPONSE_CODE, &resp); + } + } + + if (resp != RESPONSE_100_CONTINUE) { + /* No 100 Continue response received. Using POST with HTTP 1.1 implies + * the use of a "Expect: 100-continue" header. If the server doesn't + * send HTTP/1.1 100 Continue, libcurl will not call transfer_read_cb + * in order to send POST data. + */ + goto no_100_continue_response; + } + + if (m_code != CURLM_OK) { + goto curl_multi_error; + } + + /* problems still might have occurred on individual transfers even when + * curl_multi_perform returns CURLM_OK */ + if ((e_code = gst_curl_sink_transfer_check (sink)) != CURLE_OK) { + goto curl_easy_error; + } + + /* check response code */ + curl_easy_getinfo (sink->priv->curl, CURLINFO_RESPONSE_CODE, &resp); + GST_DEBUG_OBJECT (sink, "response code: %d", resp); + if (resp < 200 || resp >= 300) { + goto response_error; + } + + return GST_FLOW_OK; + +poll_error: + { + GST_DEBUG_OBJECT (sink, "poll failed: %s", g_strerror (errno)); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("poll failed"), (NULL)); + return GST_FLOW_ERROR; + } + +poll_stopped: + { + GST_DEBUG_OBJECT (sink, "poll stopped"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("poll stopped"), (NULL)); + return GST_FLOW_ERROR; + } + +poll_timeout: + { + GST_DEBUG_OBJECT (sink, "poll timed out"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("poll timed out"), (NULL)); + return GST_FLOW_ERROR; + } + +curl_multi_error: + { + GST_DEBUG_OBJECT (sink, "curl multi error"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (curl_multi_strerror (m_code)), + (NULL)); + return GST_FLOW_ERROR; + } + +curl_easy_error: + { + GST_DEBUG_OBJECT (sink, "curl easy error"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (curl_easy_strerror (e_code)), + (NULL)); + return GST_FLOW_ERROR; + } + +no_100_continue_response: + { + GST_DEBUG_OBJECT (sink, "100 continue response missing"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("100 continue response missing"), + (NULL)); + return GST_FLOW_ERROR; + } + +response_error: + { + GST_DEBUG_OBJECT (sink, "response error"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("response error: %ld", resp), + (NULL)); + return GST_FLOW_ERROR; + } +} + +/* This function gets called by libcurl after the socket() call but before + * the connect() call. */ +static int +gst_curl_sink_transfer_socket_cb (void *clientp, curl_socket_t curlfd, + curlsocktype G_GNUC_UNUSED purpose) +{ + GstCurlSink *sink; + gboolean ret = TRUE; + + sink = (GstCurlSink *) clientp; + + g_assert (sink); + + if (curlfd < 0) { + /* signal an unrecoverable error to the library which will close the socket + and return CURLE_COULDNT_CONNECT + */ + return 1; + } + + gst_poll_fd_init (&sink->priv->fd); + sink->priv->fd.fd = curlfd; + + ret = ret && gst_poll_add_fd (sink->priv->fdset, &sink->priv->fd); + ret = ret && gst_poll_fd_ctl_write (sink->priv->fdset, &sink->priv->fd, TRUE); + ret = ret && gst_poll_fd_ctl_read (sink->priv->fdset, &sink->priv->fd, TRUE); + GST_DEBUG ("fd: %d", sink->priv->fd.fd); + GST_OBJECT_LOCK (sink); + gst_curl_sink_setup_dscp_unlocked (sink); + GST_OBJECT_UNLOCK (sink); + + /* success */ + if (ret) { + return 0; + } else { + return 1; + } +} + +static gboolean +gst_curl_sink_transfer_start_unlocked (GstCurlSink * sink) +{ + GError *error = NULL; + gboolean ret = TRUE; + + GST_LOG ("creating transfer thread"); + sink->priv->transfer_thread_close = FALSE; + sink->priv->new_file = TRUE; + sink->priv->transfer_thread = + g_thread_create ((GThreadFunc) gst_curl_sink_transfer_thread_func, sink, + TRUE, &error); + + if (sink->priv->transfer_thread == NULL || error != NULL) { + ret = FALSE; + if (error) { + GST_ERROR_OBJECT (sink, "could not create thread %s", error->message); + g_error_free (error); + } else { + GST_ERROR_OBJECT (sink, "could not create thread for unknown reason"); + } + } + + return ret; +} + +static gpointer +gst_curl_sink_transfer_thread_func (gpointer data) +{ + GstCurlSink *sink = (GstCurlSink *) data; + GstFlowReturn ret = GST_FLOW_OK; + gboolean data_available; + + GST_LOG ("transfer thread started"); + GST_OBJECT_LOCK (sink); + if (!gst_curl_sink_transfer_setup_unlocked (sink)) { + GST_DEBUG_OBJECT (sink, "curl setup error"); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("curl setup error"), (NULL)); + sink->priv->flow_ret = GST_FLOW_ERROR; + goto done; + } + + while (!sink->priv->transfer_thread_close && + sink->priv->flow_ret == GST_FLOW_OK) { + /* we are working on a new file, clearing flag and setting file + * name in http header */ + sink->priv->new_file = FALSE; + + /* wait for data to arrive for this new file, if we get a new file name + * again before getting data we will simply skip transfering anything + * for this file and go directly to the new file */ + data_available = gst_curl_sink_wait_for_data_unlocked (sink); + if (data_available) { + gst_curl_sink_set_http_header_unlocked (sink); + } + + /* stay unlocked while handling the actual transfer */ + GST_OBJECT_UNLOCK (sink); + + if (data_available) { + curl_multi_add_handle (sink->priv->multi_handle, sink->priv->curl); + + /* Start driving the transfer. */ + ret = gst_curl_sink_handle_transfer (sink); + + /* easy handle will be possibly re-used for next transfer, thus it needs to + * be removed from the multi stack and re-added again */ + curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + } + + /* lock again before looping to check the thread closed flag */ + GST_OBJECT_LOCK (sink); + + /* if we have transfered data, then set the return code */ + if (data_available) { + sink->priv->flow_ret = ret; + } + } + +done: + /* if there is a flow error, always notify the render function so it + * can return the flow error up along the pipeline */ + if (sink->priv->flow_ret != GST_FLOW_OK) { + gst_curl_sink_data_sent_notify_unlocked (sink); + } + + GST_OBJECT_UNLOCK (sink); + GST_DEBUG ("exit thread func - transfer thread close flag: %d", + sink->priv->transfer_thread_close); + + return NULL; +} + +static gboolean +gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink) +{ + g_assert (sink); + + if (sink->priv->curl == NULL) { + /* curl_easy_init automatically calls curl_global_init(3) */ + if ((sink->priv->curl = curl_easy_init ()) == NULL) { + g_warning ("Failed to init easy handle"); + return FALSE; + } + } + + if (!gst_curl_sink_transfer_set_options_unlocked (sink)) { + g_warning ("Failed to setup easy handle"); + GST_OBJECT_UNLOCK (sink); + return FALSE; + } + + /* init a multi stack (non-blocking interface to liburl) */ + if (sink->priv->multi_handle == NULL) { + if ((sink->priv->multi_handle = curl_multi_init ()) == NULL) { + return FALSE; + } + } + + return TRUE; +} + +static void +gst_curl_sink_transfer_cleanup (GstCurlSink * sink) +{ + if (sink->priv->curl != NULL) { + if (sink->priv->multi_handle != NULL) { + curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + } + curl_easy_cleanup (sink->priv->curl); + sink->priv->curl = NULL; + } + + if (sink->priv->multi_handle != NULL) { + curl_multi_cleanup (sink->priv->multi_handle); + sink->priv->multi_handle = NULL; + } +} + +static gboolean +gst_curl_sink_wait_for_data_unlocked (GstCurlSink * sink) +{ + gboolean data_available = FALSE; + + GST_LOG ("waiting for data"); + while (!sink->priv->transfer_cond->data_available && + !sink->priv->transfer_thread_close && !sink->priv->new_file) { + g_cond_wait (sink->priv->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); + } + + if (sink->priv->transfer_thread_close) { + GST_LOG ("wait for data aborted due to thread close"); + } else if (sink->priv->new_file) { + GST_LOG ("wait for data aborted due to new file name"); + } else { + GST_LOG ("wait for data completed"); + data_available = TRUE; + } + + return data_available; +} + +static void +gst_curl_sink_transfer_thread_notify_unlocked (GstCurlSink * sink) +{ + GST_LOG ("more data to send"); + sink->priv->transfer_cond->data_available = TRUE; + sink->priv->transfer_cond->data_sent = FALSE; + g_cond_signal (sink->priv->transfer_cond->cond); +} + +static void +gst_curl_sink_new_file_notify_unlocked (GstCurlSink * sink) +{ + GST_LOG ("new file name"); + sink->priv->new_file = TRUE; + g_cond_signal (sink->priv->transfer_cond->cond); +} + +static void +gst_curl_sink_transfer_thread_close_unlocked (GstCurlSink * sink) +{ + GST_LOG ("setting transfer thread close flag"); + sink->priv->transfer_thread_close = TRUE; + g_cond_signal (sink->priv->transfer_cond->cond); +} + +static void +gst_curl_sink_wait_for_transfer_thread_to_send_unlocked (GstCurlSink * sink) +{ + GST_LOG ("waiting for buffer send to complete"); + + /* this function should not check if the transfer thread is set to be closed + * since that flag only can be set by the EoS event (by the pipeline thread). + * This can therefore never happen while this function is running since this + * function also is called by the pipeline thread (in the render function) */ + while (!sink->priv->transfer_cond->data_sent) { + g_cond_wait (sink->priv->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); + } + GST_LOG ("buffer send completed"); +} + +static void +gst_curl_sink_data_sent_notify_unlocked (GstCurlSink * sink) +{ + GST_LOG ("transfer completed"); + sink->priv->transfer_cond->data_available = FALSE; + sink->priv->transfer_cond->data_sent = TRUE; + g_cond_signal (sink->priv->transfer_cond->cond); +} + +static gint +gst_curl_sink_setup_dscp_unlocked (GstCurlSink * sink) +{ + gint tos; + gint af; + gint ret = -1; + union + { + struct sockaddr sa; + struct sockaddr_in6 sa_in6; + struct sockaddr_storage sa_stor; + } sa; + socklen_t slen = sizeof (sa); + + if (getsockname (sink->priv->fd.fd, &sa.sa, &slen) < 0) { + GST_DEBUG_OBJECT (sink, "could not get sockname: %s", g_strerror (errno)); + return ret; + } + af = sa.sa.sa_family; + + /* if this is an IPv4-mapped address then do IPv4 QoS */ + if (af == AF_INET6) { + GST_DEBUG_OBJECT (sink, "check IP6 socket"); + if (IN6_IS_ADDR_V4MAPPED (&(sa.sa_in6.sin6_addr))) { + GST_DEBUG_OBJECT (sink, "mapped to IPV4"); + af = AF_INET; + } + } + /* extract and shift 6 bits of the DSCP */ + tos = (sink->priv->qos_dscp & 0x3f) << 2; + + switch (af) { + case AF_INET: + ret = setsockopt (sink->priv->fd.fd, IPPROTO_IP, IP_TOS, &tos, + sizeof (tos)); + break; + case AF_INET6: +#ifdef IPV6_TCLASS + ret = setsockopt (sink->priv->fd.fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, + sizeof (tos)); + break; +#endif + default: + GST_ERROR_OBJECT (sink, "unsupported AF"); + break; + } + if (ret) { + GST_DEBUG_OBJECT (sink, "could not set DSCP: %s", g_strerror (errno)); + } + + return ret; +} diff --git a/ext/curl/gstcurlsink.h b/ext/curl/gstcurlsink.h new file mode 100644 index 0000000000..1a49e21c6d --- /dev/null +++ b/ext/curl/gstcurlsink.h @@ -0,0 +1,106 @@ +/* GStreamer + * Copyright (C) 2011 Axis Communications + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_CURL_SINK__ +#define __GST_CURL_SINK__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_CURL_SINK \ + (gst_curl_sink_get_type()) +#define GST_CURL_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CURL_SINK, GstCurlSink)) +#define GST_CURL_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CURL_SINK, GstCurlSinkClass)) +#define GST_IS_CURL_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CURL_SINK)) +#define GST_IS_CURL_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CURL_SINK)) + +typedef struct _GstCurlSink GstCurlSink; +typedef struct _GstCurlSinkClass GstCurlSinkClass; +typedef struct _GstCurlSinkPrivate GstCurlSinkPrivate; + +typedef struct _TransferBuffer TransferBuffer; +typedef struct _TransferCondition TransferCondition; + +struct _TransferBuffer { + guint8 *ptr; + size_t len; + size_t offset; +}; + +struct _TransferCondition { + GCond *cond; + gboolean data_sent; + gboolean data_available; +}; + +struct _GstCurlSinkPrivate +{ + CURLM *multi_handle; + CURL *curl; + struct curl_slist *header_list; + GstPollFD fd; + GstPoll *fdset; + GThread *transfer_thread; + GstFlowReturn flow_ret; + TransferBuffer *transfer_buf; + TransferCondition *transfer_cond; + gint num_buffers_per_packet; + gint timeout; + gchar *url; + gchar *user; + gchar *passwd; + gchar *proxy; + guint proxy_port; + gchar *proxy_user; + gchar *proxy_passwd; + gchar *file_name; + guint qos_dscp; + gboolean accept_self_signed; + gboolean use_content_length; + gboolean transfer_thread_close; + gboolean new_file; + gchar *content_type; + gboolean proxy_headers_set; +}; + +struct _GstCurlSink +{ + GstBaseSink parent; + + /*< private >*/ + GstCurlSinkPrivate *priv; +}; + +struct _GstCurlSinkClass +{ + GstBaseSinkClass parent_class; +}; + +GType gst_curl_sink_get_type (void); + +G_END_DECLS + +#endif From 56c2cc0f83ce93de97714b119e478960d5dbb02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Sat, 26 Feb 2011 20:21:25 +0000 Subject: [PATCH 06/20] curl: add configure check and hook up to build system --- configure.ac | 13 +++++++++++++ ext/Makefile.am | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/configure.ac b/configure.ac index b88f328561..27e2013c18 100644 --- a/configure.ac +++ b/configure.ac @@ -653,6 +653,17 @@ AG_GST_CHECK_FEATURE(COG, [Cog plugin], cog, [ AC_SUBST(COG_LIBS) ]) +dnl *** Curl *** +translit(dnm, m, l) AM_CONDITIONAL(USE_CURL, true) +AG_GST_CHECK_FEATURE(CURL, [Curl plugin], curl, [ + PKG_CHECK_MODULES(CURL, libcurl >= 7.21.0, HAVE_CURL="yes", [ + HAVE_CURL="no" + AC_MSG_RESULT(no) + ]) + AC_SUBST(CURL_CFLAGS) + AC_SUBST(CURL_LIBS) +]) + dnl *** dc1394 *** translit(dnm, m, l) AM_CONDITIONAL(USE_DC1394, true) AG_GST_CHECK_FEATURE(DC1394, [libdc1394], dc1394, [ @@ -1592,6 +1603,7 @@ AM_CONDITIONAL(USE_BZ2, false) AM_CONDITIONAL(USE_CDAUDIO, false) AM_CONDITIONAL(USE_CELT, false) AM_CONDITIONAL(USE_COG, false) +AM_CONDITIONAL(USE_CURL, false) AM_CONDITIONAL(USE_DC1394, false) AM_CONDITIONAL(USE_DIRECTFB, false) AM_CONDITIONAL(USE_DIRAC, false) @@ -1828,6 +1840,7 @@ ext/bz2/Makefile ext/cdaudio/Makefile ext/celt/Makefile ext/cog/Makefile +ext/curl/Makefile ext/dc1394/Makefile ext/dirac/Makefile ext/directfb/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index 9b670d4dbb..f9b55ea522 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -64,6 +64,12 @@ else COG_DIR= endif +if USE_CURL +CURL_DIR=curl +else +CURL_DIR= +endif + if USE_DC1394 DC1394_DIR=dc1394 else @@ -379,6 +385,7 @@ SUBDIRS=\ $(CDAUDIO_DIR) \ $(CELT_DIR) \ $(COG_DIR) \ + $(CURL_DIR) \ $(DC1394_DIR) \ $(DIRAC_DIR) \ $(DIRECTFB_DIR) \ From 6f01abd85df9edf2a4592d83cb52fe9ef12f8bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Mar 2011 09:56:51 +0000 Subject: [PATCH 07/20] curlsink: clean up property registration code Fix some typos, use same style as in all other plugins, avoiding unnecessary temporary GParamSpec variables; use G_PARAM_SPEC_STATIC_STRINGS. --- ext/curl/gstcurlsink.c | 143 ++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 89 deletions(-) diff --git a/ext/curl/gstcurlsink.c b/ext/curl/gstcurlsink.c index 8a4c7643f3..80d4e0d268 100644 --- a/ext/curl/gstcurlsink.c +++ b/ext/curl/gstcurlsink.c @@ -138,7 +138,8 @@ gst_curl_sink_base_init (gpointer g_class) gst_element_class_set_details_simple (element_class, "Curl sink", "Sink/Network", - "Send over network using curl", "Patricia Muscalu "); + "Upload data over the network to a server using libcurl", + "Patricia Muscalu "); } static void @@ -146,79 +147,6 @@ gst_curl_sink_class_init (GstCurlSinkClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass; - GParamSpec *loc_prspec = g_param_spec_string ("location", - "Location", - "URI location to write to", - NULL, - G_PARAM_READWRITE); - GParamSpec *user_prspec = g_param_spec_string ("user", - "User nanme)", - "User name to use for server authentication", - NULL, - G_PARAM_READWRITE); - GParamSpec *passwd_prspec = g_param_spec_string ("passwd", - "User password)", - "User password to use for server authentication", - NULL, - G_PARAM_READWRITE); - GParamSpec *proxy_prspec = g_param_spec_string ("proxy", - "proxy", - "HTTP proxy server URI", - NULL, - G_PARAM_READWRITE); - - GParamSpec *proxy_port_prspec = g_param_spec_int ("proxy-port", - "proxy port", - "HTTP proxy server port", - 0, - G_MAXINT, - DEFAULT_PROXY_PORT, - G_PARAM_READWRITE); - GParamSpec *proxy_user_prspec = g_param_spec_string ("proxy-user", - "Proxy user name)", - "Proxy user name to use for proxy authentication", - NULL, - G_PARAM_READWRITE); - GParamSpec *proxy_passwd_prspec = g_param_spec_string ("proxy-passwd", - "Prpxu user password)", - "Proxy user password to use for proxy authentication", - NULL, - G_PARAM_READWRITE); - GParamSpec *file_name_prspec = g_param_spec_string ("file-name", - "Base file name", - "The base file name for the uploaded images", - NULL, - G_PARAM_READWRITE); - - GParamSpec *timeout_prspec = g_param_spec_int ("timeout", - "timeout", - "Number of seconds waiting to write before timeout", - 0, - G_MAXINT, - DEFAULT_TIMEOUT, - G_PARAM_READWRITE); - GParamSpec *qos_dscp_prspec = g_param_spec_int ("qos-dscp", - "QoS diff srv code point", - "Quality of Service, differentiated services code point (0 default)", - DSCP_MIN, - DSCP_MAX, - DEFAULT_QOS_DSCP, - G_PARAM_READWRITE); - GParamSpec *self_cert_prspec = g_param_spec_boolean ("accept-self-signed", - "Accept self-signed certificates", - "Accept self-signed SSL/TLS certificates", - DEFAULT_ACCEPT_SELF_SIGNED, - G_PARAM_READWRITE); - GParamSpec *content_lngth_prspec = g_param_spec_boolean ("use-content-length", - "Use content length header", - "Use the Content-Length HTTP header instead of Transfer-Encoding header", - DEFAULT_USE_CONTENT_LENGTH, - G_PARAM_READWRITE); - GParamSpec *content_type_prspec = g_param_spec_string ("content-type", - "Content type header)", - "The mime type of the body of the request", - NULL, - G_PARAM_READWRITE); GST_DEBUG_OBJECT (klass, "class_init"); @@ -231,30 +159,67 @@ gst_curl_sink_class_init (GstCurlSinkClass * klass) GST_DEBUG_FUNCPTR (gst_curl_sink_unlock_stop); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_curl_sink_finalize); - gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_curl_sink_set_property); - gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_curl_sink_get_property); - g_object_class_install_property (gobject_class, PROP_LOCATION, loc_prspec); - g_object_class_install_property (gobject_class, PROP_USER_NAME, user_prspec); + gobject_class->set_property = gst_curl_sink_set_property; + gobject_class->get_property = gst_curl_sink_get_property; + + /* FIXME: check against souphttpsrc and use same names for same properties */ + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "Location", + "URI location to write to", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_USER_NAME, + g_param_spec_string ("user", "User name", + "User name to use for server authentication", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_USER_PASSWD, - passwd_prspec); - g_object_class_install_property (gobject_class, PROP_PROXY, proxy_prspec); + g_param_spec_string ("passwd", "User password", + "User password to use for server authentication", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PROXY, + g_param_spec_string ("proxy", "Proxy", "HTTP proxy server URI", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PROXY_PORT, - proxy_port_prspec); + g_param_spec_int ("proxy-port", "Proxy port", + "HTTP proxy server port", 0, G_MAXINT, DEFAULT_PROXY_PORT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PROXY_USER_NAME, - proxy_user_prspec); + g_param_spec_string ("proxy-user", "Proxy user name", + "Proxy user name to use for proxy authentication", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_PROXY_USER_PASSWD, - proxy_passwd_prspec); + g_param_spec_string ("proxy-passwd", "Proxy user password", + "Proxy user password to use for proxy authentication", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_FILE_NAME, - file_name_prspec); - g_object_class_install_property (gobject_class, PROP_TIMEOUT, timeout_prspec); + g_param_spec_string ("file-name", "Base file name", + "The base file name for the uploaded images", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_int ("timeout", "Timeout", + "Number of seconds waiting to write before timeout", + 0, G_MAXINT, DEFAULT_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_QOS_DSCP, - qos_dscp_prspec); + g_param_spec_int ("qos-dscp", + "QoS diff srv code point", + "Quality of Service, differentiated services code point (0 default)", + DSCP_MIN, DSCP_MAX, DEFAULT_QOS_DSCP, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_ACCEPT_SELF_SIGNED, - self_cert_prspec); + g_param_spec_boolean ("accept-self-signed", + "Accept self-signed certificates", + "Accept self-signed SSL/TLS certificates", + DEFAULT_ACCEPT_SELF_SIGNED, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_USE_CONTENT_LENGTH, - content_lngth_prspec); + g_param_spec_boolean ("use-content-length", "Use content length header", + "Use the Content-Length HTTP header instead of " + "Transfer-Encoding header", DEFAULT_USE_CONTENT_LENGTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE, - content_type_prspec); + g_param_spec_string ("content-type", "Content type", + "The mime type of the body of the request", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (klass, sizeof (GstCurlSinkPrivate)); } From eb5b3be384fca545273f4eeaeea47d28d9d2e2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Mar 2011 10:03:07 +0000 Subject: [PATCH 08/20] curlsink: no need for a private instance structure The entire instance structure is private anyway. --- ext/curl/gstcurlsink.c | 451 ++++++++++++++++++++--------------------- ext/curl/gstcurlsink.h | 14 +- 2 files changed, 219 insertions(+), 246 deletions(-) diff --git a/ext/curl/gstcurlsink.c b/ext/curl/gstcurlsink.c index 80d4e0d268..77fa1c483e 100644 --- a/ext/curl/gstcurlsink.c +++ b/ext/curl/gstcurlsink.c @@ -220,32 +220,27 @@ gst_curl_sink_class_init (GstCurlSinkClass * klass) g_param_spec_string ("content-type", "Content type", "The mime type of the body of the request", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_type_class_add_private (klass, sizeof (GstCurlSinkPrivate)); } static void gst_curl_sink_init (GstCurlSink * sink, GstCurlSinkClass * klass) { - sink->priv = G_TYPE_INSTANCE_GET_PRIVATE (sink, GST_TYPE_CURL_SINK, - GstCurlSinkPrivate); - - sink->priv->transfer_buf = g_malloc (sizeof (TransferBuffer)); - sink->priv->transfer_cond = g_malloc (sizeof (TransferCondition)); - sink->priv->transfer_cond->cond = g_cond_new (); - sink->priv->transfer_cond->data_sent = FALSE; - sink->priv->transfer_cond->data_available = FALSE; - sink->priv->timeout = DEFAULT_TIMEOUT; - sink->priv->proxy_port = DEFAULT_PROXY_PORT; - sink->priv->qos_dscp = DEFAULT_QOS_DSCP; - sink->priv->url = g_strdup (DEFAULT_URL); - sink->priv->header_list = NULL; - sink->priv->accept_self_signed = DEFAULT_ACCEPT_SELF_SIGNED; - sink->priv->use_content_length = DEFAULT_USE_CONTENT_LENGTH; - sink->priv->transfer_thread_close = FALSE; - sink->priv->new_file = TRUE; - sink->priv->proxy_headers_set = FALSE; - sink->priv->content_type = NULL; + sink->transfer_buf = g_malloc (sizeof (TransferBuffer)); + sink->transfer_cond = g_malloc (sizeof (TransferCondition)); + sink->transfer_cond->cond = g_cond_new (); + sink->transfer_cond->data_sent = FALSE; + sink->transfer_cond->data_available = FALSE; + sink->timeout = DEFAULT_TIMEOUT; + sink->proxy_port = DEFAULT_PROXY_PORT; + sink->qos_dscp = DEFAULT_QOS_DSCP; + sink->url = g_strdup (DEFAULT_URL); + sink->header_list = NULL; + sink->accept_self_signed = DEFAULT_ACCEPT_SELF_SIGNED; + sink->use_content_length = DEFAULT_USE_CONTENT_LENGTH; + sink->transfer_thread_close = FALSE; + sink->new_file = TRUE; + sink->proxy_headers_set = FALSE; + sink->content_type = NULL; } static void @@ -254,33 +249,33 @@ gst_curl_sink_finalize (GObject * gobject) GstCurlSink *this = GST_CURL_SINK (gobject); GST_DEBUG ("finalizing curlsink"); - if (this->priv->transfer_thread != NULL) { - g_thread_join (this->priv->transfer_thread); + if (this->transfer_thread != NULL) { + g_thread_join (this->transfer_thread); } gst_curl_sink_transfer_cleanup (this); - g_cond_free (this->priv->transfer_cond->cond); - g_free (this->priv->transfer_cond); + g_cond_free (this->transfer_cond->cond); + g_free (this->transfer_cond); - g_free (this->priv->transfer_buf); + g_free (this->transfer_buf); - g_free (this->priv->url); - g_free (this->priv->user); - g_free (this->priv->passwd); - g_free (this->priv->proxy); - g_free (this->priv->proxy_user); - g_free (this->priv->proxy_passwd); - g_free (this->priv->file_name); - g_free (this->priv->content_type); + g_free (this->url); + g_free (this->user); + g_free (this->passwd); + g_free (this->proxy); + g_free (this->proxy_user); + g_free (this->proxy_passwd); + g_free (this->file_name); + g_free (this->content_type); - if (this->priv->header_list) { - curl_slist_free_all (this->priv->header_list); - this->priv->header_list = NULL; + if (this->header_list) { + curl_slist_free_all (this->header_list); + this->header_list = NULL; } - if (this->priv->fdset != NULL) { - gst_poll_free (this->priv->fdset); - this->priv->fdset = NULL; + if (this->fdset != NULL) { + gst_poll_free (this->fdset); + this->fdset = NULL; } G_OBJECT_CLASS (parent_class)->finalize (gobject); } @@ -299,7 +294,7 @@ gst_curl_sink_render (GstBaseSink * bsink, GstBuffer * buf) data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); - if (sink->priv->content_type == NULL) { + if (sink->content_type == NULL) { GstCaps *caps; GstStructure *structure; const gchar *mime_type; @@ -307,31 +302,31 @@ gst_curl_sink_render (GstBaseSink * bsink, GstBuffer * buf) caps = buf->caps; structure = gst_caps_get_structure (caps, 0); mime_type = gst_structure_get_name (structure); - sink->priv->content_type = g_strdup (mime_type); + sink->content_type = g_strdup (mime_type); } GST_OBJECT_LOCK (sink); /* check if the transfer thread has encountered problems while the * pipeline thread was working elsewhere */ - if (sink->priv->flow_ret != GST_FLOW_OK) { + if (sink->flow_ret != GST_FLOW_OK) { goto done; } - g_assert (sink->priv->transfer_cond->data_available == FALSE); + g_assert (sink->transfer_cond->data_available == FALSE); /* if there is no transfer thread created, lets create one */ - if (sink->priv->transfer_thread == NULL) { + if (sink->transfer_thread == NULL) { if (!gst_curl_sink_transfer_start_unlocked (sink)) { - sink->priv->flow_ret = GST_FLOW_ERROR; + sink->flow_ret = GST_FLOW_ERROR; goto done; } } /* make data available for the transfer thread and notify */ - sink->priv->transfer_buf->ptr = data; - sink->priv->transfer_buf->len = size; - sink->priv->transfer_buf->offset = 0; + sink->transfer_buf->ptr = data; + sink->transfer_buf->len = size; + sink->transfer_buf->offset = 0; gst_curl_sink_transfer_thread_notify_unlocked (sink); /* wait for the transfer thread to send the data. This will be notified @@ -340,7 +335,7 @@ gst_curl_sink_render (GstBaseSink * bsink, GstBuffer * buf) gst_curl_sink_wait_for_transfer_thread_to_send_unlocked (sink); done: - ret = sink->priv->flow_ret; + ret = sink->flow_ret; GST_OBJECT_UNLOCK (sink); GST_LOG ("exit render"); @@ -359,9 +354,9 @@ gst_curl_sink_event (GstBaseSink * bsink, GstEvent * event) GST_OBJECT_LOCK (sink); gst_curl_sink_transfer_thread_close_unlocked (sink); GST_OBJECT_UNLOCK (sink); - if (sink->priv->transfer_thread != NULL) { - g_thread_join (sink->priv->transfer_thread); - sink->priv->transfer_thread = NULL; + if (sink->transfer_thread != NULL) { + g_thread_join (sink->transfer_thread); + sink->transfer_thread = NULL; } break; default: @@ -377,7 +372,7 @@ gst_curl_sink_start (GstBaseSink * bsink) sink = GST_CURL_SINK (bsink); - if ((sink->priv->fdset = gst_poll_new (TRUE)) == NULL) { + if ((sink->fdset = gst_poll_new (TRUE)) == NULL) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("gst_poll_new failed: %s", g_strerror (errno)), (NULL)); return FALSE; @@ -394,9 +389,9 @@ gst_curl_sink_stop (GstBaseSink * bsink) GST_OBJECT_LOCK (sink); gst_curl_sink_transfer_thread_close_unlocked (sink); GST_OBJECT_UNLOCK (sink); - if (sink->priv->fdset != NULL) { - gst_poll_free (sink->priv->fdset); - sink->priv->fdset = NULL; + if (sink->fdset != NULL) { + gst_poll_free (sink->fdset); + sink->fdset = NULL; } return TRUE; @@ -410,7 +405,7 @@ gst_curl_sink_unlock (GstBaseSink * bsink) sink = GST_CURL_SINK (bsink); GST_LOG_OBJECT (sink, "Flushing"); - gst_poll_set_flushing (sink->priv->fdset, TRUE); + gst_poll_set_flushing (sink->fdset, TRUE); return TRUE; } @@ -423,7 +418,7 @@ gst_curl_sink_unlock_stop (GstBaseSink * bsink) sink = GST_CURL_SINK (bsink); GST_LOG_OBJECT (sink, "No longer flushing"); - gst_poll_set_flushing (sink->priv->fdset, FALSE); + gst_poll_set_flushing (sink->fdset, FALSE); return TRUE; } @@ -444,69 +439,67 @@ gst_curl_sink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_LOCATION: - g_free (sink->priv->url); - sink->priv->url = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "url set to %s", sink->priv->url); + g_free (sink->url); + sink->url = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "url set to %s", sink->url); break; case PROP_USER_NAME: - g_free (sink->priv->user); - sink->priv->user = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "user set to %s", sink->priv->user); + g_free (sink->user); + sink->user = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "user set to %s", sink->user); break; case PROP_USER_PASSWD: - g_free (sink->priv->passwd); - sink->priv->passwd = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->priv->passwd); + g_free (sink->passwd); + sink->passwd = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->passwd); break; case PROP_PROXY: - g_free (sink->priv->proxy); - sink->priv->proxy = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "proxy set to %s", sink->priv->proxy); + g_free (sink->proxy); + sink->proxy = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy set to %s", sink->proxy); break; case PROP_PROXY_PORT: - sink->priv->proxy_port = g_value_get_int (value); - GST_DEBUG_OBJECT (sink, "proxy port set to %d", sink->priv->proxy_port); + sink->proxy_port = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "proxy port set to %d", sink->proxy_port); break; case PROP_PROXY_USER_NAME: - g_free (sink->priv->proxy_user); - sink->priv->proxy_user = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "proxy user set to %s", sink->priv->proxy_user); + g_free (sink->proxy_user); + sink->proxy_user = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy user set to %s", sink->proxy_user); break; case PROP_PROXY_USER_PASSWD: - g_free (sink->priv->proxy_passwd); - sink->priv->proxy_passwd = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "proxy password set to %s", - sink->priv->proxy_passwd); + g_free (sink->proxy_passwd); + sink->proxy_passwd = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "proxy password set to %s", sink->proxy_passwd); break; case PROP_FILE_NAME: - g_free (sink->priv->file_name); - sink->priv->file_name = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->priv->file_name); + g_free (sink->file_name); + sink->file_name = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); break; case PROP_TIMEOUT: - sink->priv->timeout = g_value_get_int (value); - GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->priv->timeout); + sink->timeout = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: - sink->priv->qos_dscp = g_value_get_int (value); + sink->qos_dscp = g_value_get_int (value); gst_curl_sink_setup_dscp_unlocked (sink); - GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->priv->qos_dscp); + GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; case PROP_ACCEPT_SELF_SIGNED: - sink->priv->accept_self_signed = g_value_get_boolean (value); + sink->accept_self_signed = g_value_get_boolean (value); GST_DEBUG_OBJECT (sink, "accept_self_signed set to %d", - sink->priv->accept_self_signed); + sink->accept_self_signed); break; case PROP_USE_CONTENT_LENGTH: - sink->priv->use_content_length = g_value_get_boolean (value); + sink->use_content_length = g_value_get_boolean (value); GST_DEBUG_OBJECT (sink, "use_content_length set to %d", - sink->priv->use_content_length); + sink->use_content_length); break; case PROP_CONTENT_TYPE: - g_free (sink->priv->content_type); - sink->priv->content_type = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "content type set to %s", - sink->priv->content_type); + g_free (sink->content_type); + sink->content_type = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "content type set to %s", sink->content_type); break; default: GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id); @@ -523,25 +516,24 @@ gst_curl_sink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_FILE_NAME: - g_free (sink->priv->file_name); - sink->priv->file_name = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->priv->file_name); + g_free (sink->file_name); + sink->file_name = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); gst_curl_sink_new_file_notify_unlocked (sink); break; case PROP_TIMEOUT: - sink->priv->timeout = g_value_get_int (value); - GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->priv->timeout); + sink->timeout = g_value_get_int (value); + GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: - sink->priv->qos_dscp = g_value_get_int (value); + sink->qos_dscp = g_value_get_int (value); gst_curl_sink_setup_dscp_unlocked (sink); - GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->priv->qos_dscp); + GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; case PROP_CONTENT_TYPE: - g_free (sink->priv->content_type); - sink->priv->content_type = g_value_dup_string (value); - GST_DEBUG_OBJECT (sink, "content type set to %s", - sink->priv->content_type); + g_free (sink->content_type); + sink->content_type = g_value_dup_string (value); + GST_DEBUG_OBJECT (sink, "content type set to %s", sink->content_type); break; default: GST_WARNING_OBJECT (sink, "cannot set property when PLAYING"); @@ -562,43 +554,43 @@ gst_curl_sink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_LOCATION: - g_value_set_string (value, sink->priv->url); + g_value_set_string (value, sink->url); break; case PROP_USER_NAME: - g_value_set_string (value, sink->priv->user); + g_value_set_string (value, sink->user); break; case PROP_USER_PASSWD: - g_value_set_string (value, sink->priv->passwd); + g_value_set_string (value, sink->passwd); break; case PROP_PROXY: - g_value_set_string (value, sink->priv->proxy); + g_value_set_string (value, sink->proxy); break; case PROP_PROXY_PORT: - g_value_set_int (value, sink->priv->proxy_port); + g_value_set_int (value, sink->proxy_port); break; case PROP_PROXY_USER_NAME: - g_value_set_string (value, sink->priv->proxy_user); + g_value_set_string (value, sink->proxy_user); break; case PROP_PROXY_USER_PASSWD: - g_value_set_string (value, sink->priv->proxy_passwd); + g_value_set_string (value, sink->proxy_passwd); break; case PROP_FILE_NAME: - g_value_set_string (value, sink->priv->file_name); + g_value_set_string (value, sink->file_name); break; case PROP_TIMEOUT: - g_value_set_int (value, sink->priv->timeout); + g_value_set_int (value, sink->timeout); break; case PROP_QOS_DSCP: - g_value_set_int (value, sink->priv->qos_dscp); + g_value_set_int (value, sink->qos_dscp); break; case PROP_ACCEPT_SELF_SIGNED: - g_value_set_boolean (value, sink->priv->accept_self_signed); + g_value_set_boolean (value, sink->accept_self_signed); break; case PROP_USE_CONTENT_LENGTH: - g_value_set_boolean (value, sink->priv->use_content_length); + g_value_set_boolean (value, sink->use_content_length); break; case PROP_CONTENT_TYPE: - g_value_set_string (value, sink->priv->content_type); + g_value_set_string (value, sink->content_type); break; default: GST_DEBUG_OBJECT (sink, "invalid property id"); @@ -611,111 +603,103 @@ gst_curl_sink_set_http_header_unlocked (GstCurlSink * sink) { gchar *tmp; - if (sink->priv->header_list) { - curl_slist_free_all (sink->priv->header_list); - sink->priv->header_list = NULL; + if (sink->header_list) { + curl_slist_free_all (sink->header_list); + sink->header_list = NULL; } - if (proxy_auth && !sink->priv->proxy_headers_set && !proxy_conn_established) { - sink->priv->header_list = - curl_slist_append (sink->priv->header_list, "Content-Length: 0"); - sink->priv->proxy_headers_set = TRUE; + if (proxy_auth && !sink->proxy_headers_set && !proxy_conn_established) { + sink->header_list = + curl_slist_append (sink->header_list, "Content-Length: 0"); + sink->proxy_headers_set = TRUE; goto set_headers; } - if (sink->priv->use_content_length) { + if (sink->use_content_length) { /* if content length is used we assume that every buffer is one * entire file, which is the case when uploading several jpegs */ - tmp = - g_strdup_printf ("Content-Length: %d", - (int) sink->priv->transfer_buf->len); - sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + tmp = g_strdup_printf ("Content-Length: %d", (int) sink->transfer_buf->len); + sink->header_list = curl_slist_append (sink->header_list, tmp); g_free (tmp); } else { /* when sending a POST request to a HTTP 1.1 server, you can send data * without knowing the size before starting the POST if you use chunked * encoding */ - sink->priv->header_list = curl_slist_append (sink->priv->header_list, + sink->header_list = curl_slist_append (sink->header_list, "Transfer-Encoding: chunked"); } - tmp = g_strdup_printf ("Content-Type: %s", sink->priv->content_type); - sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + tmp = g_strdup_printf ("Content-Type: %s", sink->content_type); + sink->header_list = curl_slist_append (sink->header_list, tmp); g_free (tmp); set_headers: tmp = g_strdup_printf ("Content-Disposition: attachment; filename=" - "\"%s\"", sink->priv->file_name); - sink->priv->header_list = curl_slist_append (sink->priv->header_list, tmp); + "\"%s\"", sink->file_name); + sink->header_list = curl_slist_append (sink->header_list, tmp); g_free (tmp); - curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPHEADER, - sink->priv->header_list); + curl_easy_setopt (sink->curl, CURLOPT_HTTPHEADER, sink->header_list); } static gboolean gst_curl_sink_transfer_set_options_unlocked (GstCurlSink * sink) { #ifdef DEBUG - curl_easy_setopt (sink->priv->curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt (sink->curl, CURLOPT_VERBOSE, 1); #endif - curl_easy_setopt (sink->priv->curl, CURLOPT_URL, sink->priv->url); - curl_easy_setopt (sink->priv->curl, CURLOPT_CONNECTTIMEOUT, - sink->priv->timeout); + curl_easy_setopt (sink->curl, CURLOPT_URL, sink->url); + curl_easy_setopt (sink->curl, CURLOPT_CONNECTTIMEOUT, sink->timeout); - curl_easy_setopt (sink->priv->curl, CURLOPT_SOCKOPTDATA, sink); - curl_easy_setopt (sink->priv->curl, CURLOPT_SOCKOPTFUNCTION, + curl_easy_setopt (sink->curl, CURLOPT_SOCKOPTDATA, sink); + curl_easy_setopt (sink->curl, CURLOPT_SOCKOPTFUNCTION, gst_curl_sink_transfer_socket_cb); - if (sink->priv->user != NULL && strlen (sink->priv->user)) { - curl_easy_setopt (sink->priv->curl, CURLOPT_USERNAME, sink->priv->user); - curl_easy_setopt (sink->priv->curl, CURLOPT_PASSWORD, sink->priv->passwd); - curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); + if (sink->user != NULL && strlen (sink->user)) { + curl_easy_setopt (sink->curl, CURLOPT_USERNAME, sink->user); + curl_easy_setopt (sink->curl, CURLOPT_PASSWORD, sink->passwd); + curl_easy_setopt (sink->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); } - if (sink->priv->accept_self_signed && g_str_has_prefix (sink->priv->url, - "https")) { + if (sink->accept_self_signed && g_str_has_prefix (sink->url, "https")) { /* TODO verify the authenticity of the peer's certificate */ - curl_easy_setopt (sink->priv->curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt (sink->curl, CURLOPT_SSL_VERIFYPEER, 0L); /* TODO check the servers's claimed identity */ - curl_easy_setopt (sink->priv->curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt (sink->curl, CURLOPT_SSL_VERIFYHOST, 0L); } /* proxy settings */ - if (sink->priv->proxy != NULL && strlen (sink->priv->proxy)) { - if (curl_easy_setopt (sink->priv->curl, CURLOPT_PROXY, sink->priv->proxy) + if (sink->proxy != NULL && strlen (sink->proxy)) { + if (curl_easy_setopt (sink->curl, CURLOPT_PROXY, sink->proxy) != CURLE_OK) { return FALSE; } - if (curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYPORT, - sink->priv->proxy_port) + if (curl_easy_setopt (sink->curl, CURLOPT_PROXYPORT, sink->proxy_port) != CURLE_OK) { return FALSE; } - if (sink->priv->proxy_user != NULL && - strlen (sink->priv->proxy_user) && - sink->priv->proxy_passwd != NULL && strlen (sink->priv->proxy_passwd)) { - curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYUSERNAME, - sink->priv->proxy_user); - curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYPASSWORD, - sink->priv->proxy_passwd); - curl_easy_setopt (sink->priv->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + if (sink->proxy_user != NULL && + strlen (sink->proxy_user) && + sink->proxy_passwd != NULL && strlen (sink->proxy_passwd)) { + curl_easy_setopt (sink->curl, CURLOPT_PROXYUSERNAME, sink->proxy_user); + curl_easy_setopt (sink->curl, CURLOPT_PROXYPASSWORD, sink->proxy_passwd); + curl_easy_setopt (sink->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); proxy_auth = TRUE; } /* tunnel all operations through a given HTTP proxy */ - if (curl_easy_setopt (sink->priv->curl, CURLOPT_HTTPPROXYTUNNEL, 1L) + if (curl_easy_setopt (sink->curl, CURLOPT_HTTPPROXYTUNNEL, 1L) != CURLE_OK) { return FALSE; } } /* POST options */ - curl_easy_setopt (sink->priv->curl, CURLOPT_POST, 1L); + curl_easy_setopt (sink->curl, CURLOPT_POST, 1L); - curl_easy_setopt (sink->priv->curl, CURLOPT_READFUNCTION, + curl_easy_setopt (sink->curl, CURLOPT_READFUNCTION, gst_curl_sink_transfer_read_cb); - curl_easy_setopt (sink->priv->curl, CURLOPT_READDATA, sink); - curl_easy_setopt (sink->priv->curl, CURLOPT_WRITEFUNCTION, + curl_easy_setopt (sink->curl, CURLOPT_READDATA, sink); + curl_easy_setopt (sink->curl, CURLOPT_WRITEFUNCTION, gst_curl_sink_transfer_write_cb); return TRUE; @@ -726,7 +710,6 @@ gst_curl_sink_transfer_read_cb (void *curl_ptr, size_t size, size_t nmemb, void *stream) { GstCurlSink *sink; - GstCurlSinkPrivate *pr; TransferBuffer *buffer; size_t max_bytes_to_send; guint buf_len; @@ -745,8 +728,7 @@ gst_curl_sink_transfer_read_cb (void *curl_ptr, size_t size, size_t nmemb, max_bytes_to_send = size * nmemb; - pr = sink->priv; - buffer = pr->transfer_buf; + buffer = sink->transfer_buf; buf_len = buffer->len; GST_LOG ("write buf len=%d, offset=%d", buffer->len, buffer->offset); @@ -800,7 +782,7 @@ gst_curl_sink_transfer_check (GstCurlSink * sink) do { easy = NULL; - while ((msg = curl_multi_info_read (sink->priv->multi_handle, &msgs_left))) { + while ((msg = curl_multi_info_read (sink->multi_handle, &msgs_left))) { if (msg->msg == CURLMSG_DONE) { easy = msg->easy_handle; code = msg->data.result; @@ -829,34 +811,33 @@ gst_curl_sink_handle_transfer (GstCurlSink * sink) glong resp_proxy = -1; GST_OBJECT_LOCK (sink); - timeout = sink->priv->timeout; + timeout = sink->timeout; GST_OBJECT_UNLOCK (sink); /* Receiving CURLM_CALL_MULTI_PERFORM means that libcurl may have more data available to send or receive - call simply curl_multi_perform before poll() on more actions */ do { - m_code = curl_multi_perform (sink->priv->multi_handle, &running_handles); + m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); while (running_handles && (m_code == CURLM_OK)) { if (!proxy_conn_established && (resp_proxy != RESPONSE_CONNECT_PROXY) && proxy_auth) { - curl_easy_getinfo (sink->priv->curl, CURLINFO_HTTP_CONNECTCODE, - &resp_proxy); + curl_easy_getinfo (sink->curl, CURLINFO_HTTP_CONNECTCODE, &resp_proxy); if ((resp_proxy == RESPONSE_CONNECT_PROXY)) { GST_LOG ("received HTTP/1.0 200 Connection Established"); /* Workaround: redefine HTTP headers before connecting to HTTP server. * When talking to proxy, the Content-Length: 0 is send with the request. */ - curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + curl_multi_remove_handle (sink->multi_handle, sink->curl); gst_curl_sink_set_http_header_unlocked (sink); - curl_multi_add_handle (sink->priv->multi_handle, sink->priv->curl); + curl_multi_add_handle (sink->multi_handle, sink->curl); proxy_conn_established = TRUE; } } - retval = gst_poll_wait (sink->priv->fdset, timeout * GST_SECOND); + retval = gst_poll_wait (sink->fdset, timeout * GST_SECOND); if (G_UNLIKELY (retval == -1)) { if (errno == EAGAIN || errno == EINTR) { GST_DEBUG_OBJECT (sink, "interrupted by signal"); @@ -872,11 +853,11 @@ gst_curl_sink_handle_transfer (GstCurlSink * sink) /* readable/writable sockets */ do { - m_code = curl_multi_perform (sink->priv->multi_handle, &running_handles); + m_code = curl_multi_perform (sink->multi_handle, &running_handles); } while (m_code == CURLM_CALL_MULTI_PERFORM); if (resp != RESPONSE_100_CONTINUE) { - curl_easy_getinfo (sink->priv->curl, CURLINFO_RESPONSE_CODE, &resp); + curl_easy_getinfo (sink->curl, CURLINFO_RESPONSE_CODE, &resp); } } @@ -900,7 +881,7 @@ gst_curl_sink_handle_transfer (GstCurlSink * sink) } /* check response code */ - curl_easy_getinfo (sink->priv->curl, CURLINFO_RESPONSE_CODE, &resp); + curl_easy_getinfo (sink->curl, CURLINFO_RESPONSE_CODE, &resp); GST_DEBUG_OBJECT (sink, "response code: %d", resp); if (resp < 200 || resp >= 300) { goto response_error; @@ -982,13 +963,13 @@ gst_curl_sink_transfer_socket_cb (void *clientp, curl_socket_t curlfd, return 1; } - gst_poll_fd_init (&sink->priv->fd); - sink->priv->fd.fd = curlfd; + gst_poll_fd_init (&sink->fd); + sink->fd.fd = curlfd; - ret = ret && gst_poll_add_fd (sink->priv->fdset, &sink->priv->fd); - ret = ret && gst_poll_fd_ctl_write (sink->priv->fdset, &sink->priv->fd, TRUE); - ret = ret && gst_poll_fd_ctl_read (sink->priv->fdset, &sink->priv->fd, TRUE); - GST_DEBUG ("fd: %d", sink->priv->fd.fd); + ret = ret && gst_poll_add_fd (sink->fdset, &sink->fd); + ret = ret && gst_poll_fd_ctl_write (sink->fdset, &sink->fd, TRUE); + ret = ret && gst_poll_fd_ctl_read (sink->fdset, &sink->fd, TRUE); + GST_DEBUG ("fd: %d", sink->fd.fd); GST_OBJECT_LOCK (sink); gst_curl_sink_setup_dscp_unlocked (sink); GST_OBJECT_UNLOCK (sink); @@ -1008,13 +989,13 @@ gst_curl_sink_transfer_start_unlocked (GstCurlSink * sink) gboolean ret = TRUE; GST_LOG ("creating transfer thread"); - sink->priv->transfer_thread_close = FALSE; - sink->priv->new_file = TRUE; - sink->priv->transfer_thread = + sink->transfer_thread_close = FALSE; + sink->new_file = TRUE; + sink->transfer_thread = g_thread_create ((GThreadFunc) gst_curl_sink_transfer_thread_func, sink, TRUE, &error); - if (sink->priv->transfer_thread == NULL || error != NULL) { + if (sink->transfer_thread == NULL || error != NULL) { ret = FALSE; if (error) { GST_ERROR_OBJECT (sink, "could not create thread %s", error->message); @@ -1039,15 +1020,14 @@ gst_curl_sink_transfer_thread_func (gpointer data) if (!gst_curl_sink_transfer_setup_unlocked (sink)) { GST_DEBUG_OBJECT (sink, "curl setup error"); GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("curl setup error"), (NULL)); - sink->priv->flow_ret = GST_FLOW_ERROR; + sink->flow_ret = GST_FLOW_ERROR; goto done; } - while (!sink->priv->transfer_thread_close && - sink->priv->flow_ret == GST_FLOW_OK) { + while (!sink->transfer_thread_close && sink->flow_ret == GST_FLOW_OK) { /* we are working on a new file, clearing flag and setting file * name in http header */ - sink->priv->new_file = FALSE; + sink->new_file = FALSE; /* wait for data to arrive for this new file, if we get a new file name * again before getting data we will simply skip transfering anything @@ -1061,14 +1041,14 @@ gst_curl_sink_transfer_thread_func (gpointer data) GST_OBJECT_UNLOCK (sink); if (data_available) { - curl_multi_add_handle (sink->priv->multi_handle, sink->priv->curl); + curl_multi_add_handle (sink->multi_handle, sink->curl); /* Start driving the transfer. */ ret = gst_curl_sink_handle_transfer (sink); /* easy handle will be possibly re-used for next transfer, thus it needs to * be removed from the multi stack and re-added again */ - curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + curl_multi_remove_handle (sink->multi_handle, sink->curl); } /* lock again before looping to check the thread closed flag */ @@ -1076,20 +1056,20 @@ gst_curl_sink_transfer_thread_func (gpointer data) /* if we have transfered data, then set the return code */ if (data_available) { - sink->priv->flow_ret = ret; + sink->flow_ret = ret; } } done: /* if there is a flow error, always notify the render function so it * can return the flow error up along the pipeline */ - if (sink->priv->flow_ret != GST_FLOW_OK) { + if (sink->flow_ret != GST_FLOW_OK) { gst_curl_sink_data_sent_notify_unlocked (sink); } GST_OBJECT_UNLOCK (sink); GST_DEBUG ("exit thread func - transfer thread close flag: %d", - sink->priv->transfer_thread_close); + sink->transfer_thread_close); return NULL; } @@ -1099,9 +1079,9 @@ gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink) { g_assert (sink); - if (sink->priv->curl == NULL) { + if (sink->curl == NULL) { /* curl_easy_init automatically calls curl_global_init(3) */ - if ((sink->priv->curl = curl_easy_init ()) == NULL) { + if ((sink->curl = curl_easy_init ()) == NULL) { g_warning ("Failed to init easy handle"); return FALSE; } @@ -1114,8 +1094,8 @@ gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink) } /* init a multi stack (non-blocking interface to liburl) */ - if (sink->priv->multi_handle == NULL) { - if ((sink->priv->multi_handle = curl_multi_init ()) == NULL) { + if (sink->multi_handle == NULL) { + if ((sink->multi_handle = curl_multi_init ()) == NULL) { return FALSE; } } @@ -1126,17 +1106,17 @@ gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink) static void gst_curl_sink_transfer_cleanup (GstCurlSink * sink) { - if (sink->priv->curl != NULL) { - if (sink->priv->multi_handle != NULL) { - curl_multi_remove_handle (sink->priv->multi_handle, sink->priv->curl); + if (sink->curl != NULL) { + if (sink->multi_handle != NULL) { + curl_multi_remove_handle (sink->multi_handle, sink->curl); } - curl_easy_cleanup (sink->priv->curl); - sink->priv->curl = NULL; + curl_easy_cleanup (sink->curl); + sink->curl = NULL; } - if (sink->priv->multi_handle != NULL) { - curl_multi_cleanup (sink->priv->multi_handle); - sink->priv->multi_handle = NULL; + if (sink->multi_handle != NULL) { + curl_multi_cleanup (sink->multi_handle); + sink->multi_handle = NULL; } } @@ -1146,14 +1126,14 @@ gst_curl_sink_wait_for_data_unlocked (GstCurlSink * sink) gboolean data_available = FALSE; GST_LOG ("waiting for data"); - while (!sink->priv->transfer_cond->data_available && - !sink->priv->transfer_thread_close && !sink->priv->new_file) { - g_cond_wait (sink->priv->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); + while (!sink->transfer_cond->data_available && + !sink->transfer_thread_close && !sink->new_file) { + g_cond_wait (sink->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); } - if (sink->priv->transfer_thread_close) { + if (sink->transfer_thread_close) { GST_LOG ("wait for data aborted due to thread close"); - } else if (sink->priv->new_file) { + } else if (sink->new_file) { GST_LOG ("wait for data aborted due to new file name"); } else { GST_LOG ("wait for data completed"); @@ -1167,25 +1147,25 @@ static void gst_curl_sink_transfer_thread_notify_unlocked (GstCurlSink * sink) { GST_LOG ("more data to send"); - sink->priv->transfer_cond->data_available = TRUE; - sink->priv->transfer_cond->data_sent = FALSE; - g_cond_signal (sink->priv->transfer_cond->cond); + sink->transfer_cond->data_available = TRUE; + sink->transfer_cond->data_sent = FALSE; + g_cond_signal (sink->transfer_cond->cond); } static void gst_curl_sink_new_file_notify_unlocked (GstCurlSink * sink) { GST_LOG ("new file name"); - sink->priv->new_file = TRUE; - g_cond_signal (sink->priv->transfer_cond->cond); + sink->new_file = TRUE; + g_cond_signal (sink->transfer_cond->cond); } static void gst_curl_sink_transfer_thread_close_unlocked (GstCurlSink * sink) { GST_LOG ("setting transfer thread close flag"); - sink->priv->transfer_thread_close = TRUE; - g_cond_signal (sink->priv->transfer_cond->cond); + sink->transfer_thread_close = TRUE; + g_cond_signal (sink->transfer_cond->cond); } static void @@ -1197,8 +1177,8 @@ gst_curl_sink_wait_for_transfer_thread_to_send_unlocked (GstCurlSink * sink) * since that flag only can be set by the EoS event (by the pipeline thread). * This can therefore never happen while this function is running since this * function also is called by the pipeline thread (in the render function) */ - while (!sink->priv->transfer_cond->data_sent) { - g_cond_wait (sink->priv->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); + while (!sink->transfer_cond->data_sent) { + g_cond_wait (sink->transfer_cond->cond, GST_OBJECT_GET_LOCK (sink)); } GST_LOG ("buffer send completed"); } @@ -1207,9 +1187,9 @@ static void gst_curl_sink_data_sent_notify_unlocked (GstCurlSink * sink) { GST_LOG ("transfer completed"); - sink->priv->transfer_cond->data_available = FALSE; - sink->priv->transfer_cond->data_sent = TRUE; - g_cond_signal (sink->priv->transfer_cond->cond); + sink->transfer_cond->data_available = FALSE; + sink->transfer_cond->data_sent = TRUE; + g_cond_signal (sink->transfer_cond->cond); } static gint @@ -1226,7 +1206,7 @@ gst_curl_sink_setup_dscp_unlocked (GstCurlSink * sink) } sa; socklen_t slen = sizeof (sa); - if (getsockname (sink->priv->fd.fd, &sa.sa, &slen) < 0) { + if (getsockname (sink->fd.fd, &sa.sa, &slen) < 0) { GST_DEBUG_OBJECT (sink, "could not get sockname: %s", g_strerror (errno)); return ret; } @@ -1241,16 +1221,15 @@ gst_curl_sink_setup_dscp_unlocked (GstCurlSink * sink) } } /* extract and shift 6 bits of the DSCP */ - tos = (sink->priv->qos_dscp & 0x3f) << 2; + tos = (sink->qos_dscp & 0x3f) << 2; switch (af) { case AF_INET: - ret = setsockopt (sink->priv->fd.fd, IPPROTO_IP, IP_TOS, &tos, - sizeof (tos)); + ret = setsockopt (sink->fd.fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)); break; case AF_INET6: #ifdef IPV6_TCLASS - ret = setsockopt (sink->priv->fd.fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, + ret = setsockopt (sink->fd.fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)); break; #endif diff --git a/ext/curl/gstcurlsink.h b/ext/curl/gstcurlsink.h index 1a49e21c6d..d158577ef5 100644 --- a/ext/curl/gstcurlsink.h +++ b/ext/curl/gstcurlsink.h @@ -39,7 +39,6 @@ G_BEGIN_DECLS typedef struct _GstCurlSink GstCurlSink; typedef struct _GstCurlSinkClass GstCurlSinkClass; -typedef struct _GstCurlSinkPrivate GstCurlSinkPrivate; typedef struct _TransferBuffer TransferBuffer; typedef struct _TransferCondition TransferCondition; @@ -56,8 +55,11 @@ struct _TransferCondition { gboolean data_available; }; -struct _GstCurlSinkPrivate +struct _GstCurlSink { + GstBaseSink parent; + + /*< private >*/ CURLM *multi_handle; CURL *curl; struct curl_slist *header_list; @@ -86,14 +88,6 @@ struct _GstCurlSinkPrivate gboolean proxy_headers_set; }; -struct _GstCurlSink -{ - GstBaseSink parent; - - /*< private >*/ - GstCurlSinkPrivate *priv; -}; - struct _GstCurlSinkClass { GstBaseSinkClass parent_class; From 1fe9c8c8ae2bf8456b5ac9b411a52de53ba95c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Mar 2011 10:49:57 +0000 Subject: [PATCH 09/20] configure: also check for platform socket headers needed by curlsink element --- configure.ac | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 27e2013c18..e06b8c9542 100644 --- a/configure.ac +++ b/configure.ac @@ -656,7 +656,13 @@ AG_GST_CHECK_FEATURE(COG, [Cog plugin], cog, [ dnl *** Curl *** translit(dnm, m, l) AM_CONDITIONAL(USE_CURL, true) AG_GST_CHECK_FEATURE(CURL, [Curl plugin], curl, [ - PKG_CHECK_MODULES(CURL, libcurl >= 7.21.0, HAVE_CURL="yes", [ + PKG_CHECK_MODULES(CURL, libcurl >= 7.21.0, [ + HAVE_CURL="yes" + AC_CHECK_HEADERS([unistd.h sys/socket.h sys/types.h netinet/in.h netinet/ip.h netinet/tcp.h fcntl.h], + [ ], [HAVE_CURL="no"]) + AC_MSG_CHECKING([for socket support needed by curlsink]) + AC_MSG_RESULT($HAVE_CURL) + ], [ HAVE_CURL="no" AC_MSG_RESULT(no) ]) From c6d7071d938d2acb5481f5e8ea9cf0e671a5c2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Mar 2011 11:16:56 +0000 Subject: [PATCH 10/20] docs: add new curl plugin and curlsink element to docs --- docs/plugins/Makefile.am | 1 + .../plugins/gst-plugins-bad-plugins-docs.sgml | 2 ++ .../gst-plugins-bad-plugins-sections.txt | 14 ++++++++++ docs/plugins/inspect/plugin-curl.xml | 28 +++++++++++++++++++ ext/curl/gstcurlsink.c | 28 +++++++++++++++++-- 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 docs/plugins/inspect/plugin-curl.xml diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index c9820cfd79..0d124a74b6 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -94,6 +94,7 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/amrwbenc/gstamrwbenc.h \ $(top_srcdir)/ext/celt/gstceltdec.h \ $(top_srcdir)/ext/celt/gstceltenc.h \ + $(top_srcdir)/ext/curl/gstcurlsink.h \ $(top_srcdir)/ext/dc1394/gstdc1394.h \ $(top_srcdir)/ext/directfb/dfbvideosink.h \ $(top_srcdir)/ext/dts/gstdtsdec.h \ diff --git a/docs/plugins/gst-plugins-bad-plugins-docs.sgml b/docs/plugins/gst-plugins-bad-plugins-docs.sgml index 5551d5c600..8cbad1e7db 100644 --- a/docs/plugins/gst-plugins-bad-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-bad-plugins-docs.sgml @@ -33,6 +33,7 @@ + @@ -147,6 +148,7 @@ + diff --git a/docs/plugins/gst-plugins-bad-plugins-sections.txt b/docs/plugins/gst-plugins-bad-plugins-sections.txt index f85d0754d8..98e3264d69 100644 --- a/docs/plugins/gst-plugins-bad-plugins-sections.txt +++ b/docs/plugins/gst-plugins-bad-plugins-sections.txt @@ -244,6 +244,20 @@ GST_TYPE_COLOR_EFFECTS gst_color_effects_get_type +
+element-curlsink +curlsink +GstCurlSink + +GstCurlSinkClass +GST_CURL_SINK +GST_CURL_SINK_CLASS +GST_IS_CURL_SINK +GST_IS_CURL_SINK_CLASS +GST_TYPE_CURL_SINK +gst_curl_sink_get_type +
+
element-cvdilate cvdilate diff --git a/docs/plugins/inspect/plugin-curl.xml b/docs/plugins/inspect/plugin-curl.xml new file mode 100644 index 0000000000..64e82c9546 --- /dev/null +++ b/docs/plugins/inspect/plugin-curl.xml @@ -0,0 +1,28 @@ + + curl + libcurl-based elements + ../../ext/curl/.libs/libgstcurl.so + libgstcurl.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + curlsink + Curl sink + Sink/Network + Upload data over the network to a server using libcurl + Patricia Muscalu <patricia@axis.com> + + + sink + sink + always +
ANY
+
+
+
+
+
\ No newline at end of file diff --git a/ext/curl/gstcurlsink.c b/ext/curl/gstcurlsink.c index 77fa1c483e..f234e37777 100644 --- a/ext/curl/gstcurlsink.c +++ b/ext/curl/gstcurlsink.c @@ -17,6 +17,31 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:element-curlsink + * @short_description: sink that uploads data to a server using libcurl + * @see_also: + * + * This is a network sink that uses libcurl as a client to upload data to + * a server (e.g. a HTTP/FTP server). + * + * + * Example launch line (upload a JPEG file to an HTTP server) + * |[ + * gst-launch filesrc filesrc location=image.jpg ! jpegparse ! curlsink \ + * file-name=image.jpg \ + * location=http://192.168.0.1:8080/cgi-bin/patupload.cgi/ \ + * user=test passwd=test \ + * content-type=image/jpeg \ + * use-content-length=false + * ]| + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -30,9 +55,6 @@ #include #include -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif #include "gstcurlsink.h" /* Default values */ From 8e60680c3381b5a579d8e6fd21110289c7125b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Tue, 1 Mar 2011 11:23:49 +0000 Subject: [PATCH 11/20] docs: update docs for recent changes in git --- docs/plugins/gst-plugins-bad-plugins.args | 312 ++++++++++++++++-- .../plugins/gst-plugins-bad-plugins.hierarchy | 16 +- .../gst-plugins-bad-plugins.interfaces | 3 +- docs/plugins/inspect/plugin-colorspace.xml | 4 +- docs/plugins/inspect/plugin-h264parse.xml | 2 +- docs/plugins/inspect/plugin-mpegtsdemux.xml | 79 +++++ docs/plugins/inspect/plugin-rtmpsrc.xml | 28 ++ docs/plugins/inspect/plugin-rtpvp8.xml | 55 +++ docs/plugins/inspect/plugin-schro.xml | 21 -- .../inspect/plugin-videoparsersbad.xml | 76 +++++ 10 files changed, 546 insertions(+), 50 deletions(-) create mode 100644 docs/plugins/inspect/plugin-mpegtsdemux.xml create mode 100644 docs/plugins/inspect/plugin-rtmpsrc.xml create mode 100644 docs/plugins/inspect/plugin-rtpvp8.xml create mode 100644 docs/plugins/inspect/plugin-videoparsersbad.xml diff --git a/docs/plugins/gst-plugins-bad-plugins.args b/docs/plugins/gst-plugins-bad-plugins.args index f6f1b5816c..a446e82c39 100644 --- a/docs/plugins/gst-plugins-bad-plugins.args +++ b/docs/plugins/gst-plugins-bad-plugins.args @@ -1675,7 +1675,7 @@ rw trans-mode Transmission Mode (DVB-T). -8k +8K @@ -17955,7 +17955,7 @@ rw trans-mode Transmission Mode (DVB-T). -8k +8K @@ -18322,7 +18322,7 @@ GstH264Parse::split-packetized gboolean -rw +rwx Split packetized Split NAL units of packetized streams. FALSE @@ -18352,7 +18352,7 @@ GstH264Parse::config-interval guint <= 3600 -rw +rwx SPS PPS Send Interval Send SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled). 0 @@ -26510,7 +26510,7 @@ rw physics water density: from 1 to 4. -4.63015e-299 +0 @@ -26550,7 +26550,7 @@ rw splash make a big splash in the center. -7.7486e-304 +0 @@ -26560,7 +26560,7 @@ rw splash make a big splash in the center. -4.62957e-299 +0 @@ -26590,7 +26590,7 @@ rw ratiox x-ratio. -2.31928e-310 +3.81574e-236 @@ -26600,7 +26600,7 @@ rw ratioy y-ratio. -2.31928e-310 +2.58656e-231 @@ -26610,7 +26610,7 @@ rw DelayTime the delay time. -0 +-6.17189e+303 @@ -26640,7 +26640,7 @@ rw Color the color of the image. -0 +7.05334e-30 @@ -26650,7 +26650,7 @@ rw Color the color of the image. -0 +7.05334e-30 @@ -26990,7 +26990,7 @@ rw lredscale multiplier for downscaling non-edge brightness. -0 +8.20251e-304 @@ -27000,7 +27000,7 @@ rw lthresh threshold for edge lightening. -6.9235e+228 +0 @@ -27010,7 +27010,7 @@ rw lupscale multiplier for upscaling edge brightness. -0 +7.74861e-304 @@ -27180,7 +27180,7 @@ rw blend blend factor. --6.17056e+303 +8.20251e-304 @@ -27190,7 +27190,7 @@ rw fader the fader position. -7.7486e-304 +-5.83035e+303 @@ -27370,7 +27370,7 @@ rw HSync the hsync offset. -2.38039e-316 +1.86264e-09 @@ -45499,7 +45499,7 @@ [0,1000000000] rw Bit rate -Bit rate. +Bit rate (in bits/sec). 0 @@ -47036,7 +47036,7 @@ GstRsvgOverlay::x gint ->= 0 +>= -2147483647 rw x offset Specify an x offset. @@ -47046,10 +47046,280 @@ GstRsvgOverlay::y gint ->= 0 +>= -2147483647 rw y offset Specify a y offset. 0 + +GstRsvgOverlay::height +gint +>= -2147483647 +rw +height +Specify a height in pixels. +0 + + + +GstRsvgOverlay::height-relative +gfloat + +rw +relative height +Specify a height relative to the display size. +0 + + + +GstRsvgOverlay::width +gint +>= -2147483647 +rw +width +Specify a width in pixels. +0 + + + +GstRsvgOverlay::width-relative +gfloat + +rw +relative width +Specify a width relative to the display size. +0 + + + +GstRsvgOverlay::x-relative +gfloat + +rw +x relative offset +Specify an x offset relative to the display size. +0 + + + +GstRsvgOverlay::y-relative +gfloat + +rw +y relative offset +Specify a y offset relative to the display size. +0 + + + +GstLegacyH264Parse::access-unit +gboolean + +rw +Access Units +Output Acess Units rather than NALUs. +FALSE + + + +GstLegacyH264Parse::config-interval +guint +<= 3600 +rw +SPS PPS Send Interval +Send SPS and PPS Insertion Interval in seconds (sprop parameter sets will be multiplexed in the data stream when detected.) (0 = disabled). +0 + + + +GstLegacyH264Parse::output-format +GstH264ParseFormat + +rw +Output Format +Output Format of stream (bytestream or otherwise). +Input Format + + + +GstLegacyH264Parse::split-packetized +gboolean + +rw +Split packetized +Split NAL units of packetized streams. +FALSE + + + +GstCsp::dither +GstColorspaceDitherMethod + +rw +Dither +Apply dithering while converting. +No dithering (default) + + + +MpegTSParse2::program-numbers +gchar* + +rw +Program Numbers +Colon separated list of programs. +"" + + + +GstTSDemux::emit-stats +gboolean + +rw +Emit statistics +Emit messages for every pcr/opcr/pts/dts. +FALSE + + + +GstTSDemux::program-number +gint +>= G_MAXULONG +rw +Program number +Program Number to demux for (-1 to ignore). +-1 + + + +GstCurlSink::accept-self-signed +gboolean + +rw +Accept self-signed certificates +Accept self-signed SSL/TLS certificates. +FALSE + + + +GstCurlSink::content-type +gchar* + +rw +Content type +The mime type of the body of the request. +NULL + + + +GstCurlSink::file-name +gchar* + +rw +Base file name +The base file name for the uploaded images. +NULL + + + +GstCurlSink::location +gchar* + +rw +Location +URI location to write to. +NULL + + + +GstCurlSink::passwd +gchar* + +rw +User password +User password to use for server authentication. +NULL + + + +GstCurlSink::proxy +gchar* + +rw +Proxy +HTTP proxy server URI. +NULL + + + +GstCurlSink::proxy-passwd +gchar* + +rw +Proxy user password +Proxy user password to use for proxy authentication. +NULL + + + +GstCurlSink::proxy-port +gint +>= 0 +rw +Proxy port +HTTP proxy server port. +3128 + + + +GstCurlSink::proxy-user +gchar* + +rw +Proxy user name +Proxy user name to use for proxy authentication. +NULL + + + +GstCurlSink::qos-dscp +gint +[0,63] +rw +QoS diff srv code point +Quality of Service, differentiated services code point (0 default). +0 + + + +GstCurlSink::timeout +gint +>= 0 +rw +Timeout +Number of seconds waiting to write before timeout. +30 + + + +GstCurlSink::use-content-length +gboolean + +rw +Use content length header +Use the Content-Length HTTP header instead of Transfer-Encoding header. +FALSE + + + +GstCurlSink::user +gchar* + +rw +User name +User name to use for server authentication. +NULL + + diff --git a/docs/plugins/gst-plugins-bad-plugins.hierarchy b/docs/plugins/gst-plugins-bad-plugins.hierarchy index 84322e7d5a..8c6f8579a6 100644 --- a/docs/plugins/gst-plugins-bad-plugins.hierarchy +++ b/docs/plugins/gst-plugins-bad-plugins.hierarchy @@ -14,17 +14,22 @@ GObject GstAsfMux GstAsfParse GstAssRender - GstAudioBaseParseBad + GstBaseParseBad GstAacParse GstAc3Parse GstAmrParse GstDcaParse + GstDiracParse GstFlacParse + GstH263Parse + GstH264Parse GstMpegAudioParse GstBaseRTPDepayload GstRtpDTMFDepay + GstRtpVP8Depay GstBaseRTPPayload GstRtpAsfPay + GstRtpVP8Pay GstBaseSink GstBaseAudioSink GstAudioSink @@ -32,6 +37,7 @@ GObject GstNasSink GstSDLAudioSink GstChecksumSink + GstCurlSink GstDCCPClientSink GstDCCPServerSink GstFBDEVSink @@ -52,6 +58,7 @@ GObject GstMMS GstMythtvSrc GstNeonhttpSrc + GstRTMPSrc GstRfbSrc GstShmSrc GstVCDSrc @@ -181,8 +188,6 @@ GObject GstDiracEnc GstSchroEnc GstVP8Enc - GstBaseVideoParse - GstSchroParse GstBin DvbBaseBin GstAutoConvert @@ -216,7 +221,6 @@ GObject GstGPPMux GstGSMDec GstGSMEnc - GstH264Parse GstISMLMux GstId3BaseMux GstId3Mux @@ -231,6 +235,7 @@ GObject GstKateParse GstKateTag GstKateTiger + GstLegacyH264Parse GstLiveAdder GstMJ2Mux GstMP4Mux @@ -436,6 +441,9 @@ GObject Gstpyramidsegment Gsttextwrite MpegPsMux + MpegTSBase + GstTSDemux + MpegTSParse2 MpegTSParse MpegTsMux MpegVideoParse diff --git a/docs/plugins/gst-plugins-bad-plugins.interfaces b/docs/plugins/gst-plugins-bad-plugins.interfaces index bfa93f0553..bec4fc6a63 100644 --- a/docs/plugins/gst-plugins-bad-plugins.interfaces +++ b/docs/plugins/gst-plugins-bad-plugins.interfaces @@ -14,13 +14,14 @@ GstAutoConvert GstChildProxy GstAutoVideoConvert GstChildProxy GstSDPDemux GstChildProxy GstFPSDisplaySink GstChildProxy -GstMpeg2enc GstPreset GstSDLVideoSink GstImplementsInterface GstXOverlay GstNavigation GstDfbVideoSink GstImplementsInterface GstNavigation GstColorBalance VdpSink GstImplementsInterface GstNavigation GstXOverlay GstApExSink GstImplementsInterface GstMixer +GstMpeg2enc GstPreset GstCeltEnc GstTagSetter GstPreset GstCDAudio GstURIHandler +GstRTMPSrc GstURIHandler GstMythtvSrc GstURIHandler GstMMS GstURIHandler GstNeonhttpSrc GstURIHandler diff --git a/docs/plugins/inspect/plugin-colorspace.xml b/docs/plugins/inspect/plugin-colorspace.xml index d8eeb1cc66..9cfedafffb 100644 --- a/docs/plugins/inspect/plugin-colorspace.xml +++ b/docs/plugins/inspect/plugin-colorspace.xml @@ -20,13 +20,13 @@ sink sink always -
video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, A420 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, v216, A420, AY64 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)30, endianness=(int)4321, red_mask=(int)1072693248, green_mask=(int)1047552, blue_mask=(int)1023, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)64, depth=(int)64, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
src source always -
video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, A420 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
video/x-raw-yuv, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ], format=(fourcc){ I420, NV12, NV21, YV12, YUY2, Y42B, Y444, YUV9, YVU9, Y41B, Y800, Y8 , GREY, Y16 , UYVY, YVYU, IYU1, v308, AYUV, v210, v216, A420, AY64 }; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)63488, green_mask=(int)2016, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)16, endianness=(int)1234, red_mask=(int)31, green_mask=(int)2016, blue_mask=(int)63488, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31744, green_mask=(int)992, blue_mask=(int)31, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)16, depth=(int)15, endianness=(int)1234, red_mask=(int)31, green_mask=(int)992, blue_mask=(int)31744, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)8, depth=(int)8, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)4321, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-gray, bpp=(int)16, depth=(int)16, endianness=(int)1234, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)30, endianness=(int)4321, red_mask=(int)1072693248, green_mask=(int)1047552, blue_mask=(int)1023, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)64, depth=(int)64, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
diff --git a/docs/plugins/inspect/plugin-h264parse.xml b/docs/plugins/inspect/plugin-h264parse.xml index 14977a52c8..3862d7ee93 100644 --- a/docs/plugins/inspect/plugin-h264parse.xml +++ b/docs/plugins/inspect/plugin-h264parse.xml @@ -10,7 +10,7 @@ Unknown package origin - h264parse + legacyh264parse H264Parse Codec/Parser/Video Parses raw h264 stream diff --git a/docs/plugins/inspect/plugin-mpegtsdemux.xml b/docs/plugins/inspect/plugin-mpegtsdemux.xml new file mode 100644 index 0000000000..6dbd0669f4 --- /dev/null +++ b/docs/plugins/inspect/plugin-mpegtsdemux.xml @@ -0,0 +1,79 @@ + + mpegtsdemux + MPEG TS demuxer + ../../gst/mpegtsdemux/.libs/libgstmpegtsdemux.so + libgstmpegtsdemux.so + 0.10.21.1 + unknown + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + tsdemux + MPEG transport stream demuxer + Codec/Demuxer + Demuxes MPEG2 transport streams + Zaheer Abbas Merali <zaheerabbas at merali dot org>; Edward Hervey <edward.hervey@collabora.co.uk> + + + sink + sink + always +
video/mpegts, systemstream=(boolean)true
+
+ + audio_%04x + source + sometimes +
audio/mpeg, mpegversion=(int){ 1, 4 }; audio/x-lpcm, width=(int){ 16, 20, 24 }, rate=(int){ 48000, 96000 }, channels=(int)[ 1, 8 ], dynamic_range=(int)[ 0, 255 ], emphasis=(boolean){ false, true }, mute=(boolean){ false, true }; audio/x-ac3; audio/x-eac3; audio/x-dts; audio/x-private-ts-lpcm
+
+ + private_%04x + source + sometimes +
ANY
+
+ + subpicture_%04x + source + sometimes +
subpicture/x-pgs; video/x-dvd-subpicture
+
+ + video_%04x + source + sometimes +
video/mpeg, mpegversion=(int){ 1, 2, 4 }, systemstream=(boolean)false; video/x-h264; video/x-dirac; video/x-wmv, wmvversion=(int)3, format=(fourcc)WVC1
+
+
+
+ + tsparse + MPEG transport stream parser + Codec/Parser + Parses MPEG2 transport streams + Alessandro Decina <alessandro@nnva.org>, Zaheer Abbas Merali <zaheerabbas at merali dot org> + + + sink + sink + always +
video/mpegts, systemstream=(boolean)true
+
+ + program_%d + source + sometimes +
video/mpegts, systemstream=(boolean)true
+
+ + src%d + source + request +
video/mpegts, systemstream=(boolean)true
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-rtmpsrc.xml b/docs/plugins/inspect/plugin-rtmpsrc.xml new file mode 100644 index 0000000000..007979cdcb --- /dev/null +++ b/docs/plugins/inspect/plugin-rtmpsrc.xml @@ -0,0 +1,28 @@ + + rtmpsrc + RTMP source + ../../ext/rtmp/.libs/libgstrtmp.so + libgstrtmp.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + rtmpsrc + RTMP Source + Source/File + Read RTMP streams + Bastien Nocera <hadess@hadess.net>, Sebastian Dröge <sebastian.droege@collabora.co.uk> + + + src + source + always +
ANY
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-rtpvp8.xml b/docs/plugins/inspect/plugin-rtpvp8.xml new file mode 100644 index 0000000000..db2051ec91 --- /dev/null +++ b/docs/plugins/inspect/plugin-rtpvp8.xml @@ -0,0 +1,55 @@ + + rtpvp8 + rtpvp8 + ../../gst/rtpvp8/.libs/libgstrtpvp8.so + libgstrtpvp8.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + rtpvp8depay + RTP VP8 depayloader + Codec/Depayloader/Network/RTP + Extracts VP8 video from RTP packets) + Sjoerd Simons <sjoerd@luon.net> + + + sink + sink + always +
application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, media=(string)video, encoding-name=(string)VP8-DRAFT-0-3-2
+
+ + src + source + always +
video/x-vp8
+
+
+
+ + rtpvp8pay + RTP VP8 payloader + Codec/Payloader/Network/RTP + Puts VP8 video in RTP packets) + Sjoerd Simons <sjoerd@luon.net> + + + sink + sink + always +
video/x-vp8
+
+ + src + source + always +
application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)VP8-DRAFT-0-3-2
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-schro.xml b/docs/plugins/inspect/plugin-schro.xml index 3bb341ad5c..59e7549e68 100644 --- a/docs/plugins/inspect/plugin-schro.xml +++ b/docs/plugins/inspect/plugin-schro.xml @@ -51,26 +51,5 @@
- - schroparse - Dirac Parser - Codec/Parser/Video - Parse Dirac streams - David Schleef <ds@schleef.org> - - - sink - sink - always -
video/x-dirac
-
- - src - source - always -
video/x-dirac; video/x-qt-part; video/x-avi-part; video/x-mp4-part
-
-
-
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-videoparsersbad.xml b/docs/plugins/inspect/plugin-videoparsersbad.xml new file mode 100644 index 0000000000..c961f44b89 --- /dev/null +++ b/docs/plugins/inspect/plugin-videoparsersbad.xml @@ -0,0 +1,76 @@ + + videoparsersbad + videoparsers + ../../gst/videoparsers/.libs/libgstvideoparsersbad.so + libgstvideoparsersbad.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + diracparse + FIXME + Generic + FIXME + David Schleef <ds@schleef.org> + + + sink + sink + always +
application/unknown
+
+ + src + source + always +
application/unknown
+
+
+
+ + h263parse + H.263 parser + Codec/Parser/Video + Parses H.263 streams + Arun Raghavan <arun.raghavan@collabora.co.uk>,Edward Hervey <edward.hervey@collabora.co.uk> + + + sink + sink + always +
video/x-h263, variant=(string)itu, parsed=(boolean)false
+
+ + src + source + always +
video/x-h263, variant=(string)itu, parsed=(boolean)true
+
+
+
+ + h264parse + H.264 parser + Codec/Parser/Video + Parses H.264 streams + Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + + sink + sink + always +
video/x-h264, parsed=(boolean)false
+
+ + src + source + always +
video/x-h264, parsed=(boolean)true
+
+
+
+
+
\ No newline at end of file From 14fb72014982c26a0847e9faeacac4fc25b738be Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Wed, 15 Sep 2010 17:32:09 +0200 Subject: [PATCH 12/20] fieldanalysis: Add fieldanalysis element This element analyses video buffers to identify if they are progressive, interlaced or telecined and outputs buffers with appropriate flags for a downstream element (which will be the deinterlace element, after some forthcoming modifications) to be able to output progressive frames and adjust timestamps resulting in a progressive stream. --- configure.ac | 2 + gst/fieldanalysis/Makefile.am | 26 + gst/fieldanalysis/gstfieldanalysis.c | 1806 +++++++++++++++++++++ gst/fieldanalysis/gstfieldanalysis.h | 144 ++ gst/fieldanalysis/gstfieldanalysisorc.orc | 119 ++ 5 files changed, 2097 insertions(+) create mode 100644 gst/fieldanalysis/Makefile.am create mode 100644 gst/fieldanalysis/gstfieldanalysis.c create mode 100644 gst/fieldanalysis/gstfieldanalysis.h create mode 100644 gst/fieldanalysis/gstfieldanalysisorc.orc diff --git a/configure.ac b/configure.ac index e06b8c9542..a2a38bcf8f 100644 --- a/configure.ac +++ b/configure.ac @@ -306,6 +306,7 @@ AG_GST_CHECK_PLUGIN(dtmf) AG_GST_CHECK_PLUGIN(dvbsuboverlay) AG_GST_CHECK_PLUGIN(dvdspu) AG_GST_CHECK_PLUGIN(festival) +AG_GST_CHECK_PLUGIN(fieldanalysis) AG_GST_CHECK_PLUGIN(freeze) AG_GST_CHECK_PLUGIN(frei0r) AG_GST_CHECK_PLUGIN(gaudieffects) @@ -1753,6 +1754,7 @@ gst/dtmf/Makefile gst/dvbsuboverlay/Makefile gst/dvdspu/Makefile gst/festival/Makefile +gst/fieldanalysis/Makefile gst/freeze/Makefile gst/frei0r/Makefile gst/gaudieffects/Makefile diff --git a/gst/fieldanalysis/Makefile.am b/gst/fieldanalysis/Makefile.am new file mode 100644 index 0000000000..e6c02ad2f4 --- /dev/null +++ b/gst/fieldanalysis/Makefile.am @@ -0,0 +1,26 @@ +plugin_LTLIBRARIES = libgstfieldanalysis.la + +ORC_SOURCE=gstfieldanalysisorc +include $(top_srcdir)/common/orc.mak + +libgstfieldanalysis_la_SOURCES = gstfieldanalysis.c gstfieldanalysis.h +nodist_libgstfieldanalysis_la_SOURCES = $(ORC_NODIST_SOURCES) + +libgstfieldanalysis_la_CFLAGS = \ + $(GST_PLUGINS_BAD_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(ORC_CFLAGS) + +libgstfieldanalysis_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/video/libgstbasevideo-@GST_MAJORMINOR@.la \ + $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(ORC_LIBS) + +libgstfieldanalysis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstfieldanalysis_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstfieldanalysis.h diff --git a/gst/fieldanalysis/gstfieldanalysis.c b/gst/fieldanalysis/gstfieldanalysis.c new file mode 100644 index 0000000000..5f093320f1 --- /dev/null +++ b/gst/fieldanalysis/gstfieldanalysis.c @@ -0,0 +1,1806 @@ +/* + * GStreamer + * Copyright (C) 2011 Robert Swain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-fieldanalysis + * + * Analyse fields from video buffers to identify whether the buffers are + * progressive/telecined/interlaced and, if telecined, the telecine pattern + * used. + * + * + * Example launch line + * |[ + * gst-launch -v uridecodebin uri=/path/to/foo.bar ! fieldanalysis ! deinterlace ! ffmpegcolorspace ! autovideosink + * ]| This pipeline will analyse a video stream with default metrics and thresholds and output progressive frames. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include /* for abs() */ + +#include "gstfieldanalysis.h" +#include "gstfieldanalysisorc.h" + +GST_DEBUG_CATEGORY_STATIC (gst_field_analysis_debug); +#define GST_CAT_DEFAULT gst_field_analysis_debug + +#define DEFAULT_FIELD_METRIC GST_FIELDANALYSIS_SSD +#define DEFAULT_FRAME_METRIC GST_FIELDANALYSIS_5_TAP +#define DEFAULT_NOISE_FLOOR 16 +#define DEFAULT_FIELD_THRESH 0.08f +#define DEFAULT_FRAME_THRESH 0.002f +#define DEFAULT_COMB_METHOD METHOD_5_TAP +#define DEFAULT_SPATIAL_THRESH 9 +#define DEFAULT_BLOCK_WIDTH 16 +#define DEFAULT_BLOCK_HEIGHT 16 +#define DEFAULT_BLOCK_THRESH 80 +#define DEFAULT_IGNORED_LINES 2 + +enum +{ + PROP_0, + PROP_FIELD_METRIC, + PROP_FRAME_METRIC, + PROP_NOISE_FLOOR, + PROP_FIELD_THRESH, + PROP_FRAME_THRESH, + PROP_COMB_METHOD, + PROP_SPATIAL_THRESH, + PROP_BLOCK_WIDTH, + PROP_BLOCK_HEIGHT, + PROP_BLOCK_THRESH, + PROP_IGNORED_LINES +}; + +static GstStaticPadTemplate sink_factory = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{YUY2,UYVY,I420,YV12}"))); + +static GstStaticPadTemplate src_factory = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{YUY2,UYVY,I420,YV12}"))); + +GST_BOILERPLATE (GstFieldAnalysis, gst_field_analysis, GstElement, + GST_TYPE_ELEMENT); + +static void gst_field_analysis_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_field_analysis_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_field_analysis_set_caps (GstPad * pad, GstCaps * caps); +static gboolean gst_field_analysis_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_field_analysis_chain (GstPad * pad, GstBuffer * buf); +static GstStateChangeReturn gst_field_analysis_change_state (GstElement * + element, GstStateChange transition); +static void gst_field_analysis_finalize (GObject * self); + +static GQueue *gst_field_analysis_flush_queue (GstFieldAnalysis * filter, + GQueue * queue); + +static void +gst_field_analysis_base_init (gpointer gclass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); + + gst_element_class_set_details_simple (element_class, + "Video field analysis", + "Filter/Analysis/Video", + "Analyse fields from video frames to identify if they are progressive/telecined/interlaced", + "Robert Swain "); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); +} + +typedef enum +{ + GST_FIELDANALYSIS_SAD, + GST_FIELDANALYSIS_SSD, + GST_FIELDANALYSIS_3_TAP +} GstFieldAnalysisFieldMetric; + +#define GST_TYPE_FIELDANALYSIS_FIELD_METRIC (gst_fieldanalysis_field_metric_get_type()) +static GType +gst_fieldanalysis_field_metric_get_type (void) +{ + static GType fieldanalysis_field_metric_type = 0; + + if (!fieldanalysis_field_metric_type) { + static const GEnumValue fieldanalysis_field_metrics[] = { + {GST_FIELDANALYSIS_SAD, "Sum of Absolute Differences", "sad"}, + {GST_FIELDANALYSIS_SSD, "Sum of Squared Differences", "ssd"}, + {GST_FIELDANALYSIS_3_TAP, "Difference of 3-tap [1,4,1] Horizontal Filter", + "3-tap"}, + {0, NULL, NULL}, + }; + + fieldanalysis_field_metric_type = + g_enum_register_static ("GstFieldAnalysisFieldMetric", + fieldanalysis_field_metrics); + } + + return fieldanalysis_field_metric_type; +} + +typedef enum +{ + GST_FIELDANALYSIS_5_TAP, + GST_FIELDANALYSIS_WINDOWED_COMB +} GstFieldAnalysisFrameMetric; + +#define GST_TYPE_FIELDANALYSIS_FRAME_METRIC (gst_fieldanalysis_frame_metric_get_type()) +static GType +gst_fieldanalysis_frame_metric_get_type (void) +{ + static GType fieldanalysis_frame_metric_type = 0; + + if (!fieldanalysis_frame_metric_type) { + static const GEnumValue fieldanalyis_frame_metrics[] = { + {GST_FIELDANALYSIS_5_TAP, "5-tap [1,-3,4,-3,1] Vertical Filter", "5-tap"}, + {GST_FIELDANALYSIS_WINDOWED_COMB, + "Windowed Comb Detection (not optimised)", + "windowed-comb"}, + {0, NULL, NULL}, + }; + + fieldanalysis_frame_metric_type = + g_enum_register_static ("GstFieldAnalysisFrameMetric", + fieldanalyis_frame_metrics); + } + + return fieldanalysis_frame_metric_type; +} + +#define GST_TYPE_FIELDANALYSIS_COMB_METHOD (gst_fieldanalysis_comb_method_get_type()) +static GType +gst_fieldanalysis_comb_method_get_type (void) +{ + static GType fieldanalysis_comb_method_type = 0; + + if (!fieldanalysis_comb_method_type) { + static const GEnumValue fieldanalyis_comb_methods[] = { + {METHOD_32DETECT, + "Difference to above sample in same field small and difference to sample in other field large", + "32-detect"}, + {METHOD_IS_COMBED, + "Differences between current sample and the above/below samples in other field multiplied together, larger than squared spatial threshold (from Tritical's isCombed)", + "isCombed"}, + {METHOD_5_TAP, + "5-tap [1,-3,4,-3,1] vertical filter result is larger than spatial threshold*6", + "5-tap"}, + {0, NULL, NULL}, + }; + + fieldanalysis_comb_method_type = + g_enum_register_static ("FieldAnalysisCombMethod", + fieldanalyis_comb_methods); + } + + return fieldanalysis_comb_method_type; +} + +static void +gst_field_analysis_class_init (GstFieldAnalysisClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_field_analysis_set_property; + gobject_class->get_property = gst_field_analysis_get_property; + gobject_class->finalize = gst_field_analysis_finalize; + + g_object_class_install_property (gobject_class, PROP_FIELD_METRIC, + g_param_spec_enum ("field-metric", "Field Metric", + "Metric to be used for comparing same parity fields to decide if they are a repeated field for telecine", + GST_TYPE_FIELDANALYSIS_FIELD_METRIC, DEFAULT_FIELD_METRIC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FRAME_METRIC, + g_param_spec_enum ("frame-metric", "Frame Metric", + "Metric to be used for comparing opposite parity fields to decide if they are a progressive frame", + GST_TYPE_FIELDANALYSIS_FRAME_METRIC, DEFAULT_FRAME_METRIC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_NOISE_FLOOR, + g_param_spec_uint ("noise-floor", "Noise Floor", + "Noise floor for appropriate metrics (per-pixel metric values with a score less than this will be ignored)", + 0, G_MAXUINT32, + DEFAULT_NOISE_FLOOR, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FIELD_THRESH, + g_param_spec_float ("field-threshold", "Field Threshold", + "Threshold for field metric decisions", 0.0f, G_MAXFLOAT, + DEFAULT_FIELD_THRESH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FRAME_THRESH, + g_param_spec_float ("frame-threshold", "Frame Threshold", + "Threshold for frame metric decisions", 0.0f, G_MAXFLOAT, + DEFAULT_FRAME_THRESH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_COMB_METHOD, + g_param_spec_enum ("comb-method", "Comb-detection Method", + "Metric to be used for identifying comb artifacts if using windowed comb detection", + GST_TYPE_FIELDANALYSIS_COMB_METHOD, DEFAULT_COMB_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SPATIAL_THRESH, + g_param_spec_int64 ("spatial-threshold", "Spatial Combing Threshold", + "Threshold for combing metric decisions", 0, G_MAXINT64, + DEFAULT_SPATIAL_THRESH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BLOCK_WIDTH, + g_param_spec_uint64 ("block-width", "Block width", + "Block width for windowed comb detection", 0, G_MAXUINT64, + DEFAULT_BLOCK_WIDTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BLOCK_HEIGHT, + g_param_spec_uint64 ("block-height", "Block height", + "Block height for windowed comb detection", 0, G_MAXUINT64, + DEFAULT_BLOCK_HEIGHT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BLOCK_THRESH, + g_param_spec_uint64 ("block-threshold", "Block threshold", + "Block threshold for windowed comb detection", 0, G_MAXUINT64, + DEFAULT_BLOCK_THRESH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_IGNORED_LINES, + g_param_spec_uint64 ("ignored-lines", "Ignored lines", + "Ignore this many lines from the top and bottom for windowed comb detection", + 2, G_MAXUINT64, DEFAULT_IGNORED_LINES, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_field_analysis_change_state); +} + +static gfloat same_parity_sad (GstFieldAnalysis * filter, + FieldAnalysisFields * fields); +static gfloat same_parity_ssd (GstFieldAnalysis * filter, + FieldAnalysisFields * fields); +static gfloat same_parity_3_tap (GstFieldAnalysis * filter, + FieldAnalysisFields * fields); +static gfloat opposite_parity_5_tap (GstFieldAnalysis * filter, + FieldAnalysisFields * fields); +static guint64 block_score_for_row_32detect (GstFieldAnalysis * filter, + guint8 * base_fj, guint8 * base_fjp1); +static guint64 block_score_for_row_iscombed (GstFieldAnalysis * filter, + guint8 * base_fj, guint8 * base_fjp1); +static guint64 block_score_for_row_5_tap (GstFieldAnalysis * filter, + guint8 * base_fj, guint8 * base_fjp1); +static gfloat opposite_parity_windowed_comb (GstFieldAnalysis * filter, + FieldAnalysisFields * fields); + + +static void +gst_field_analysis_reset (GstFieldAnalysis * filter) +{ + if (filter->frames) { + guint length = g_queue_get_length (filter->frames); + GST_DEBUG_OBJECT (filter, "Clearing queue (size %u)", length); + while (length) { + /* each buffer in the queue should have a ref on it and so to clear the + * queue we must pop and unref each buffer here */ + gst_buffer_unref (g_queue_pop_head (filter->frames)); + length--; + } + } + GST_DEBUG_OBJECT (filter, "Resetting context"); + memset (filter->results, 0, 2 * sizeof (FieldAnalysis)); + filter->is_telecine = FALSE; + filter->first_buffer = TRUE; + filter->width = 0; + g_free (filter->comb_mask); + g_free (filter->block_scores); +} + +static void +gst_field_analysis_init (GstFieldAnalysis * filter, + GstFieldAnalysisClass * gclass) +{ + filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); + gst_pad_set_setcaps_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_field_analysis_set_caps)); + gst_pad_set_getcaps_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps)); + gst_pad_set_event_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_field_analysis_sink_event)); + gst_pad_set_chain_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_field_analysis_chain)); + + filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_set_getcaps_function (filter->srcpad, + GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps)); + + gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); + + filter->frames = g_queue_new (); + gst_field_analysis_reset (filter); + filter->same_field = &same_parity_ssd; + filter->field_thresh = DEFAULT_FIELD_THRESH; + filter->same_frame = &opposite_parity_5_tap; + filter->frame_thresh = DEFAULT_FRAME_THRESH; + filter->noise_floor = DEFAULT_NOISE_FLOOR; + filter->block_score_for_row = &block_score_for_row_5_tap; + filter->spatial_thresh = DEFAULT_SPATIAL_THRESH; + filter->block_width = DEFAULT_BLOCK_WIDTH; + filter->block_height = DEFAULT_BLOCK_HEIGHT; + filter->block_thresh = DEFAULT_BLOCK_THRESH; + filter->ignored_lines = DEFAULT_IGNORED_LINES; +} + +static void +gst_field_analysis_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstFieldAnalysis *filter = GST_FIELDANALYSIS (object); + + switch (prop_id) { + case PROP_FIELD_METRIC: + switch (g_value_get_enum (value)) { + case GST_FIELDANALYSIS_SAD: + filter->same_field = &same_parity_sad; + break; + case GST_FIELDANALYSIS_SSD: + filter->same_field = &same_parity_ssd; + break; + case GST_FIELDANALYSIS_3_TAP: + filter->same_field = &same_parity_3_tap; + break; + default: + break; + } + break; + case PROP_FRAME_METRIC: + switch (g_value_get_enum (value)) { + case GST_FIELDANALYSIS_5_TAP: + filter->same_frame = &opposite_parity_5_tap; + break; + case GST_FIELDANALYSIS_WINDOWED_COMB: + filter->same_frame = &opposite_parity_windowed_comb; + break; + default: + break; + } + break; + case PROP_NOISE_FLOOR: + filter->noise_floor = g_value_get_uint (value); + break; + case PROP_FIELD_THRESH: + filter->field_thresh = g_value_get_float (value); + break; + case PROP_FRAME_THRESH: + filter->frame_thresh = g_value_get_float (value); + break; + case PROP_COMB_METHOD: + switch (g_value_get_enum (value)) { + case METHOD_32DETECT: + filter->block_score_for_row = &block_score_for_row_32detect; + break; + case METHOD_IS_COMBED: + filter->block_score_for_row = &block_score_for_row_iscombed; + break; + case METHOD_5_TAP: + filter->block_score_for_row = &block_score_for_row_5_tap; + break; + default: + break; + } + break; + case PROP_SPATIAL_THRESH: + filter->spatial_thresh = g_value_get_int64 (value); + break; + case PROP_BLOCK_WIDTH: + filter->block_width = g_value_get_uint64 (value); + if (filter->width) { + if (filter->block_scores) { + gsize nbytes = (filter->width / filter->block_width) * sizeof (guint); + filter->block_scores = g_realloc (filter->block_scores, nbytes); + memset (filter->block_scores, 0, nbytes); + } else { + filter->block_scores = + g_malloc0 ((filter->width / filter->block_width) * + sizeof (guint)); + } + } + break; + case PROP_BLOCK_HEIGHT: + filter->block_height = g_value_get_uint64 (value); + break; + case PROP_BLOCK_THRESH: + filter->block_thresh = g_value_get_uint64 (value); + break; + case PROP_IGNORED_LINES: + filter->ignored_lines = g_value_get_uint64 (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_field_analysis_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstFieldAnalysis *filter = GST_FIELDANALYSIS (object); + + switch (prop_id) { + case PROP_FIELD_METRIC: + { + GstFieldAnalysisFieldMetric metric = DEFAULT_FIELD_METRIC; + if (filter->same_field == &same_parity_sad) { + metric = GST_FIELDANALYSIS_SAD; + } else if (filter->same_field == &same_parity_ssd) { + metric = GST_FIELDANALYSIS_SSD; + } else if (filter->same_field == &same_parity_3_tap) { + metric = GST_FIELDANALYSIS_3_TAP; + } + g_value_set_enum (value, metric); + break; + } + case PROP_FRAME_METRIC: + { + GstFieldAnalysisFrameMetric metric = DEFAULT_FRAME_METRIC; + if (filter->same_frame == &opposite_parity_5_tap) { + metric = GST_FIELDANALYSIS_5_TAP; + } else if (filter->same_frame == &opposite_parity_windowed_comb) { + metric = GST_FIELDANALYSIS_WINDOWED_COMB; + } + g_value_set_enum (value, metric); + break; + } + case PROP_NOISE_FLOOR: + g_value_set_uint (value, filter->noise_floor); + break; + case PROP_FIELD_THRESH: + g_value_set_float (value, filter->field_thresh); + break; + case PROP_FRAME_THRESH: + g_value_set_float (value, filter->frame_thresh); + break; + case PROP_COMB_METHOD: + { + FieldAnalysisCombMethod method = DEFAULT_COMB_METHOD; + if (filter->block_score_for_row == &block_score_for_row_32detect) { + method = METHOD_32DETECT; + } else if (filter->block_score_for_row == &block_score_for_row_iscombed) { + method = METHOD_IS_COMBED; + } else if (filter->block_score_for_row == &block_score_for_row_5_tap) { + method = METHOD_5_TAP; + } + g_value_set_enum (value, method); + break; + } + case PROP_SPATIAL_THRESH: + g_value_set_int64 (value, filter->spatial_thresh); + break; + case PROP_BLOCK_WIDTH: + g_value_set_uint64 (value, filter->block_width); + break; + case PROP_BLOCK_HEIGHT: + g_value_set_uint64 (value, filter->block_height); + break; + case PROP_BLOCK_THRESH: + g_value_set_uint64 (value, filter->block_thresh); + break; + case PROP_IGNORED_LINES: + g_value_set_uint64 (value, filter->ignored_lines); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_field_analysis_update_format (GstFieldAnalysis * filter, GstCaps * caps) +{ + GstStructure *struc; + guint32 fourcc; + GstVideoFormat vformat; + gint width, height, data_offset, sample_incr, line_stride; + GQueue *outbufs; + + struc = gst_caps_get_structure (caps, 0); + gst_structure_get_fourcc (struc, "format", &fourcc); + vformat = gst_video_format_from_fourcc (fourcc); + + gst_structure_get_int (struc, "width", &width); + gst_structure_get_int (struc, "height", &height); + + data_offset = + gst_video_format_get_component_offset (vformat, 0, width, height); + sample_incr = gst_video_format_get_pixel_stride (vformat, 0); + line_stride = gst_video_format_get_row_stride (vformat, 0, width); + + /* if format is unchanged in our eyes, don't update the context */ + if ((filter->width == width) && (filter->height == height) + && (filter->data_offset == data_offset) + && (filter->sample_incr == sample_incr) + && (filter->line_stride == line_stride)) + return; + + /* format changed - process and push buffers before updating context */ + + GST_OBJECT_LOCK (filter); + filter->flushing = TRUE; + outbufs = gst_field_analysis_flush_queue (filter, filter->frames); + GST_OBJECT_UNLOCK (filter); + + if (outbufs) { + while (g_queue_get_length (outbufs)) + gst_pad_push (filter->srcpad, g_queue_pop_head (outbufs)); + } + + GST_OBJECT_LOCK (filter); + filter->flushing = FALSE; + + filter->width = width; + filter->height = height; + filter->data_offset = data_offset; + filter->sample_incr = sample_incr; + filter->line_stride = line_stride; + + /* update allocations for metric scores */ + if (filter->comb_mask) { + filter->comb_mask = g_realloc (filter->comb_mask, width); + } else { + filter->comb_mask = g_malloc (width); + } + if (filter->block_scores) { + gsize nbytes = (width / filter->block_width) * sizeof (guint); + filter->block_scores = g_realloc (filter->block_scores, nbytes); + memset (filter->block_scores, 0, nbytes); + } else { + filter->block_scores = + g_malloc0 ((width / filter->block_width) * sizeof (guint)); + } + + GST_OBJECT_UNLOCK (filter); + return; +} + +static gboolean +gst_field_analysis_set_caps (GstPad * pad, GstCaps * caps) +{ + gboolean ret = TRUE; + GstFieldAnalysis *filter = GST_FIELDANALYSIS (gst_pad_get_parent (pad)); + + gst_field_analysis_update_format (filter, caps); + + ret = gst_pad_set_caps (filter->srcpad, caps); + + gst_object_unref (filter); + + return ret; +} + +#define FIELD_ANALYSIS_TOP_BOTTOM (1 << 0) +#define FIELD_ANALYSIS_BOTTOM_TOP (1 << 1) +#define FIELD_ANALYSIS_TOP_MATCH (1 << 2) +#define FIELD_ANALYSIS_BOTTOM_MATCH (1 << 3) + +/* decorate removes a buffer from the internal queue, on which we have a ref, + * then makes its metadata writable (could be the same buffer, could be a new + * buffer, but either way we have a ref on it), decorates this buffer and + * returns it */ +static GstBuffer * +gst_field_analysis_decorate (GstFieldAnalysis * filter, gboolean tff, + gboolean onefield, FieldAnalysisConclusion conclusion, gboolean gap) +{ + GstBuffer *buf = NULL; + GstCaps *caps; + + caps = gst_caps_copy (GST_PAD_CAPS (filter->srcpad)); + + /* deal with incoming buffer */ + if (conclusion > FIELD_ANALYSIS_PROGRESSIVE || filter->is_telecine == TRUE) { + gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL); + filter->is_telecine = conclusion != FIELD_ANALYSIS_INTERLACED; + if (conclusion >= FIELD_ANALYSIS_TELECINE_PROGRESSIVE + || filter->is_telecine == TRUE) { + gst_caps_set_simple (caps, "interlacing-method", G_TYPE_STRING, + "telecine", NULL); + } else { + gst_caps_set_simple (caps, "interlacing-method", G_TYPE_STRING, "unknown", + NULL); + } + } else { + gst_structure_remove_field (gst_caps_get_structure (caps, 0), + "interlacing-method"); + gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL); + } + + /* get buffer from queue + * this takes our ref on the buf that was in the queue and gives us a buf + * on which we have a refi (could be the same buffer, but need not be) */ + buf = gst_buffer_make_metadata_writable (g_queue_pop_head (filter->frames)); + + /* set buffer flags */ + if (!tff) { + GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_TFF); + } else if (tff == 1 || (tff == -1 + && GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_TFF))) { + GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_TFF); + } + + if (onefield) { + GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_ONEFIELD); + } else { + GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_ONEFIELD); + } + + GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_RFF); + + if (gap) + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_GAP); + + if (conclusion == FIELD_ANALYSIS_TELECINE_PROGRESSIVE || (filter->is_telecine + && conclusion == FIELD_ANALYSIS_PROGRESSIVE)) + GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_PROGRESSIVE); + + /* set the caps on the src pad and buffer before pushing */ + if (gst_caps_is_equal (caps, GST_PAD_CAPS (filter->srcpad))) { + gst_buffer_set_caps (buf, GST_PAD_CAPS (filter->srcpad)); + } else { + gboolean ret = TRUE; + + GST_OBJECT_UNLOCK (filter); + ret = gst_pad_set_caps (filter->srcpad, caps); + GST_OBJECT_LOCK (filter); + + if (!ret) { + GST_ERROR_OBJECT (filter, "Could not set pad caps"); + gst_buffer_unref (buf); + return NULL; + } + gst_buffer_set_caps (buf, caps); + } + /* drop our ref to the caps as the buffer and pad have their own */ + gst_caps_unref (caps); + + GST_DEBUG_OBJECT (filter, + "Pushing buffer with flags: %p (%p), p %d, tff %d, 1f %d, gap %d; conc %d", + GST_BUFFER_DATA (buf), buf, + GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_PROGRESSIVE), + GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_TFF), + GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_ONEFIELD), + GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP), conclusion); + + return buf; +} + +/* _flush_one does not touch the buffer ref counts directly but _decorate () + * has some influence on ref counts - see its annotation for details */ +static GstBuffer * +gst_field_analysis_flush_one (GstFieldAnalysis * filter, GQueue * outbufs) +{ + GstBuffer *buf = NULL; + guint n_queued = g_queue_get_length (filter->frames); + guint idx = n_queued - 1; + + if (!n_queued || n_queued > 2) + return buf; + + GST_DEBUG_OBJECT (filter, "Flushing last buffer (queue length %d)", n_queued); + if (filter->results[idx].holding == 1 + TOP_FIELD + || filter->results[idx].holding == 1 + BOTTOM_FIELD) { + /* should be only one field needed */ + buf = + gst_field_analysis_decorate (filter, + filter->results[idx].holding == 1 + TOP_FIELD, TRUE, + filter->results[idx].conclusion, FALSE); + } else { + /* possibility that both fields are needed */ + buf = + gst_field_analysis_decorate (filter, -1, FALSE, + filter->results[idx].conclusion, !filter->results[idx].holding); + } + if (buf) { + if (outbufs) + g_queue_push_tail (outbufs, buf); + } else { + GST_DEBUG_OBJECT (filter, "Error occurred during decoration"); + } + return buf; +} + +/* _flush_queue () has no direct influence on refcounts and nor does _flush_one, + * but _decorate () does and so this function does indirectly */ +static GQueue * +gst_field_analysis_flush_queue (GstFieldAnalysis * filter, GQueue * queue) +{ + GQueue *outbufs; + guint length = 0; + + if (queue) + length = g_queue_get_length (queue); + + if (length < 2) + return NULL; + + outbufs = g_queue_new (); + + while (length) { + gst_field_analysis_flush_one (filter, outbufs); + length--; + } + + return outbufs; +} + +static gboolean +gst_field_analysis_sink_event (GstPad * pad, GstEvent * event) +{ + GstFieldAnalysis *filter = GST_FIELDANALYSIS (gst_pad_get_parent (pad)); + + GST_LOG_OBJECT (pad, "received %s event: %" GST_PTR_FORMAT, + GST_EVENT_TYPE_NAME (event), event); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + case GST_EVENT_EOS: + { + /* for both NEWSEGMENT and EOS it is safest to process and push queued + * buffers */ + GQueue *outbufs; + + GST_OBJECT_LOCK (filter); + filter->flushing = TRUE; + outbufs = gst_field_analysis_flush_queue (filter, filter->frames); + GST_OBJECT_UNLOCK (filter); + + if (outbufs) { + while (g_queue_get_length (outbufs)) + gst_pad_push (filter->srcpad, g_queue_pop_head (outbufs)); + } + + GST_OBJECT_LOCK (filter); + filter->flushing = FALSE; + GST_OBJECT_UNLOCK (filter); + break; + } + case GST_EVENT_FLUSH_STOP: + /* if we have any buffers left in the queue, unref them until the queue + * is empty */ + GST_OBJECT_LOCK (filter); + gst_field_analysis_reset (filter); + GST_OBJECT_UNLOCK (filter); + break; + default: + break; + } + + /* NOTE: we always forward the event currently, change this as necessary */ + return gst_pad_push_event (filter->srcpad, event); +} + + +static gfloat +same_parity_sad (GstFieldAnalysis * filter, FieldAnalysisFields * fields) +{ + gint j; + gfloat sum; + guint8 *f1j, *f2j; + + const gint y_offset = filter->data_offset; + const gint stride = filter->line_stride; + const gint stridex2 = stride << 1; + const guint32 noise_floor = filter->noise_floor; + + f1j = GST_BUFFER_DATA (fields[0].buf) + y_offset + fields[0].parity * stride; + f2j = GST_BUFFER_DATA (fields[1].buf) + y_offset + fields[1].parity * stride; + + sum = 0.0f; + for (j = 0; j < (filter->height >> 1); j++) { + guint32 tempsum = 0; + orc_same_parity_sad_planar_yuv (&tempsum, f1j, f2j, noise_floor, + filter->width); + sum += tempsum; + f1j += stridex2; + f2j += stridex2; + } + + return sum / (0.5f * filter->width * filter->height); +} + +static gfloat +same_parity_ssd (GstFieldAnalysis * filter, FieldAnalysisFields * fields) +{ + gint j; + gfloat sum; + guint8 *f1j, *f2j; + + const gint y_offset = filter->data_offset; + const gint stride = filter->line_stride; + const gint stridex2 = stride << 1; + /* noise floor needs to be squared for SSD */ + const guint32 noise_floor = filter->noise_floor * filter->noise_floor; + + f1j = GST_BUFFER_DATA (fields[0].buf) + y_offset + fields[0].parity * stride; + f2j = GST_BUFFER_DATA (fields[1].buf) + y_offset + fields[1].parity * stride; + + sum = 0.0f; + for (j = 0; j < (filter->height >> 1); j++) { + guint32 tempsum = 0; + orc_same_parity_ssd_planar_yuv (&tempsum, f1j, f2j, noise_floor, + filter->width); + sum += tempsum; + f1j += stridex2; + f2j += stridex2; + } + + return sum / (0.5f * filter->width * filter->height); /* field is half height */ +} + +/* horizontal [1,4,1] diff between fields - is this a good idea or should the + * current sample be emphasised more or less? */ +static gfloat +same_parity_3_tap (GstFieldAnalysis * filter, FieldAnalysisFields * fields) +{ + gint i, j; + gfloat sum; + guint8 *f1j, *f2j; + + const gint y_offset = filter->data_offset; + const gint stride = filter->line_stride; + const gint stridex2 = stride << 1; + const gint incr = filter->sample_incr; + /* noise floor needs to be squared for [1,4,1] */ + const guint32 noise_floor = filter->noise_floor * 6; + + f1j = GST_BUFFER_DATA (fields[0].buf) + y_offset + fields[0].parity * stride; + f2j = GST_BUFFER_DATA (fields[1].buf) + y_offset + fields[1].parity * stride; + + sum = 0.0f; + for (j = 0; j < (filter->height >> 1); j++) { + guint32 tempsum = 0; + guint32 diff; + + /* unroll first as it is a special case */ + diff = abs (((f1j[0] << 2) + (f1j[incr] << 1)) + - ((f2j[0] << 2) + (f2j[incr] << 1))); + if (diff > noise_floor) + sum += diff; + + orc_same_parity_3_tap_planar_yuv (&tempsum, f1j, &f1j[incr], + &f1j[incr << 1], f2j, &f2j[incr], &f2j[incr << 1], noise_floor, + filter->width - 1); + sum += tempsum; + + /* unroll last as it is a special case */ + i = filter->width - 1; + diff = abs (((f1j[i - incr] << 1) + (f1j[i] << 2)) + - ((f2j[i - incr] << 1) + (f2j[i] << 2))); + if (diff > noise_floor) + sum += diff; + + f1j += stridex2; + f2j += stridex2; + } + + return sum / ((6.0f / 2.0f) * filter->width * filter->height); /* 1 + 4 + 1 = 6; field is half height */ +} + +/* vertical [1,-3,4,-3,1] - same as is used in FieldDiff from TIVTC, + * tritical's AVISynth IVTC filter */ +/* 0th field's parity defines operation */ +static gfloat +opposite_parity_5_tap (GstFieldAnalysis * filter, FieldAnalysisFields * fields) +{ + gint j; + gfloat sum; + guint8 *fjm2, *fjm1, *fj, *fjp1, *fjp2; + guint32 tempsum; + + const gint y_offset = filter->data_offset; + const gint stride = filter->line_stride; + const gint stridex2 = stride << 1; + /* noise floor needs to be *6 for [1,-3,4,-3,1] */ + const guint32 noise_floor = filter->noise_floor * 6; + + sum = 0.0f; + + /* fj is line j of the combined frame made from the top field even lines of + * field 0 and the bottom field odd lines from field 1 + * fjp1 is one line down from fj + * fjm2 is two lines up from fj + * fj with j == 0 is the 0th line of the top field + * fj with j == 1 is the 0th line of the bottom field or the 1st field of + * the frame*/ + + /* unroll first line as it is a special case */ + if (fields[0].parity == TOP_FIELD) { + fj = GST_BUFFER_DATA (fields[0].buf) + y_offset; + fjp1 = GST_BUFFER_DATA (fields[1].buf) + y_offset + stride; + } else { + fj = GST_BUFFER_DATA (fields[1].buf) + y_offset; + fjp1 = GST_BUFFER_DATA (fields[0].buf) + y_offset + stride; + } + fjp2 = fj + stridex2; + + tempsum = 0; + orc_opposite_parity_5_tap_planar_yuv (&tempsum, fjp2, fjp1, fj, fjp1, fjp2, + noise_floor, filter->width); + sum += tempsum; + + for (j = 1; j < (filter->height >> 1) - 1; j++) { + /* shift everything down a line in the field of interest (means += stridex2) */ + fjm2 = fj; + fjm1 = fjp1; + fj = fjp2; + fjp1 += stridex2; + fjp2 += stridex2; + + tempsum = 0; + orc_opposite_parity_5_tap_planar_yuv (&tempsum, fjm2, fjm1, fj, fjp1, fjp2, + noise_floor, filter->width); + sum += tempsum; + } + + /* unroll the last line as it is a special case */ + /* shift everything down a line in the field of interest (means += stridex2) */ + fjm2 = fj; + fjm1 = fjp1; + fj = fjp2; + + tempsum = 0; + orc_opposite_parity_5_tap_planar_yuv (&tempsum, fjm2, fjm1, fj, fjm1, fjm2, + noise_floor, filter->width); + sum += tempsum; + + return sum / ((6.0f / 2.0f) * filter->width * filter->height); /* 1 + 4 + 1 == 3 + 3 == 6; field is half height */ +} + +/* this metric was sourced from HandBrake but originally from transcode + * the return value is the highest block score for the row of blocks */ +static inline guint64 +block_score_for_row_32detect (GstFieldAnalysis * filter, guint8 * base_fj, + guint8 * base_fjp1) +{ + guint64 i, j; + guint8 *comb_mask = filter->comb_mask; + guint *block_scores = filter->block_scores; + guint64 block_score; + guint8 *fjm2, *fjm1, *fj, *fjp1; + const gint incr = filter->sample_incr; + const gint stridex2 = filter->line_stride << 1; + const guint64 block_width = filter->block_width; + const guint64 block_height = filter->block_height; + const gint64 spatial_thresh = filter->spatial_thresh; + const gint width = filter->width - (filter->width % block_width); + + fjm2 = base_fj - stridex2; + fjm1 = base_fjp1 - stridex2; + fj = base_fj; + fjp1 = base_fjp1; + + for (j = 0; j < block_height; j++) { + /* we have to work one result ahead of ourselves which results in some small + * peculiarities below */ + gint diff1, diff2; + + diff1 = fj[0] - fjm1[0]; + diff2 = fj[0] - fjp1[0]; + /* change in the same direction */ + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[0] = abs (fj[0] - fjm2[0]) < 10 && abs (fj[0] - fjm1[0]) > 15; + } else { + comb_mask[0] = FALSE; + } + + for (i = 1; i < width; i++) { + const guint64 idx = i * incr; + const guint64 res_idx = (i - 1) / block_width; + + diff1 = fj[idx] - fjm1[idx]; + diff2 = fj[idx] - fjp1[idx]; + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[i] = abs (fj[idx] - fjm2[idx]) < 10 + && abs (fj[idx] - fjm1[idx]) > 15; + } else { + comb_mask[i] = FALSE; + } + + if (i == 1 && comb_mask[i - 1] && comb_mask[i]) { + /* left edge */ + block_scores[res_idx]++; + } else if (i == width - 1) { + /* right edge */ + if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) + block_scores[res_idx]++; + if (comb_mask[i - 1] && comb_mask[i]) + block_scores[i / block_width]++; + } else if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) { + block_scores[res_idx]++; + } + } + /* advance down a line */ + fjm2 = fjm1; + fjm1 = fj; + fj = fjp1; + fjp1 = fjm1 + stridex2; + } + + block_score = 0; + for (i = 0; i < width / block_width; i++) { + if (block_scores[i] > block_score) + block_score = block_scores[i]; + } + + g_free (block_scores); + g_free (comb_mask); + return block_score; +} + +/* this metric was sourced from HandBrake but originally from + * tritical's isCombedT Avisynth function + * the return value is the highest block score for the row of blocks */ +static inline guint64 +block_score_for_row_iscombed (GstFieldAnalysis * filter, guint8 * base_fj, + guint8 * base_fjp1) +{ + guint64 i, j; + guint8 *comb_mask = filter->comb_mask; + guint *block_scores = filter->block_scores; + guint64 block_score; + guint8 *fjm1, *fj, *fjp1; + const gint incr = filter->sample_incr; + const gint stridex2 = filter->line_stride << 1; + const guint64 block_width = filter->block_width; + const guint64 block_height = filter->block_height; + const gint64 spatial_thresh = filter->spatial_thresh; + const gint64 spatial_thresh_squared = spatial_thresh * spatial_thresh; + const gint width = filter->width - (filter->width % block_width); + + fjm1 = base_fjp1 - stridex2; + fj = base_fj; + fjp1 = base_fjp1; + + for (j = 0; j < block_height; j++) { + /* we have to work one result ahead of ourselves which results in some small + * peculiarities below */ + gint diff1, diff2; + + diff1 = fj[0] - fjm1[0]; + diff2 = fj[0] - fjp1[0]; + /* change in the same direction */ + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[0] = + (fjm1[0] - fj[0]) * (fjp1[0] - fj[0]) > spatial_thresh_squared; + } else { + comb_mask[0] = FALSE; + } + + for (i = 1; i < width; i++) { + const guint64 idx = i * incr; + const guint64 res_idx = (i - 1) / block_width; + + diff1 = fj[idx] - fjm1[idx]; + diff2 = fj[idx] - fjp1[idx]; + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[i] = + (fjm1[idx] - fj[idx]) * (fjp1[idx] - fj[idx]) > + spatial_thresh_squared; + } else { + comb_mask[i] = FALSE; + } + + if (i == 1 && comb_mask[i - 1] && comb_mask[i]) { + /* left edge */ + block_scores[res_idx]++; + } else if (i == width - 1) { + /* right edge */ + if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) + block_scores[res_idx]++; + if (comb_mask[i - 1] && comb_mask[i]) + block_scores[i / block_width]++; + } else if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) { + block_scores[res_idx]++; + } + } + /* advance down a line */ + fjm1 = fj; + fj = fjp1; + fjp1 = fjm1 + stridex2; + } + + block_score = 0; + for (i = 0; i < width / block_width; i++) { + if (block_scores[i] > block_score) + block_score = block_scores[i]; + } + + g_free (block_scores); + g_free (comb_mask); + return block_score; +} + +/* this metric was sourced from HandBrake but originally from + * tritical's isCombedT Avisynth function + * the return value is the highest block score for the row of blocks */ +static inline guint64 +block_score_for_row_5_tap (GstFieldAnalysis * filter, guint8 * base_fj, + guint8 * base_fjp1) +{ + guint64 i, j; + guint8 *comb_mask = filter->comb_mask; + guint *block_scores = filter->block_scores; + guint64 block_score; + guint8 *fjm2, *fjm1, *fj, *fjp1, *fjp2; + const gint incr = filter->sample_incr; + const gint stridex2 = filter->line_stride << 1; + const guint64 block_width = filter->block_width; + const guint64 block_height = filter->block_height; + const gint64 spatial_thresh = filter->spatial_thresh; + const gint64 spatial_threshx6 = 6 * spatial_thresh; + const gint width = filter->width - (filter->width % block_width); + + fjm2 = base_fj - stridex2; + fjm1 = base_fjp1 - stridex2; + fj = base_fj; + fjp1 = base_fjp1; + fjp2 = fj + stridex2; + + for (j = 0; j < block_height; j++) { + /* we have to work one result ahead of ourselves which results in some small + * peculiarities below */ + gint diff1, diff2; + + diff1 = fj[0] - fjm1[0]; + diff2 = fj[0] - fjp1[0]; + /* change in the same direction */ + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[0] = + abs (fjm2[0] + (fj[0] << 2) + fjp2[0] - 3 * (fjm1[0] + fjp1[0])) > + spatial_threshx6; + + /* motion detection that needs previous and next frames + this isn't really necessary, but acts as an optimisation if the + additional delay isn't a problem + if (motion_detection) { + if (abs(fpj[idx] - fj[idx] ) > motion_thresh && + abs( fjm1[idx] - fnjm1[idx]) > motion_thresh && + abs( fjp1[idx] - fnjp1[idx]) > motion_thresh) + motion++; + if (abs( fj[idx] - fnj[idx]) > motion_thresh && + abs(fpjm1[idx] - fjm1[idx] ) > motion_thresh && + abs(fpjp1[idx] - fjp1[idx] ) > motion_thresh) + motion++; + } else { + motion = 1; + } + */ + } else { + comb_mask[0] = FALSE; + } + + for (i = 1; i < width; i++) { + const guint64 idx = i * incr; + const guint64 res_idx = (i - 1) / block_width; + + diff1 = fj[idx] - fjm1[idx]; + diff2 = fj[idx] - fjp1[idx]; + if ((diff1 > spatial_thresh && diff2 > spatial_thresh) + || (diff1 < -spatial_thresh && diff2 < -spatial_thresh)) { + comb_mask[i] = + abs (fjm2[idx] + (fj[idx] << 2) + fjp2[idx] - 3 * (fjm1[idx] + + fjp1[idx])) > spatial_threshx6; + } else { + comb_mask[i] = FALSE; + } + + if (i == 1 && comb_mask[i - 1] && comb_mask[i]) { + /* left edge */ + block_scores[res_idx]++; + } else if (i == width - 1) { + /* right edge */ + if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) + block_scores[res_idx]++; + if (comb_mask[i - 1] && comb_mask[i]) + block_scores[i / block_width]++; + } else if (comb_mask[i - 2] && comb_mask[i - 1] && comb_mask[i]) { + block_scores[res_idx]++; + } + } + /* advance down a line */ + fjm2 = fjm1; + fjm1 = fj; + fj = fjp1; + fjp1 = fjp2; + fjp2 = fj + stridex2; + } + + block_score = 0; + for (i = 0; i < width / block_width; i++) { + if (block_scores[i] > block_score) + block_score = block_scores[i]; + } + + g_free (block_scores); + g_free (comb_mask); + return block_score; +} + +/* a pass is made over the field using one of three comb-detection metrics + and the results are then analysed block-wise. if the samples to the left + and right are combed, they contribute to the block score. if the block + score is above the given threshold, the frame is combed. if the block + score is between half the threshold and the threshold, the block is + slightly combed. if when analysis is complete, slight combing is detected + that is returned. if any results are observed that are above the threshold, + the function returns immediately */ +/* 0th field's parity defines operation */ +static gfloat +opposite_parity_windowed_comb (GstFieldAnalysis * filter, + FieldAnalysisFields * fields) +{ + gint j; + gboolean slightly_combed; + + const gint y_offset = filter->data_offset; + const gint stride = filter->line_stride; + const guint64 block_thresh = filter->block_thresh; + const guint64 block_height = filter->block_height; + guint8 *base_fj, *base_fjp1; + + if (fields[0].parity == TOP_FIELD) { + base_fj = GST_BUFFER_DATA (fields[0].buf) + y_offset; + base_fjp1 = GST_BUFFER_DATA (fields[1].buf) + y_offset + stride; + } else { + base_fj = GST_BUFFER_DATA (fields[1].buf) + y_offset; + base_fjp1 = GST_BUFFER_DATA (fields[0].buf) + y_offset + stride; + } + + /* we operate on a row of blocks of height block_height through each iteration */ + slightly_combed = FALSE; + for (j = 0; j <= filter->height - filter->ignored_lines - block_height; + j += block_height) { + guint64 line_offset = (filter->ignored_lines + j) * stride; + guint block_score = + filter->block_score_for_row (filter, base_fj + line_offset, + base_fjp1 + line_offset); + + if (block_score > (block_thresh >> 1) + && block_score <= block_thresh) { + /* blend if nothing more combed comes along */ + slightly_combed = TRUE; + } else if (block_score > block_thresh) { + GstCaps *caps = GST_BUFFER_CAPS (fields[0].buf); + GstStructure *struc = gst_caps_get_structure (caps, 0); + gboolean interlaced; + if (gst_structure_get_boolean (struc, "interlaced", &interlaced) + && interlaced == TRUE) { + return 1.0f; /* blend */ + } else { + return 2.0f; /* deinterlace */ + } + } + } + + return (gfloat) slightly_combed; /* TRUE means blend, else don't */ +} + +/* this is where the magic happens + * + * the buffer incoming to the chain function (buf_to_queue) is added to the + * internal queue and then should no longer be used until it is popped from the + * queue. + * + * analysis is performed on the incoming buffer (peeked from the queue) and the + * previous buffer using two classes of metrics making up five individual + * scores. + * + * there are two same-parity comparisons: top of current with top of previous + * and bottom of current with bottom of previous + * + * there are three opposing parity comparisons: top of current with bottom of + * _current_, top of current with bottom of previous and bottom of current with + * top of previous. + * + * from the results of these comparisons we can use some rather complex logic to + * identify the state of the previous buffer, decorate and return it and + * identify some preliminary state of the current buffer. + * + * the returned buffer has a ref on it (it has come from _make_metadata_writable + * that was called on an incoming buffer that was queued and then popped) */ +static GstBuffer * +gst_field_analysis_process_buffer (GstFieldAnalysis * filter, + GstBuffer ** buf_to_queue) +{ + GQueue *queue; + guint n_queued; + /* res0/1 correspond to f0/1 */ + FieldAnalysis *res0, *res1; + FieldAnalysisFields fields[2]; + GstBuffer *outbuf = NULL; + + queue = filter->frames; + + /* move previous result to res1 */ + filter->results[1] = filter->results[0]; + + res0 = &filter->results[0]; /* results for current frame */ + res1 = &filter->results[1]; /* results for previous frame */ + + /* we have a ref on buf_to_queue when it is added to the queue */ + g_queue_push_tail (queue, (gpointer) * buf_to_queue); + /* WARNING: buf_to_queue must not be used again!!! */ + *buf_to_queue = NULL; + + n_queued = g_queue_get_length (queue); + + /* we do it like this because the first frame has no predecessor so this is + * the only result we can get for it */ + if (n_queued >= 1) { + /* compare the fields within the buffer, if the buffer exhibits combing it + * could be interlaced or a mixed telecine frame */ + fields[0].buf = fields[1].buf = g_queue_peek_tail (queue); + fields[0].parity = TOP_FIELD; + fields[1].parity = BOTTOM_FIELD; + res0->f = filter->same_frame (filter, fields); + res0->t = res0->b = res0->t_b = res0->b_t = G_MAXINT64; + if (n_queued == 1) + GST_DEBUG_OBJECT (filter, "Scores: f %f, t , b , t_b , b_t ", res0->f); + if (res0->f <= filter->frame_thresh) { + res0->conclusion = FIELD_ANALYSIS_PROGRESSIVE; + } else { + res0->conclusion = FIELD_ANALYSIS_INTERLACED; + } + res0->holding = -1; /* needed fields unknown */ + res0->gap = FALSE; + } + + if (n_queued >= 2) { + guint telecine_matches; + gboolean first_buffer = filter->first_buffer; + + filter->first_buffer = FALSE; + + fields[1].buf = g_queue_peek_nth (queue, n_queued - 2); + + /* compare the top and bottom fields to the previous frame */ + fields[0].parity = TOP_FIELD; + fields[1].parity = TOP_FIELD; + res0->t = filter->same_field (filter, fields); + fields[0].parity = BOTTOM_FIELD; + fields[1].parity = BOTTOM_FIELD; + res0->b = filter->same_field (filter, fields); + + /* compare the top field from this frame to the bottom of the previous for + * for combing (and vice versa) */ + fields[0].parity = TOP_FIELD; + fields[1].parity = BOTTOM_FIELD; + res0->t_b = filter->same_frame (filter, fields); + fields[0].parity = BOTTOM_FIELD; + fields[1].parity = TOP_FIELD; + res0->b_t = filter->same_frame (filter, fields); + + GST_DEBUG_OBJECT (filter, + "Scores: f %f, t %f, b %f, t_b %f, b_t %f", res0->f, + res0->t, res0->b, res0->t_b, res0->b_t); + + /* analysis */ + telecine_matches = 0; + if (res0->t_b <= filter->frame_thresh) + telecine_matches |= FIELD_ANALYSIS_TOP_BOTTOM; + if (res0->b_t <= filter->frame_thresh) + telecine_matches |= FIELD_ANALYSIS_BOTTOM_TOP; + /* normally if there is a top or bottom field match, it is significantly + * smaller than the other match - try 10% */ + if (res0->t <= filter->field_thresh || res0->t * (100 / 10) < res0->b) + telecine_matches |= FIELD_ANALYSIS_TOP_MATCH; + if (res0->b <= filter->field_thresh || res0->b * (100 / 10) < res0->t) + telecine_matches |= FIELD_ANALYSIS_BOTTOM_MATCH; + + if (telecine_matches & (FIELD_ANALYSIS_TOP_MATCH | + FIELD_ANALYSIS_BOTTOM_MATCH)) { + /* we have a repeated field => some kind of telecine */ + if (res1->f <= filter->frame_thresh) { + /* prev P */ + if ((telecine_matches & FIELD_ANALYSIS_TOP_MATCH) + && (telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH)) { + /* prev P, cur repeated => cur P */ + res0->conclusion = FIELD_ANALYSIS_TELECINE_PROGRESSIVE; + res0->holding = 1 + BOTH_FIELDS; + /* push prev P, GAP */ + res1->gap = TRUE; + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } else { + /* prev P, cur t xor b matches => cur TCM */ + res0->conclusion = FIELD_ANALYSIS_TELECINE_MIXED; + /* hold non-repeated: if bottom match, hold top = 1 + 0 */ + res0->holding = 1 + !(telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH); + /* push prev P */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } + } else { + /* prev !P */ + gboolean b, t; + + if (res0->f <= filter->frame_thresh) { + /* cur P */ + res0->conclusion = FIELD_ANALYSIS_TELECINE_PROGRESSIVE; + res0->holding = 1 + BOTH_FIELDS; + } else { + /* cur !P */ + res0->conclusion = FIELD_ANALYSIS_TELECINE_MIXED; + if (telecine_matches & FIELD_ANALYSIS_TOP_MATCH + && telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH) { + /* cur t && b */ + res0->holding = 0; + } else { + /* cur t xor b; hold non-repeated */ + res0->holding = + 1 + !(telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH); + } + } + + if (res1->holding == -1) { + b = t = TRUE; + } else { + b = res1->holding == 1 + BOTTOM_FIELD; + t = res1->holding == 1 + TOP_FIELD; + } + + if ((t && telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH) || (b + && telecine_matches & FIELD_ANALYSIS_TOP_MATCH)) { + if (t && telecine_matches & FIELD_ANALYSIS_BOTTOM_MATCH) { + res1->holding = 1 + TOP_FIELD; + } else if (b && telecine_matches & FIELD_ANALYSIS_TOP_MATCH) { + res1->holding = 1 + BOTTOM_FIELD; + } + /* push 1F held field */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } else if (res0->f > filter->frame_thresh && ((t + && telecine_matches & FIELD_ANALYSIS_BOTTOM_TOP) || (b + && telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM))) { + if (t && telecine_matches & FIELD_ANALYSIS_BOTTOM_TOP) { + res1->holding = 1 + TOP_FIELD; + } else if (b && telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM) { + res1->holding = 1 + BOTTOM_FIELD; + } + res0->conclusion = FIELD_ANALYSIS_TELECINE_MIXED; + /* hold the opposite field to the one held in the last frame */ + res0->holding = 1 + (res1->holding == 1 + TOP_FIELD); + /* push 1F held field */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } else if (first_buffer && (telecine_matches & FIELD_ANALYSIS_BOTTOM_TOP + || telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM)) { + /* non-matched field is an orphan in the first buffer - push orphan as 1F */ + res1->conclusion = FIELD_ANALYSIS_TELECINE_MIXED; + /* if prev b matched, prev t is orphan */ + res1->holding = 1 + !(telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM); + /* push 1F held field */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } else if (res1->holding == 1 + BOTH_FIELDS || res1->holding == -1) { + /* holding both fields, push prev as is */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } else { + /* push prev as is with GAP */ + res1->gap = TRUE; + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } + } + } else if (res0->f <= filter->frame_thresh) { + /* cur P */ + res0->conclusion = FIELD_ANALYSIS_PROGRESSIVE; + res0->holding = 1 + BOTH_FIELDS; + if (res1->holding == 1 + BOTH_FIELDS || res1->holding == -1) { + /* holding both fields, push prev as is */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } else if (res1->holding > 0) { + /* holding one field, push prev 1F held */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } else { + /* unknown or no fields held, push prev as is with GAP */ + /* this will push unknown as gap - should be pushed as not gap? */ + res1->gap = TRUE; + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } + } else { + /* cur !P */ + if (telecine_matches & (FIELD_ANALYSIS_TOP_BOTTOM | + FIELD_ANALYSIS_BOTTOM_TOP)) { + /* cross-parity match => TCM */ + gboolean b, t; + + if (res1->holding == -1) { + b = t = TRUE; + } else { + b = res1->holding == 1 + BOTTOM_FIELD; + t = res1->holding == 1 + TOP_FIELD; + } + + res0->conclusion = FIELD_ANALYSIS_TELECINE_MIXED; + /* leave holding as unknown */ + if (res1->holding == 1 + BOTH_FIELDS) { + /* prev P/TCP/I [or TCM repeated (weird case)] */ + /* push prev as is */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } else if ((t && telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM) || (b + && telecine_matches & FIELD_ANALYSIS_BOTTOM_TOP)) { + /* held is opposite to matched => need both field from prev */ + /* if t_b, hold bottom from prev and top from current, else vice-versa */ + res1->holding = 1 + ! !(telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM); + res0->holding = 1 + !(telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM); + /* push prev TCM */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } else if ((res1->holding > 0 && res1->holding != 1 + BOTH_FIELDS) || (t + && telecine_matches & FIELD_ANALYSIS_BOTTOM_TOP) || (b + && telecine_matches & FIELD_ANALYSIS_TOP_BOTTOM)) { + /* held field is needed, push prev 1F held */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } else { + /* holding none or unknown */ + /* push prev as is with GAP */ + res1->gap = TRUE; + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } + } else { + /* cur I */ + res0->conclusion = FIELD_ANALYSIS_INTERLACED; + res0->holding = 1 + BOTH_FIELDS; + /* push prev appropriately */ + res1->gap = res1->holding <= 0; + if (res1->holding != 0) { + res1->gap = FALSE; + if (res1->holding == 1 + BOTH_FIELDS || res1->holding == -1) { + /* push prev as is */ + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, + res1->conclusion, res1->gap); + } else { + /* push prev 1F held */ + outbuf = + gst_field_analysis_decorate (filter, !(res1->holding - 1), TRUE, + res1->conclusion, res1->gap); + } + } else { + /* push prev as is with GAP */ + res1->gap = TRUE; + outbuf = + gst_field_analysis_decorate (filter, -1, FALSE, res1->conclusion, + res1->gap); + } + } + } + } + + switch (res0->conclusion) { + case FIELD_ANALYSIS_PROGRESSIVE: + GST_DEBUG_OBJECT (filter, "Conclusion: PROGRESSIVE"); + break; + case FIELD_ANALYSIS_INTERLACED: + GST_DEBUG_OBJECT (filter, "Conclusion: INTERLACED"); + break; + case FIELD_ANALYSIS_TELECINE_PROGRESSIVE: + GST_DEBUG_OBJECT (filter, "Conclusion: TC PROGRESSIVE"); + break; + case FIELD_ANALYSIS_TELECINE_MIXED: + GST_DEBUG_OBJECT (filter, "Conclusion: TC MIXED %s", + res0->holding == + 1 + BOTH_FIELDS ? "top and bottom" : res0->holding == + 1 + BOTTOM_FIELD ? "bottom" : "top"); + break; + default: + GST_DEBUG_OBJECT (filter, "Invalid conclusion! This is a bug!"); + break; + } + + GST_DEBUG_OBJECT (filter, "Items remaining in the queue: %d", + g_queue_get_length (queue)); + + return outbuf; +} + +/* we have a ref on buf when it comes into chain */ +static GstFlowReturn +gst_field_analysis_chain (GstPad * pad, GstBuffer * buf) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstFieldAnalysis *filter; + GstBuffer *outbuf = NULL; + + filter = GST_FIELDANALYSIS (GST_OBJECT_PARENT (pad)); + + GST_OBJECT_LOCK (filter); + if (filter->flushing) { + GST_DEBUG_OBJECT (filter, "We are flushing."); + /* we have a ref on buf so it must be unreffed */ + goto unref_unlock_ret; + } + + if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { + GST_DEBUG_OBJECT (filter, "Discont: flushing"); + /* we should have a ref on outbuf, either because we had one when it entered + * the queue and _make_metadata_writable () inside _decorate () returned + * the same buffer or because it returned a new buffer on which we have one + * ref */ + outbuf = gst_field_analysis_flush_one (filter, NULL); + + if (outbuf) { + /* we give away our ref on outbuf here */ + GST_OBJECT_UNLOCK (filter); + ret = gst_pad_push (filter->srcpad, outbuf); + GST_OBJECT_LOCK (filter); + if (filter->flushing) { + GST_DEBUG_OBJECT (filter, "We are flushing. outbuf already pushed."); + /* we have a ref on buf so it must be unreffed */ + goto unref_unlock_ret; + } + } + + gst_field_analysis_reset (filter); + + if (ret != GST_FLOW_OK) { + GST_DEBUG_OBJECT (filter, + "Pushing of flushed buffer failed with return %d", ret); + /* we have a ref on buf so it must be unreffed */ + goto unref_unlock_ret; + } else { + outbuf = NULL; + } + } + + /* after this function, buf has been pushed to the internal queue and its ref + * retained there and we have a ref on outbuf */ + outbuf = gst_field_analysis_process_buffer (filter, &buf); + + GST_OBJECT_UNLOCK (filter); + + /* here we give up our ref on outbuf */ + if (outbuf) + ret = gst_pad_push (filter->srcpad, outbuf); + + return ret; + +unref_unlock_ret: + /* we must unref the input buffer here */ + gst_buffer_unref (buf); + GST_OBJECT_UNLOCK (filter); + return ret; +} + +static GstStateChangeReturn +gst_field_analysis_change_state (GstElement * element, + GstStateChange transition) +{ + GstStateChangeReturn ret; + GstFieldAnalysis *filter = GST_FIELDANALYSIS (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret != GST_STATE_CHANGE_SUCCESS) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_field_analysis_reset (filter); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + default: + break; + } + + return ret; +} + +static void +gst_field_analysis_finalize (GObject * object) +{ + GstFieldAnalysis *filter = GST_FIELDANALYSIS (object); + + gst_field_analysis_reset (filter); + g_queue_free (filter->frames); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + +static gboolean +fieldanalysis_init (GstPlugin * fieldanalysis) +{ + GST_DEBUG_CATEGORY_INIT (gst_field_analysis_debug, "fieldanalysis", + 0, "Video field analysis"); + + gst_fieldanalysis_orc_init (); + + return gst_element_register (fieldanalysis, "fieldanalysis", GST_RANK_NONE, + GST_TYPE_FIELDANALYSIS); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "fieldanalysis", + "Video field analysis", + fieldanalysis_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") diff --git a/gst/fieldanalysis/gstfieldanalysis.h b/gst/fieldanalysis/gstfieldanalysis.h new file mode 100644 index 0000000000..7b95871af2 --- /dev/null +++ b/gst/fieldanalysis/gstfieldanalysis.h @@ -0,0 +1,144 @@ +/* + * GStreamer + * Copyright (C) 2010 Robert Swain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_FIELDANALYSIS_H__ +#define __GST_FIELDANALYSIS_H__ + +#include + +G_BEGIN_DECLS +#define GST_TYPE_FIELDANALYSIS \ + (gst_field_analysis_get_type()) +#define GST_FIELDANALYSIS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FIELDANALYSIS,GstFieldAnalysis)) +#define GST_FIELDANALYSIS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FIELDANALYSIS,GstFieldAnalysisClass)) +#define GST_IS_FIELDANALYSIS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FIELDANALYSIS)) +#define GST_IS_FIELDANALYSIS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FIELDANALYSIS)) + +typedef struct _GstFieldAnalysis GstFieldAnalysis; +typedef struct _GstFieldAnalysisClass GstFieldAnalysisClass; +typedef struct _FieldAnalysisFields FieldAnalysisFields; +typedef struct _FieldAnalysis FieldAnalysis; + +typedef enum +{ + FIELD_ANALYSIS_PROGRESSIVE, + FIELD_ANALYSIS_INTERLACED, + FIELD_ANALYSIS_TELECINE_PROGRESSIVE, + FIELD_ANALYSIS_TELECINE_MIXED +} FieldAnalysisConclusion; + +enum FieldParity +{ + TOP_FIELD, + BOTTOM_FIELD, + BOTH_FIELDS +}; + +struct _FieldAnalysisFields +{ + GstBuffer *buf; + gboolean parity; +}; + +struct _FieldAnalysis +{ + /* frame, top, bottom, top with prev bottom, bottom with prev top */ + gfloat f, t, b, t_b, b_t; + FieldAnalysisConclusion conclusion; + /* -1 - unknown; 0 - holding none; 1 - top field; 2 - bottom field; 3 - both */ + gint holding; + gboolean gap; +}; + +typedef enum +{ + METHOD_32DETECT, + METHOD_IS_COMBED, + METHOD_5_TAP +} FieldAnalysisCombMethod; + +struct _GstFieldAnalysis +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + GQueue *frames; + gint width, height; + gint data_offset; + gint line_stride; /* step size in bytes from the 0th sample of one line to the next */ + gint sample_incr; /* step size in bytes from one sample to the next */ + FieldAnalysis results[2]; + gfloat (*same_field) (GstFieldAnalysis *, FieldAnalysisFields *); + gfloat (*same_frame) (GstFieldAnalysis *, FieldAnalysisFields *); + guint64 (*block_score_for_row) (GstFieldAnalysis *, guint8 *, guint8 *); + gboolean is_telecine; + gboolean first_buffer; /* indicates the first buffer for which a buffer will be output + * after a discont or flushing seek */ + guint8 *comb_mask; + guint *block_scores; + gboolean flushing; /* indicates whether we are flushing or not */ + + /* properties */ + guint32 noise_floor; /* threshold for the result of a metric to be valid */ + gfloat field_thresh; /* threshold used for the same parity field metric */ + gfloat frame_thresh; /* threshold used for the opposite parity field metric */ + gint64 spatial_thresh; /* threshold used spatial comb detection */ + guint64 block_width, block_height; /* width/height of window used for comb clusted detection */ + guint64 block_thresh; + guint64 ignored_lines; +}; + +struct _GstFieldAnalysisClass +{ + GstElementClass parent_class; +}; + +GType gst_field_analysis_get_type (void); + +G_END_DECLS +#endif /* __GST_FIELDANALYSIS_H__ */ diff --git a/gst/fieldanalysis/gstfieldanalysisorc.orc b/gst/fieldanalysis/gstfieldanalysisorc.orc new file mode 100644 index 0000000000..42ae222302 --- /dev/null +++ b/gst/fieldanalysis/gstfieldanalysisorc.orc @@ -0,0 +1,119 @@ + +.init gst_fieldanalysis_orc_init + + +.function orc_same_parity_sad_planar_yuv +.accumulator 4 a1 guint32 +.source 1 s1 +.source 1 s2 +# noise threshold +.param 4 nt +.temp 2 t1 +.temp 2 t2 +.temp 4 t3 +.temp 4 t4 + +convubw t1, s1 +convubw t2, s2 +subw t1, t1, t2 +absw t1, t1 +convuwl t3, t1 +cmpgtsl t4, t3, nt +andl t3, t3, t4 +accl a1, t3 + + +.function orc_same_parity_ssd_planar_yuv +.accumulator 4 a1 guint32 +.source 1 s1 +.source 1 s2 +# noise threshold +.param 4 nt +.temp 2 t1 +.temp 2 t2 +.temp 4 t3 +.temp 4 t4 + +convubw t1, s1 +convubw t2, s2 +subw t1, t1, t2 +mulswl t3, t1, t1 +cmpgtsl t4, t3, nt +andl t3, t3, t4 +accl a1, t3 + + +.function orc_same_parity_3_tap_planar_yuv +.accumulator 4 a1 guint32 +.source 1 s1 +.source 1 s2 +.source 1 s3 +.source 1 s4 +.source 1 s5 +.source 1 s6 +# noise threshold +.param 4 nt +.temp 2 t1 +.temp 2 t2 +.temp 2 t3 +.temp 2 t4 +.temp 2 t5 +.temp 2 t6 +.temp 4 t7 +.temp 4 t8 + +convubw t1, s1 +convubw t2, s2 +convubw t3, s3 +convubw t4, s4 +convubw t5, s5 +convubw t6, s6 +shlw t2, t2, 2 +shlw t5, t5, 2 +addw t1, t1, t2 +addw t1, t1, t3 +addw t4, t4, t5 +addw t4, t4, t6 +subw t1, t1, t4 +absw t1, t1 +convuwl t7, t1 +cmpgtsl t8, t7, nt +andl t7, t7, t8 +accl a1, t7 + + +.function orc_opposite_parity_5_tap_planar_yuv +.accumulator 4 a1 guint32 +.source 1 s1 +.source 1 s2 +.source 1 s3 +.source 1 s4 +.source 1 s5 +# noise threshold +.param 4 nt +.temp 2 t1 +.temp 2 t2 +.temp 2 t3 +.temp 2 t4 +.temp 2 t5 +.temp 4 t6 +.temp 4 t7 + +convubw t1, s1 +convubw t2, s2 +convubw t3, s3 +convubw t4, s4 +convubw t5, s5 +shlw t3, t3, 2 +mullw t2, t2, 3 +mullw t4, t4, 3 +subw t1, t1, t2 +addw t1, t1, t3 +subw t1, t1, t4 +addw t1, t1, t5 +absw t1, t1 +convuwl t6, t1 +cmpgtsl t7, t6, nt +andl t6, t6, t7 +accl a1, t6 + From 1eb3f7f41fdbef005a62b3f03fdfd373f93c83ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 2 Mar 2011 23:43:42 +0100 Subject: [PATCH 13/20] celtenc: Fix compilation with celt >= 0.11.0 Fixes bug #643607. --- configure.ac | 7 +++++++ ext/celt/gstceltdec.c | 5 +++++ ext/celt/gstceltenc.c | 8 ++++++++ 3 files changed, 20 insertions(+) diff --git a/configure.ac b/configure.ac index a2a38bcf8f..374c7aaa83 100644 --- a/configure.ac +++ b/configure.ac @@ -639,6 +639,13 @@ AG_GST_CHECK_FEATURE(CELT, [celt], celt, [ dnl to prevent an error true ]) + + PKG_CHECK_MODULES(CELT_0_11, celt >= 0.11.0, [ + AC_DEFINE([HAVE_CELT_0_11], 1, [Define if libcelt 0.11 is installed]) + ], [ + dnl to prevent an error + true + ]) AC_SUBST(CELT_CFLAGS) AC_SUBST(CELT_LIBS) ]) diff --git a/ext/celt/gstceltdec.c b/ext/celt/gstceltdec.c index 1b3f4eb613..66c829e4b6 100644 --- a/ext/celt/gstceltdec.c +++ b/ext/celt/gstceltdec.c @@ -510,10 +510,15 @@ celt_dec_chain_parse_header (GstCeltDec * dec, GstBuffer * buf) goto mode_init_failed; /* initialize the decoder */ +#ifdef HAVE_CELT_0_11 + dec->state = + celt_decoder_create_custom (dec->mode, dec->header.nb_channels, &error); +#else #ifdef HAVE_CELT_0_7 dec->state = celt_decoder_create (dec->mode, dec->header.nb_channels, &error); #else dec->state = celt_decoder_create (dec->mode); +#endif #endif if (!dec->state) goto init_failed; diff --git a/ext/celt/gstceltenc.c b/ext/celt/gstceltenc.c index 4fd9ee8d93..74815798e1 100644 --- a/ext/celt/gstceltenc.c +++ b/ext/celt/gstceltenc.c @@ -629,10 +629,14 @@ gst_celt_enc_setup (GstCeltEnc * enc) if (!enc->mode) goto mode_initialization_failed; +#ifdef HAVE_CELT_0_11 + celt_header_init (&enc->header, enc->mode, enc->frame_size, enc->channels); +#else #ifdef HAVE_CELT_0_7 celt_header_init (&enc->header, enc->mode, enc->channels); #else celt_header_init (&enc->header, enc->mode); +#endif #endif enc->header.nb_channels = enc->channels; @@ -642,10 +646,14 @@ gst_celt_enc_setup (GstCeltEnc * enc) celt_mode_info (enc->mode, CELT_GET_FRAME_SIZE, &enc->frame_size); #endif +#ifdef HAVE_CELT_0_11 + enc->state = celt_encoder_create_custom (enc->mode, enc->channels, &error); +#else #ifdef HAVE_CELT_0_7 enc->state = celt_encoder_create (enc->mode, enc->channels, &error); #else enc->state = celt_encoder_create (enc->mode); +#endif #endif if (!enc->state) goto encoder_creation_failed; From 588db0bf51122fe4fb17a98b5dfa95eb8e897693 Mon Sep 17 00:00:00 2001 From: benjamin gaignard Date: Mon, 28 Feb 2011 11:51:54 +0100 Subject: [PATCH 14/20] fpsdisplay: fix sync property default value --- gst/debugutils/fpsdisplaysink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/debugutils/fpsdisplaysink.c b/gst/debugutils/fpsdisplaysink.c index aca421ce60..92f9b019fc 100644 --- a/gst/debugutils/fpsdisplaysink.c +++ b/gst/debugutils/fpsdisplaysink.c @@ -65,6 +65,8 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_DEBUG_CATEGORY_STATIC (fps_display_sink_debug); #define GST_CAT_DEFAULT fps_display_sink_debug +#define DEFAULT_SYNC TRUE + enum { /* FILL ME */ @@ -114,7 +116,7 @@ fps_display_sink_class_init (GstFPSDisplaySinkClass * klass) g_object_class_install_property (gobject_klass, ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Sync on the clock (if the internally used sink doesn't " - "have this property it will be ignored", TRUE, + "have this property it will be ignored", DEFAULT_SYNC, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); g_object_class_install_property (gobject_klass, ARG_TEXT_OVERLAY, @@ -310,7 +312,7 @@ static void fps_display_sink_init (GstFPSDisplaySink * self, GstFPSDisplaySinkClass * g_class) { - self->sync = FALSE; + self->sync = DEFAULT_SYNC; self->signal_measurements = DEFAULT_SIGNAL_FPS_MEASUREMENTS; self->use_text_overlay = TRUE; self->fps_update_interval = GST_MSECOND * DEFAULT_FPS_UPDATE_INTERVAL_MS; From 88cd418bc9668d2b2d5ddfd2b2fa3f677a5e95a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 3 Mar 2011 00:45:11 +0000 Subject: [PATCH 15/20] h263parse: minor clean-ups const-ify some arguments and re-indent header a little. --- gst/videoparsers/h263parse.c | 9 +++++---- gst/videoparsers/h263parse.h | 26 ++++++++++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/gst/videoparsers/h263parse.c b/gst/videoparsers/h263parse.c index ace1e18a2f..993890b65f 100644 --- a/gst/videoparsers/h263parse.c +++ b/gst/videoparsers/h263parse.c @@ -31,7 +31,7 @@ GST_DEBUG_CATEGORY_EXTERN (h263_parse_debug); #define GST_CAT_DEFAULT h263_parse_debug gboolean -gst_h263_parse_is_delta_unit (H263Params * params) +gst_h263_parse_is_delta_unit (const H263Params * params) { return (params->type == PICTURE_I); } @@ -455,7 +455,7 @@ beach: } gint -gst_h263_parse_get_profile (H263Params * params) +gst_h263_parse_get_profile (const H263Params * params) { gboolean c, d, d1, d21, d22, e, f, f2, g, h, i, j, k, k0, k1, k2, l, m, n, o, p, q, r, s, t, u, v, w; @@ -577,7 +577,7 @@ gst_h263_parse_get_profile (H263Params * params) (gst_value_compare (&(f1), &(f2)) == GST_VALUE_EQUAL)) gint -gst_h263_parse_get_level (H263Params * params, gint profile, +gst_h263_parse_get_level (const H263Params * params, gint profile, guint bitrate, gint fps_num, gint fps_denom) { GValue fps15 = { 0, }; @@ -659,7 +659,8 @@ gst_h263_parse_get_level (H263Params * params, gint profile, } void -gst_h263_parse_get_framerate (H263Params * params, gint * num, gint * denom) +gst_h263_parse_get_framerate (const H263Params * params, gint * num, + gint * denom) { *num = params->pcfnum; *denom = params->pcfdenom; diff --git a/gst/videoparsers/h263parse.h b/gst/videoparsers/h263parse.h index 2e66f0e482..344ad3a995 100644 --- a/gst/videoparsers/h263parse.h +++ b/gst/videoparsers/h263parse.h @@ -131,14 +131,24 @@ struct _H263Params gint32 pcfnum, pcfdenom; }; -gboolean gst_h263_parse_is_delta_unit (H263Params * params); -GstFlowReturn gst_h263_parse_get_params (H263Params ** params_p, - GstBuffer * buffer, gboolean fast, H263ParseState * state); -void gst_h263_parse_get_framerate (H263Params * params, - gint * num, gint * denom); -gint gst_h263_parse_get_profile (H263Params * params); -gint gst_h263_parse_get_level (H263Params * params, gint profile, - guint bitrate, gint fps_num, gint fps_denom); +gboolean gst_h263_parse_is_delta_unit (const H263Params * params); + +GstFlowReturn gst_h263_parse_get_params (H263Params ** params_p, + GstBuffer * buffer, + gboolean fast, + H263ParseState * state); + +void gst_h263_parse_get_framerate (const H263Params * params, + gint * num, + gint * denom); + +gint gst_h263_parse_get_profile (const H263Params * params); + +gint gst_h263_parse_get_level (const H263Params * params, + gint profile, + guint bitrate, + gint fps_num, + gint fps_denom); G_END_DECLS #endif From e9b29e9dc71022bf27ccae8f5b290939dfc78b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Thu, 3 Mar 2011 00:57:09 +0000 Subject: [PATCH 16/20] h263parse: allocate H263Params struct on the stack It's flat and not kept around for longer. --- gst/videoparsers/gsth263parse.c | 16 +++++++--------- gst/videoparsers/h263parse.c | 6 +----- gst/videoparsers/h263parse.h | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/gst/videoparsers/gsth263parse.c b/gst/videoparsers/gsth263parse.c index b727f6212e..e6e94acf1a 100644 --- a/gst/videoparsers/gsth263parse.c +++ b/gst/videoparsers/gsth263parse.c @@ -179,7 +179,8 @@ out: } static void -gst_h263_parse_set_src_caps (GstH263Parse * h263parse, H263Params * params) +gst_h263_parse_set_src_caps (GstH263Parse * h263parse, + const H263Params * params) { GstStructure *st; GstCaps *caps, *sink_caps; @@ -283,7 +284,7 @@ gst_h263_parse_check_valid_frame (GstBaseParse * parse, /* If this is the first frame, parse and set srcpad caps */ if (h263parse->state == PARSING) { - H263Params *params = NULL; + H263Params params = { 0, }; GstFlowReturn res; res = gst_h263_parse_get_params (¶ms, buffer, FALSE, &h263parse->state); @@ -293,11 +294,8 @@ gst_h263_parse_check_valid_frame (GstBaseParse * parse, GST_BASE_PARSE_FORMAT_PASSTHROUGH, TRUE); } else { /* Set srcpad caps since we now have sufficient information to do so */ - gst_h263_parse_set_src_caps (h263parse, params); + gst_h263_parse_set_src_caps (h263parse, ¶ms); } - - if (params) - g_free (params); } *skipsize = psc_pos; @@ -325,7 +323,7 @@ gst_h263_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) GstH263Parse *h263parse; GstBuffer *buffer; GstFlowReturn res; - H263Params *params = NULL; + H263Params params = { 0, }; h263parse = GST_H263_PARSE (parse); buffer = frame->buffer; @@ -348,12 +346,12 @@ gst_h263_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) gst_buffer_set_caps (buffer, GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (h263parse)))); - if (gst_h263_parse_is_delta_unit (params)) + if (gst_h263_parse_is_delta_unit (¶ms)) GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); out: - g_free (params); + return res; } diff --git a/gst/videoparsers/h263parse.c b/gst/videoparsers/h263parse.c index 993890b65f..b22c4de194 100644 --- a/gst/videoparsers/h263parse.c +++ b/gst/videoparsers/h263parse.c @@ -40,7 +40,7 @@ gst_h263_parse_is_delta_unit (const H263Params * params) * extract a subset of the data (for now, it quits once we have the picture * type. */ GstFlowReturn -gst_h263_parse_get_params (H263Params ** params_p, GstBuffer * buffer, +gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, gboolean fast, H263ParseState * state) { static const guint8 partable[6][2] = { @@ -72,16 +72,12 @@ gst_h263_parse_get_params (H263Params ** params_p, GstBuffer * buffer, "Extended PType" }; - H263Params *params; GstBitReader br; guint8 tr; guint32 psc, temp32; guint8 temp8, pquant; gboolean hasplusptype; - *params_p = g_new0 (H263Params, 1); - params = *params_p; - /* FIXME: we can optimise a little by checking the value of available * instead of calling using the bit reader's get_bits_* functions. */ gst_bit_reader_init_from_buffer (&br, buffer); diff --git a/gst/videoparsers/h263parse.h b/gst/videoparsers/h263parse.h index 344ad3a995..80eb919ae6 100644 --- a/gst/videoparsers/h263parse.h +++ b/gst/videoparsers/h263parse.h @@ -133,7 +133,7 @@ struct _H263Params gboolean gst_h263_parse_is_delta_unit (const H263Params * params); -GstFlowReturn gst_h263_parse_get_params (H263Params ** params_p, +GstFlowReturn gst_h263_parse_get_params (H263Params * params_p, GstBuffer * buffer, gboolean fast, H263ParseState * state); From a4b4eeb86cf237345c9aeedf652605925c985410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 4 Mar 2011 09:25:49 +0000 Subject: [PATCH 17/20] fieldanalysis: add backup files for compiling without orc --- gst/fieldanalysis/gstfieldanalysisorc-dist.c | 1056 ++++++++++++++++++ gst/fieldanalysis/gstfieldanalysisorc-dist.h | 72 ++ 2 files changed, 1128 insertions(+) create mode 100644 gst/fieldanalysis/gstfieldanalysisorc-dist.c create mode 100644 gst/fieldanalysis/gstfieldanalysisorc-dist.h diff --git a/gst/fieldanalysis/gstfieldanalysisorc-dist.c b/gst/fieldanalysis/gstfieldanalysisorc-dist.c new file mode 100644 index 0000000000..969916376e --- /dev/null +++ b/gst/fieldanalysis/gstfieldanalysisorc-dist.c @@ -0,0 +1,1056 @@ + +/* autogenerated from gstfieldanalysisorc.orc */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifndef DISABLE_ORC +#include +#endif +#include + +#ifndef _ORC_INTEGER_TYPEDEFS_ +#define _ORC_INTEGER_TYPEDEFS_ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +typedef int8_t orc_int8; +typedef int16_t orc_int16; +typedef int32_t orc_int32; +typedef int64_t orc_int64; +typedef uint8_t orc_uint8; +typedef uint16_t orc_uint16; +typedef uint32_t orc_uint32; +typedef uint64_t orc_uint64; +#define ORC_UINT64_C(x) UINT64_C(x) +#elif defined(_MSC_VER) +typedef signed __int8 orc_int8; +typedef signed __int16 orc_int16; +typedef signed __int32 orc_int32; +typedef signed __int64 orc_int64; +typedef unsigned __int8 orc_uint8; +typedef unsigned __int16 orc_uint16; +typedef unsigned __int32 orc_uint32; +typedef unsigned __int64 orc_uint64; +#define ORC_UINT64_C(x) (x##Ui64) +#else +#include +typedef signed char orc_int8; +typedef short orc_int16; +typedef int orc_int32; +typedef unsigned char orc_uint8; +typedef unsigned short orc_uint16; +typedef unsigned int orc_uint32; +#if INT_MAX == LONG_MAX +typedef long long orc_int64; +typedef unsigned long long orc_uint64; +#define ORC_UINT64_C(x) (x##ULL) +#else +typedef long orc_int64; +typedef unsigned long orc_uint64; +#define ORC_UINT64_C(x) (x##UL) +#endif +#endif +typedef union +{ + orc_int16 i; + orc_int8 x2[2]; +} orc_union16; +typedef union +{ + orc_int32 i; + float f; + orc_int16 x2[2]; + orc_int8 x4[4]; +} orc_union32; +typedef union +{ + orc_int64 i; + double f; + orc_int32 x2[2]; + float x2f[2]; + orc_int16 x4[4]; +} orc_union64; +#endif + +void orc_same_parity_sad_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n); +void orc_same_parity_ssd_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n); +void orc_same_parity_3_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, const orc_uint8 * s6, int p2, int n); +void orc_opposite_parity_5_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, int p2, int n); + +void gst_fieldanalysis_orc_init (void); + + +/* begin Orc C target preamble */ +#define ORC_CLAMP(x,a,b) ((x)<(a) ? (a) : ((x)>(b) ? (b) : (x))) +#define ORC_ABS(a) ((a)<0 ? -(a) : (a)) +#define ORC_MIN(a,b) ((a)<(b) ? (a) : (b)) +#define ORC_MAX(a,b) ((a)>(b) ? (a) : (b)) +#define ORC_SB_MAX 127 +#define ORC_SB_MIN (-1-ORC_SB_MAX) +#define ORC_UB_MAX 255 +#define ORC_UB_MIN 0 +#define ORC_SW_MAX 32767 +#define ORC_SW_MIN (-1-ORC_SW_MAX) +#define ORC_UW_MAX 65535 +#define ORC_UW_MIN 0 +#define ORC_SL_MAX 2147483647 +#define ORC_SL_MIN (-1-ORC_SL_MAX) +#define ORC_UL_MAX 4294967295U +#define ORC_UL_MIN 0 +#define ORC_CLAMP_SB(x) ORC_CLAMP(x,ORC_SB_MIN,ORC_SB_MAX) +#define ORC_CLAMP_UB(x) ORC_CLAMP(x,ORC_UB_MIN,ORC_UB_MAX) +#define ORC_CLAMP_SW(x) ORC_CLAMP(x,ORC_SW_MIN,ORC_SW_MAX) +#define ORC_CLAMP_UW(x) ORC_CLAMP(x,ORC_UW_MIN,ORC_UW_MAX) +#define ORC_CLAMP_SL(x) ORC_CLAMP(x,ORC_SL_MIN,ORC_SL_MAX) +#define ORC_CLAMP_UL(x) ORC_CLAMP(x,ORC_UL_MIN,ORC_UL_MAX) +#define ORC_SWAP_W(x) ((((x)&0xff)<<8) | (((x)&0xff00)>>8)) +#define ORC_SWAP_L(x) ((((x)&0xff)<<24) | (((x)&0xff00)<<8) | (((x)&0xff0000)>>8) | (((x)&0xff000000)>>24)) +#define ORC_SWAP_Q(x) ((((x)&ORC_UINT64_C(0xff))<<56) | (((x)&ORC_UINT64_C(0xff00))<<40) | (((x)&ORC_UINT64_C(0xff0000))<<24) | (((x)&ORC_UINT64_C(0xff000000))<<8) | (((x)&ORC_UINT64_C(0xff00000000))>>8) | (((x)&ORC_UINT64_C(0xff0000000000))>>24) | (((x)&ORC_UINT64_C(0xff000000000000))>>40) | (((x)&ORC_UINT64_C(0xff00000000000000))>>56)) +#define ORC_PTR_OFFSET(ptr,offset) ((void *)(((unsigned char *)(ptr)) + (offset))) +#define ORC_DENORMAL(x) ((x) & ((((x)&0x7f800000) == 0) ? 0xff800000 : 0xffffffff)) +#define ORC_ISNAN(x) ((((x)&0x7f800000) == 0x7f800000) && (((x)&0x007fffff) != 0)) +#define ORC_DENORMAL_DOUBLE(x) ((x) & ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == 0) ? ORC_UINT64_C(0xfff0000000000000) : ORC_UINT64_C(0xffffffffffffffff))) +#define ORC_ISNAN_DOUBLE(x) ((((x)&ORC_UINT64_C(0x7ff0000000000000)) == ORC_UINT64_C(0x7ff0000000000000)) && (((x)&ORC_UINT64_C(0x000fffffffffffff)) != 0)) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#define ORC_RESTRICT restrict +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define ORC_RESTRICT __restrict__ +#else +#define ORC_RESTRICT +#endif +/* end Orc C target preamble */ + + + +/* orc_same_parity_sad_planar_yuv */ +#ifdef DISABLE_ORC +void +orc_same_parity_sad_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n) +{ + int i; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + orc_union32 var12 = { 0 }; + orc_int8 var36; + orc_int8 var37; + orc_union32 var38; + orc_union16 var39; + orc_union16 var40; + orc_union16 var41; + orc_union16 var42; + orc_union32 var43; + orc_union32 var44; + orc_union32 var45; + + ptr4 = (orc_int8 *) s1; + ptr5 = (orc_int8 *) s2; + + /* 7: loadpl */ + var38.i = p2; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var36 = ptr4[i]; + /* 1: convubw */ + var39.i = (orc_uint8) var36; + /* 2: loadb */ + var37 = ptr5[i]; + /* 3: convubw */ + var40.i = (orc_uint8) var37; + /* 4: subw */ + var41.i = var39.i - var40.i; + /* 5: absw */ + var42.i = ORC_ABS (var41.i); + /* 6: convuwl */ + var43.i = (orc_uint16) var42.i; + /* 8: cmpgtsl */ + var44.i = (var43.i > var38.i) ? (~0) : 0; + /* 9: andl */ + var45.i = var43.i & var44.i; + /* 10: accl */ + var12.i = var12.i + var45.i; + } + *a1 = var12.i; + +} + +#else +static void +_backup_orc_same_parity_sad_planar_yuv (OrcExecutor * ex) +{ + int i; + int n = ex->n; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + orc_union32 var12 = { 0 }; + orc_int8 var36; + orc_int8 var37; + orc_union32 var38; + orc_union16 var39; + orc_union16 var40; + orc_union16 var41; + orc_union16 var42; + orc_union32 var43; + orc_union32 var44; + orc_union32 var45; + + ptr4 = (orc_int8 *) ex->arrays[4]; + ptr5 = (orc_int8 *) ex->arrays[5]; + + /* 7: loadpl */ + var38.i = ex->params[25]; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var36 = ptr4[i]; + /* 1: convubw */ + var39.i = (orc_uint8) var36; + /* 2: loadb */ + var37 = ptr5[i]; + /* 3: convubw */ + var40.i = (orc_uint8) var37; + /* 4: subw */ + var41.i = var39.i - var40.i; + /* 5: absw */ + var42.i = ORC_ABS (var41.i); + /* 6: convuwl */ + var43.i = (orc_uint16) var42.i; + /* 8: cmpgtsl */ + var44.i = (var43.i > var38.i) ? (~0) : 0; + /* 9: andl */ + var45.i = var43.i & var44.i; + /* 10: accl */ + var12.i = var12.i + var45.i; + } + ex->accumulators[0] = var12.i; + +} + +static OrcProgram *_orc_program_orc_same_parity_sad_planar_yuv; +void +orc_same_parity_sad_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n) +{ + OrcExecutor _ex, *ex = &_ex; + OrcProgram *p = _orc_program_orc_same_parity_sad_planar_yuv; + void (*func) (OrcExecutor *); + + ex->program = p; + + ex->n = n; + ex->arrays[ORC_VAR_S1] = (void *) s1; + ex->arrays[ORC_VAR_S2] = (void *) s2; + ex->params[ORC_VAR_P2] = p2; + + func = p->code_exec; + func (ex); + *a1 = orc_executor_get_accumulator (ex, ORC_VAR_A1); +} +#endif + + +/* orc_same_parity_ssd_planar_yuv */ +#ifdef DISABLE_ORC +void +orc_same_parity_ssd_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n) +{ + int i; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + orc_union32 var12 = { 0 }; + orc_int8 var36; + orc_int8 var37; + orc_union32 var38; + orc_union16 var39; + orc_union16 var40; + orc_union16 var41; + orc_union32 var42; + orc_union32 var43; + orc_union32 var44; + + ptr4 = (orc_int8 *) s1; + ptr5 = (orc_int8 *) s2; + + /* 6: loadpl */ + var38.i = p2; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var36 = ptr4[i]; + /* 1: convubw */ + var39.i = (orc_uint8) var36; + /* 2: loadb */ + var37 = ptr5[i]; + /* 3: convubw */ + var40.i = (orc_uint8) var37; + /* 4: subw */ + var41.i = var39.i - var40.i; + /* 5: mulswl */ + var42.i = var41.i * var41.i; + /* 7: cmpgtsl */ + var43.i = (var42.i > var38.i) ? (~0) : 0; + /* 8: andl */ + var44.i = var42.i & var43.i; + /* 9: accl */ + var12.i = var12.i + var44.i; + } + *a1 = var12.i; + +} + +#else +static void +_backup_orc_same_parity_ssd_planar_yuv (OrcExecutor * ex) +{ + int i; + int n = ex->n; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + orc_union32 var12 = { 0 }; + orc_int8 var36; + orc_int8 var37; + orc_union32 var38; + orc_union16 var39; + orc_union16 var40; + orc_union16 var41; + orc_union32 var42; + orc_union32 var43; + orc_union32 var44; + + ptr4 = (orc_int8 *) ex->arrays[4]; + ptr5 = (orc_int8 *) ex->arrays[5]; + + /* 6: loadpl */ + var38.i = ex->params[25]; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var36 = ptr4[i]; + /* 1: convubw */ + var39.i = (orc_uint8) var36; + /* 2: loadb */ + var37 = ptr5[i]; + /* 3: convubw */ + var40.i = (orc_uint8) var37; + /* 4: subw */ + var41.i = var39.i - var40.i; + /* 5: mulswl */ + var42.i = var41.i * var41.i; + /* 7: cmpgtsl */ + var43.i = (var42.i > var38.i) ? (~0) : 0; + /* 8: andl */ + var44.i = var42.i & var43.i; + /* 9: accl */ + var12.i = var12.i + var44.i; + } + ex->accumulators[0] = var12.i; + +} + +static OrcProgram *_orc_program_orc_same_parity_ssd_planar_yuv; +void +orc_same_parity_ssd_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, int p2, int n) +{ + OrcExecutor _ex, *ex = &_ex; + OrcProgram *p = _orc_program_orc_same_parity_ssd_planar_yuv; + void (*func) (OrcExecutor *); + + ex->program = p; + + ex->n = n; + ex->arrays[ORC_VAR_S1] = (void *) s1; + ex->arrays[ORC_VAR_S2] = (void *) s2; + ex->params[ORC_VAR_P2] = p2; + + func = p->code_exec; + func (ex); + *a1 = orc_executor_get_accumulator (ex, ORC_VAR_A1); +} +#endif + + +/* orc_same_parity_3_tap_planar_yuv */ +#ifdef DISABLE_ORC +void +orc_same_parity_3_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, const orc_uint8 * s6, int p2, int n) +{ + int i; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + const orc_int8 *ORC_RESTRICT ptr6; + const orc_int8 *ORC_RESTRICT ptr7; + const orc_int8 *ORC_RESTRICT ptr8; + const orc_int8 *ORC_RESTRICT ptr9; + orc_union32 var12 = { 0 }; + orc_int8 var40; + orc_int8 var41; + orc_int8 var42; + orc_int8 var43; + orc_int8 var44; + orc_int8 var45; + orc_union32 var46; + orc_union16 var47; + orc_union16 var48; + orc_union16 var49; + orc_union16 var50; + orc_union16 var51; + orc_union16 var52; + orc_union16 var53; + orc_union16 var54; + orc_union16 var55; + orc_union16 var56; + orc_union16 var57; + orc_union16 var58; + orc_union16 var59; + orc_union16 var60; + orc_union32 var61; + orc_union32 var62; + orc_union32 var63; + + ptr4 = (orc_int8 *) s1; + ptr5 = (orc_int8 *) s2; + ptr6 = (orc_int8 *) s3; + ptr7 = (orc_int8 *) s4; + ptr8 = (orc_int8 *) s5; + ptr9 = (orc_int8 *) s6; + + /* 21: loadpl */ + var46.i = p2; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var40 = ptr4[i]; + /* 1: convubw */ + var47.i = (orc_uint8) var40; + /* 2: loadb */ + var41 = ptr5[i]; + /* 3: convubw */ + var48.i = (orc_uint8) var41; + /* 4: loadb */ + var42 = ptr6[i]; + /* 5: convubw */ + var49.i = (orc_uint8) var42; + /* 6: loadb */ + var43 = ptr7[i]; + /* 7: convubw */ + var50.i = (orc_uint8) var43; + /* 8: loadb */ + var44 = ptr8[i]; + /* 9: convubw */ + var51.i = (orc_uint8) var44; + /* 10: loadb */ + var45 = ptr9[i]; + /* 11: convubw */ + var52.i = (orc_uint8) var45; + /* 12: shlw */ + var53.i = var48.i << 2; + /* 13: shlw */ + var54.i = var51.i << 2; + /* 14: addw */ + var55.i = var47.i + var53.i; + /* 15: addw */ + var56.i = var55.i + var49.i; + /* 16: addw */ + var57.i = var50.i + var54.i; + /* 17: addw */ + var58.i = var57.i + var52.i; + /* 18: subw */ + var59.i = var56.i - var58.i; + /* 19: absw */ + var60.i = ORC_ABS (var59.i); + /* 20: convuwl */ + var61.i = (orc_uint16) var60.i; + /* 22: cmpgtsl */ + var62.i = (var61.i > var46.i) ? (~0) : 0; + /* 23: andl */ + var63.i = var61.i & var62.i; + /* 24: accl */ + var12.i = var12.i + var63.i; + } + *a1 = var12.i; + +} + +#else +static void +_backup_orc_same_parity_3_tap_planar_yuv (OrcExecutor * ex) +{ + int i; + int n = ex->n; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + const orc_int8 *ORC_RESTRICT ptr6; + const orc_int8 *ORC_RESTRICT ptr7; + const orc_int8 *ORC_RESTRICT ptr8; + const orc_int8 *ORC_RESTRICT ptr9; + orc_union32 var12 = { 0 }; + orc_int8 var40; + orc_int8 var41; + orc_int8 var42; + orc_int8 var43; + orc_int8 var44; + orc_int8 var45; + orc_union32 var46; + orc_union16 var47; + orc_union16 var48; + orc_union16 var49; + orc_union16 var50; + orc_union16 var51; + orc_union16 var52; + orc_union16 var53; + orc_union16 var54; + orc_union16 var55; + orc_union16 var56; + orc_union16 var57; + orc_union16 var58; + orc_union16 var59; + orc_union16 var60; + orc_union32 var61; + orc_union32 var62; + orc_union32 var63; + + ptr4 = (orc_int8 *) ex->arrays[4]; + ptr5 = (orc_int8 *) ex->arrays[5]; + ptr6 = (orc_int8 *) ex->arrays[6]; + ptr7 = (orc_int8 *) ex->arrays[7]; + ptr8 = (orc_int8 *) ex->arrays[8]; + ptr9 = (orc_int8 *) ex->arrays[9]; + + /* 21: loadpl */ + var46.i = ex->params[25]; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var40 = ptr4[i]; + /* 1: convubw */ + var47.i = (orc_uint8) var40; + /* 2: loadb */ + var41 = ptr5[i]; + /* 3: convubw */ + var48.i = (orc_uint8) var41; + /* 4: loadb */ + var42 = ptr6[i]; + /* 5: convubw */ + var49.i = (orc_uint8) var42; + /* 6: loadb */ + var43 = ptr7[i]; + /* 7: convubw */ + var50.i = (orc_uint8) var43; + /* 8: loadb */ + var44 = ptr8[i]; + /* 9: convubw */ + var51.i = (orc_uint8) var44; + /* 10: loadb */ + var45 = ptr9[i]; + /* 11: convubw */ + var52.i = (orc_uint8) var45; + /* 12: shlw */ + var53.i = var48.i << 2; + /* 13: shlw */ + var54.i = var51.i << 2; + /* 14: addw */ + var55.i = var47.i + var53.i; + /* 15: addw */ + var56.i = var55.i + var49.i; + /* 16: addw */ + var57.i = var50.i + var54.i; + /* 17: addw */ + var58.i = var57.i + var52.i; + /* 18: subw */ + var59.i = var56.i - var58.i; + /* 19: absw */ + var60.i = ORC_ABS (var59.i); + /* 20: convuwl */ + var61.i = (orc_uint16) var60.i; + /* 22: cmpgtsl */ + var62.i = (var61.i > var46.i) ? (~0) : 0; + /* 23: andl */ + var63.i = var61.i & var62.i; + /* 24: accl */ + var12.i = var12.i + var63.i; + } + ex->accumulators[0] = var12.i; + +} + +static OrcProgram *_orc_program_orc_same_parity_3_tap_planar_yuv; +void +orc_same_parity_3_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, const orc_uint8 * s6, int p2, int n) +{ + OrcExecutor _ex, *ex = &_ex; + OrcProgram *p = _orc_program_orc_same_parity_3_tap_planar_yuv; + void (*func) (OrcExecutor *); + + ex->program = p; + + ex->n = n; + ex->arrays[ORC_VAR_S1] = (void *) s1; + ex->arrays[ORC_VAR_S2] = (void *) s2; + ex->arrays[ORC_VAR_S3] = (void *) s3; + ex->arrays[ORC_VAR_S4] = (void *) s4; + ex->arrays[ORC_VAR_S5] = (void *) s5; + ex->arrays[ORC_VAR_S6] = (void *) s6; + ex->params[ORC_VAR_P2] = p2; + + func = p->code_exec; + func (ex); + *a1 = orc_executor_get_accumulator (ex, ORC_VAR_A1); +} +#endif + + +/* orc_opposite_parity_5_tap_planar_yuv */ +#ifdef DISABLE_ORC +void +orc_opposite_parity_5_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, int p2, int n) +{ + int i; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + const orc_int8 *ORC_RESTRICT ptr6; + const orc_int8 *ORC_RESTRICT ptr7; + const orc_int8 *ORC_RESTRICT ptr8; + orc_union32 var12 = { 0 }; + orc_int8 var39; + orc_int8 var40; + orc_int8 var41; + orc_int8 var42; + orc_int8 var43; + orc_union16 var44; + orc_union16 var45; + orc_union32 var46; + orc_union16 var47; + orc_union16 var48; + orc_union16 var49; + orc_union16 var50; + orc_union16 var51; + orc_union16 var52; + orc_union16 var53; + orc_union16 var54; + orc_union16 var55; + orc_union16 var56; + orc_union16 var57; + orc_union16 var58; + orc_union16 var59; + orc_union32 var60; + orc_union32 var61; + orc_union32 var62; + + ptr4 = (orc_int8 *) s1; + ptr5 = (orc_int8 *) s2; + ptr6 = (orc_int8 *) s3; + ptr7 = (orc_int8 *) s4; + ptr8 = (orc_int8 *) s5; + + /* 11: loadpw */ + var44.i = 0x00000003; /* 3 or 1.4822e-323f */ + /* 13: loadpw */ + var45.i = 0x00000003; /* 3 or 1.4822e-323f */ + /* 21: loadpl */ + var46.i = p2; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var39 = ptr4[i]; + /* 1: convubw */ + var47.i = (orc_uint8) var39; + /* 2: loadb */ + var40 = ptr5[i]; + /* 3: convubw */ + var48.i = (orc_uint8) var40; + /* 4: loadb */ + var41 = ptr6[i]; + /* 5: convubw */ + var49.i = (orc_uint8) var41; + /* 6: loadb */ + var42 = ptr7[i]; + /* 7: convubw */ + var50.i = (orc_uint8) var42; + /* 8: loadb */ + var43 = ptr8[i]; + /* 9: convubw */ + var51.i = (orc_uint8) var43; + /* 10: shlw */ + var52.i = var49.i << 2; + /* 12: mullw */ + var53.i = (var48.i * var44.i) & 0xffff; + /* 14: mullw */ + var54.i = (var50.i * var45.i) & 0xffff; + /* 15: subw */ + var55.i = var47.i - var53.i; + /* 16: addw */ + var56.i = var55.i + var52.i; + /* 17: subw */ + var57.i = var56.i - var54.i; + /* 18: addw */ + var58.i = var57.i + var51.i; + /* 19: absw */ + var59.i = ORC_ABS (var58.i); + /* 20: convuwl */ + var60.i = (orc_uint16) var59.i; + /* 22: cmpgtsl */ + var61.i = (var60.i > var46.i) ? (~0) : 0; + /* 23: andl */ + var62.i = var60.i & var61.i; + /* 24: accl */ + var12.i = var12.i + var62.i; + } + *a1 = var12.i; + +} + +#else +static void +_backup_orc_opposite_parity_5_tap_planar_yuv (OrcExecutor * ex) +{ + int i; + int n = ex->n; + const orc_int8 *ORC_RESTRICT ptr4; + const orc_int8 *ORC_RESTRICT ptr5; + const orc_int8 *ORC_RESTRICT ptr6; + const orc_int8 *ORC_RESTRICT ptr7; + const orc_int8 *ORC_RESTRICT ptr8; + orc_union32 var12 = { 0 }; + orc_int8 var39; + orc_int8 var40; + orc_int8 var41; + orc_int8 var42; + orc_int8 var43; + orc_union16 var44; + orc_union16 var45; + orc_union32 var46; + orc_union16 var47; + orc_union16 var48; + orc_union16 var49; + orc_union16 var50; + orc_union16 var51; + orc_union16 var52; + orc_union16 var53; + orc_union16 var54; + orc_union16 var55; + orc_union16 var56; + orc_union16 var57; + orc_union16 var58; + orc_union16 var59; + orc_union32 var60; + orc_union32 var61; + orc_union32 var62; + + ptr4 = (orc_int8 *) ex->arrays[4]; + ptr5 = (orc_int8 *) ex->arrays[5]; + ptr6 = (orc_int8 *) ex->arrays[6]; + ptr7 = (orc_int8 *) ex->arrays[7]; + ptr8 = (orc_int8 *) ex->arrays[8]; + + /* 11: loadpw */ + var44.i = 0x00000003; /* 3 or 1.4822e-323f */ + /* 13: loadpw */ + var45.i = 0x00000003; /* 3 or 1.4822e-323f */ + /* 21: loadpl */ + var46.i = ex->params[25]; + + for (i = 0; i < n; i++) { + /* 0: loadb */ + var39 = ptr4[i]; + /* 1: convubw */ + var47.i = (orc_uint8) var39; + /* 2: loadb */ + var40 = ptr5[i]; + /* 3: convubw */ + var48.i = (orc_uint8) var40; + /* 4: loadb */ + var41 = ptr6[i]; + /* 5: convubw */ + var49.i = (orc_uint8) var41; + /* 6: loadb */ + var42 = ptr7[i]; + /* 7: convubw */ + var50.i = (orc_uint8) var42; + /* 8: loadb */ + var43 = ptr8[i]; + /* 9: convubw */ + var51.i = (orc_uint8) var43; + /* 10: shlw */ + var52.i = var49.i << 2; + /* 12: mullw */ + var53.i = (var48.i * var44.i) & 0xffff; + /* 14: mullw */ + var54.i = (var50.i * var45.i) & 0xffff; + /* 15: subw */ + var55.i = var47.i - var53.i; + /* 16: addw */ + var56.i = var55.i + var52.i; + /* 17: subw */ + var57.i = var56.i - var54.i; + /* 18: addw */ + var58.i = var57.i + var51.i; + /* 19: absw */ + var59.i = ORC_ABS (var58.i); + /* 20: convuwl */ + var60.i = (orc_uint16) var59.i; + /* 22: cmpgtsl */ + var61.i = (var60.i > var46.i) ? (~0) : 0; + /* 23: andl */ + var62.i = var60.i & var61.i; + /* 24: accl */ + var12.i = var12.i + var62.i; + } + ex->accumulators[0] = var12.i; + +} + +static OrcProgram *_orc_program_orc_opposite_parity_5_tap_planar_yuv; +void +orc_opposite_parity_5_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, + const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, + const orc_uint8 * s5, int p2, int n) +{ + OrcExecutor _ex, *ex = &_ex; + OrcProgram *p = _orc_program_orc_opposite_parity_5_tap_planar_yuv; + void (*func) (OrcExecutor *); + + ex->program = p; + + ex->n = n; + ex->arrays[ORC_VAR_S1] = (void *) s1; + ex->arrays[ORC_VAR_S2] = (void *) s2; + ex->arrays[ORC_VAR_S3] = (void *) s3; + ex->arrays[ORC_VAR_S4] = (void *) s4; + ex->arrays[ORC_VAR_S5] = (void *) s5; + ex->params[ORC_VAR_P2] = p2; + + func = p->code_exec; + func (ex); + *a1 = orc_executor_get_accumulator (ex, ORC_VAR_A1); +} +#endif + + +void +gst_fieldanalysis_orc_init (void) +{ +#ifndef DISABLE_ORC + { + /* orc_same_parity_sad_planar_yuv */ + OrcProgram *p; + OrcCompileResult result; + + p = orc_program_new (); + orc_program_set_name (p, "orc_same_parity_sad_planar_yuv"); + orc_program_set_backup_function (p, _backup_orc_same_parity_sad_planar_yuv); + orc_program_add_source (p, 1, "s1"); + orc_program_add_source (p, 1, "s2"); + orc_program_add_accumulator (p, 4, "a1"); + orc_program_add_parameter (p, 4, "p2"); + orc_program_add_temporary (p, 2, "t1"); + orc_program_add_temporary (p, 2, "t2"); + orc_program_add_temporary (p, 4, "t3"); + orc_program_add_temporary (p, 4, "t4"); + + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "subw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2, + ORC_VAR_D1); + orc_program_append_2 (p, "absw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convuwl", 0, ORC_VAR_T3, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "cmpgtsl", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_P2, + ORC_VAR_D1); + orc_program_append_2 (p, "andl", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_T4, + ORC_VAR_D1); + orc_program_append_2 (p, "accl", 0, ORC_VAR_A1, ORC_VAR_T3, ORC_VAR_D1, + ORC_VAR_D1); + + result = orc_program_compile (p); + + _orc_program_orc_same_parity_sad_planar_yuv = p; + } + { + /* orc_same_parity_ssd_planar_yuv */ + OrcProgram *p; + OrcCompileResult result; + + p = orc_program_new (); + orc_program_set_name (p, "orc_same_parity_ssd_planar_yuv"); + orc_program_set_backup_function (p, _backup_orc_same_parity_ssd_planar_yuv); + orc_program_add_source (p, 1, "s1"); + orc_program_add_source (p, 1, "s2"); + orc_program_add_accumulator (p, 4, "a1"); + orc_program_add_parameter (p, 4, "p2"); + orc_program_add_temporary (p, 2, "t1"); + orc_program_add_temporary (p, 2, "t2"); + orc_program_add_temporary (p, 4, "t3"); + orc_program_add_temporary (p, 4, "t4"); + + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "subw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2, + ORC_VAR_D1); + orc_program_append_2 (p, "mulswl", 0, ORC_VAR_T3, ORC_VAR_T1, ORC_VAR_T1, + ORC_VAR_D1); + orc_program_append_2 (p, "cmpgtsl", 0, ORC_VAR_T4, ORC_VAR_T3, ORC_VAR_P2, + ORC_VAR_D1); + orc_program_append_2 (p, "andl", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_T4, + ORC_VAR_D1); + orc_program_append_2 (p, "accl", 0, ORC_VAR_A1, ORC_VAR_T3, ORC_VAR_D1, + ORC_VAR_D1); + + result = orc_program_compile (p); + + _orc_program_orc_same_parity_ssd_planar_yuv = p; + } + { + /* orc_same_parity_3_tap_planar_yuv */ + OrcProgram *p; + OrcCompileResult result; + + p = orc_program_new (); + orc_program_set_name (p, "orc_same_parity_3_tap_planar_yuv"); + orc_program_set_backup_function (p, + _backup_orc_same_parity_3_tap_planar_yuv); + orc_program_add_source (p, 1, "s1"); + orc_program_add_source (p, 1, "s2"); + orc_program_add_source (p, 1, "s3"); + orc_program_add_source (p, 1, "s4"); + orc_program_add_source (p, 1, "s5"); + orc_program_add_source (p, 1, "s6"); + orc_program_add_accumulator (p, 4, "a1"); + orc_program_add_constant (p, 4, 0x00000002, "c1"); + orc_program_add_parameter (p, 4, "p2"); + orc_program_add_temporary (p, 2, "t1"); + orc_program_add_temporary (p, 2, "t2"); + orc_program_add_temporary (p, 2, "t3"); + orc_program_add_temporary (p, 2, "t4"); + orc_program_add_temporary (p, 2, "t5"); + orc_program_add_temporary (p, 2, "t6"); + orc_program_add_temporary (p, 4, "t7"); + orc_program_add_temporary (p, 4, "t8"); + + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T3, ORC_VAR_S3, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T4, ORC_VAR_S4, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T5, ORC_VAR_S5, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T6, ORC_VAR_S6, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "shlw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C1, + ORC_VAR_D1); + orc_program_append_2 (p, "shlw", 0, ORC_VAR_T5, ORC_VAR_T5, ORC_VAR_C1, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T3, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_T5, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_T6, + ORC_VAR_D1); + orc_program_append_2 (p, "subw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T4, + ORC_VAR_D1); + orc_program_append_2 (p, "absw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convuwl", 0, ORC_VAR_T7, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "cmpgtsl", 0, ORC_VAR_T8, ORC_VAR_T7, ORC_VAR_P2, + ORC_VAR_D1); + orc_program_append_2 (p, "andl", 0, ORC_VAR_T7, ORC_VAR_T7, ORC_VAR_T8, + ORC_VAR_D1); + orc_program_append_2 (p, "accl", 0, ORC_VAR_A1, ORC_VAR_T7, ORC_VAR_D1, + ORC_VAR_D1); + + result = orc_program_compile (p); + + _orc_program_orc_same_parity_3_tap_planar_yuv = p; + } + { + /* orc_opposite_parity_5_tap_planar_yuv */ + OrcProgram *p; + OrcCompileResult result; + + p = orc_program_new (); + orc_program_set_name (p, "orc_opposite_parity_5_tap_planar_yuv"); + orc_program_set_backup_function (p, + _backup_orc_opposite_parity_5_tap_planar_yuv); + orc_program_add_source (p, 1, "s1"); + orc_program_add_source (p, 1, "s2"); + orc_program_add_source (p, 1, "s3"); + orc_program_add_source (p, 1, "s4"); + orc_program_add_source (p, 1, "s5"); + orc_program_add_accumulator (p, 4, "a1"); + orc_program_add_constant (p, 4, 0x00000002, "c1"); + orc_program_add_constant (p, 4, 0x00000003, "c2"); + orc_program_add_parameter (p, 4, "p2"); + orc_program_add_temporary (p, 2, "t1"); + orc_program_add_temporary (p, 2, "t2"); + orc_program_add_temporary (p, 2, "t3"); + orc_program_add_temporary (p, 2, "t4"); + orc_program_add_temporary (p, 2, "t5"); + orc_program_add_temporary (p, 4, "t6"); + orc_program_add_temporary (p, 4, "t7"); + + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T1, ORC_VAR_S1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T2, ORC_VAR_S2, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T3, ORC_VAR_S3, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T4, ORC_VAR_S4, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convubw", 0, ORC_VAR_T5, ORC_VAR_S5, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "shlw", 0, ORC_VAR_T3, ORC_VAR_T3, ORC_VAR_C1, + ORC_VAR_D1); + orc_program_append_2 (p, "mullw", 0, ORC_VAR_T2, ORC_VAR_T2, ORC_VAR_C2, + ORC_VAR_D1); + orc_program_append_2 (p, "mullw", 0, ORC_VAR_T4, ORC_VAR_T4, ORC_VAR_C2, + ORC_VAR_D1); + orc_program_append_2 (p, "subw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T2, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T3, + ORC_VAR_D1); + orc_program_append_2 (p, "subw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T4, + ORC_VAR_D1); + orc_program_append_2 (p, "addw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_T5, + ORC_VAR_D1); + orc_program_append_2 (p, "absw", 0, ORC_VAR_T1, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "convuwl", 0, ORC_VAR_T6, ORC_VAR_T1, ORC_VAR_D1, + ORC_VAR_D1); + orc_program_append_2 (p, "cmpgtsl", 0, ORC_VAR_T7, ORC_VAR_T6, ORC_VAR_P2, + ORC_VAR_D1); + orc_program_append_2 (p, "andl", 0, ORC_VAR_T6, ORC_VAR_T6, ORC_VAR_T7, + ORC_VAR_D1); + orc_program_append_2 (p, "accl", 0, ORC_VAR_A1, ORC_VAR_T6, ORC_VAR_D1, + ORC_VAR_D1); + + result = orc_program_compile (p); + + _orc_program_orc_opposite_parity_5_tap_planar_yuv = p; + } +#endif +} diff --git a/gst/fieldanalysis/gstfieldanalysisorc-dist.h b/gst/fieldanalysis/gstfieldanalysisorc-dist.h new file mode 100644 index 0000000000..b46b6fa60a --- /dev/null +++ b/gst/fieldanalysis/gstfieldanalysisorc-dist.h @@ -0,0 +1,72 @@ + +/* autogenerated from gstfieldanalysisorc.orc */ + +#ifndef _GSTFIELDANALYSISORC_H_ +#define _GSTFIELDANALYSISORC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void gst_fieldanalysis_orc_init (void); + + + +#ifndef _ORC_INTEGER_TYPEDEFS_ +#define _ORC_INTEGER_TYPEDEFS_ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +typedef int8_t orc_int8; +typedef int16_t orc_int16; +typedef int32_t orc_int32; +typedef int64_t orc_int64; +typedef uint8_t orc_uint8; +typedef uint16_t orc_uint16; +typedef uint32_t orc_uint32; +typedef uint64_t orc_uint64; +#define ORC_UINT64_C(x) UINT64_C(x) +#elif defined(_MSC_VER) +typedef signed __int8 orc_int8; +typedef signed __int16 orc_int16; +typedef signed __int32 orc_int32; +typedef signed __int64 orc_int64; +typedef unsigned __int8 orc_uint8; +typedef unsigned __int16 orc_uint16; +typedef unsigned __int32 orc_uint32; +typedef unsigned __int64 orc_uint64; +#define ORC_UINT64_C(x) (x##Ui64) +#else +#include +typedef signed char orc_int8; +typedef short orc_int16; +typedef int orc_int32; +typedef unsigned char orc_uint8; +typedef unsigned short orc_uint16; +typedef unsigned int orc_uint32; +#if INT_MAX == LONG_MAX +typedef long long orc_int64; +typedef unsigned long long orc_uint64; +#define ORC_UINT64_C(x) (x##ULL) +#else +typedef long orc_int64; +typedef unsigned long orc_uint64; +#define ORC_UINT64_C(x) (x##UL) +#endif +#endif +typedef union { orc_int16 i; orc_int8 x2[2]; } orc_union16; +typedef union { orc_int32 i; float f; orc_int16 x2[2]; orc_int8 x4[4]; } orc_union32; +typedef union { orc_int64 i; double f; orc_int32 x2[2]; float x2f[2]; orc_int16 x4[4]; } orc_union64; +#endif +void orc_same_parity_sad_planar_yuv (guint32 * a1, const orc_uint8 * s1, const orc_uint8 * s2, int p2, int n); +void orc_same_parity_ssd_planar_yuv (guint32 * a1, const orc_uint8 * s1, const orc_uint8 * s2, int p2, int n); +void orc_same_parity_3_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, const orc_uint8 * s5, const orc_uint8 * s6, int p2, int n); +void orc_opposite_parity_5_tap_planar_yuv (guint32 * a1, const orc_uint8 * s1, const orc_uint8 * s2, const orc_uint8 * s3, const orc_uint8 * s4, const orc_uint8 * s5, int p2, int n); + +#ifdef __cplusplus +} +#endif + +#endif + From 605352f1185b08a7bdf16939fe33c3d29435e50c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 4 Mar 2011 11:59:44 +0100 Subject: [PATCH 18/20] rtpvp8: Fix unitialized variable Makes macosx compiler happy. --- gst/rtpvp8/gstrtpvp8pay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/rtpvp8/gstrtpvp8pay.c b/gst/rtpvp8/gstrtpvp8pay.c index 0ea5777134..b54ec28985 100644 --- a/gst/rtpvp8/gstrtpvp8pay.c +++ b/gst/rtpvp8/gstrtpvp8pay.c @@ -127,7 +127,7 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer) gboolean keyframe; guint32 header_size; guint8 version; - guint8 tmp8; + guint8 tmp8 = 0; guint8 *data; guint8 partitions; From d9a930aa250d5525978ef97108da627bc18f9b24 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 4 Mar 2011 12:10:25 +0100 Subject: [PATCH 19/20] curlsink: Fix print-related issues --- ext/curl/gstcurlsink.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ext/curl/gstcurlsink.c b/ext/curl/gstcurlsink.c index f234e37777..2a448f436c 100644 --- a/ext/curl/gstcurlsink.c +++ b/ext/curl/gstcurlsink.c @@ -753,7 +753,8 @@ gst_curl_sink_transfer_read_cb (void *curl_ptr, size_t size, size_t nmemb, buffer = sink->transfer_buf; buf_len = buffer->len; - GST_LOG ("write buf len=%d, offset=%d", buffer->len, buffer->offset); + GST_LOG ("write buf len=%" G_GSIZE_FORMAT ", offset=%" G_GSIZE_FORMAT, + buffer->len, buffer->offset); /* more data in buffer */ if (buffer->len > 0) { @@ -774,7 +775,7 @@ gst_curl_sink_transfer_read_cb (void *curl_ptr, size_t size, size_t nmemb, GST_OBJECT_UNLOCK (sink); } - GST_LOG ("sent : %d (%x)", bytes_to_send, bytes_to_send); + GST_LOG ("sent : %" G_GSIZE_FORMAT, bytes_to_send); return bytes_to_send; } else { @@ -904,7 +905,7 @@ gst_curl_sink_handle_transfer (GstCurlSink * sink) /* check response code */ curl_easy_getinfo (sink->curl, CURLINFO_RESPONSE_CODE, &resp); - GST_DEBUG_OBJECT (sink, "response code: %d", resp); + GST_DEBUG_OBJECT (sink, "response code: %ld", resp); if (resp < 200 || resp >= 300) { goto response_error; } @@ -935,16 +936,16 @@ poll_timeout: curl_multi_error: { GST_DEBUG_OBJECT (sink, "curl multi error"); - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (curl_multi_strerror (m_code)), - (NULL)); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s", + curl_multi_strerror (m_code)), (NULL)); return GST_FLOW_ERROR; } curl_easy_error: { GST_DEBUG_OBJECT (sink, "curl easy error"); - GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (curl_easy_strerror (e_code)), - (NULL)); + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s", + curl_easy_strerror (e_code)), (NULL)); return GST_FLOW_ERROR; } From 8d050d21165cf29e89846c8009f69c55d8d13ac5 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 4 Mar 2011 12:11:12 +0100 Subject: [PATCH 20/20] videoparsers: Fix unitialized variables Makes macosx compiler happy --- gst/videoparsers/gstdiracparse.c | 2 +- gst/videoparsers/h263parse.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gst/videoparsers/gstdiracparse.c b/gst/videoparsers/gstdiracparse.c index 4ddcd3a5ae..00130f8fef 100644 --- a/gst/videoparsers/gstdiracparse.c +++ b/gst/videoparsers/gstdiracparse.c @@ -272,7 +272,7 @@ gst_dirac_parse_check_valid_frame (GstBaseParse * parse, drain = GST_BASE_PARSE_FRAME_DRAIN (frame); if (!sync && !drain) { - guint32 next_sync_word; + guint32 next_sync_word = 0; next_header = GST_READ_UINT32_BE (GST_BUFFER_DATA (frame->buffer) + 5); GST_LOG ("next header %d", next_header); diff --git a/gst/videoparsers/h263parse.c b/gst/videoparsers/h263parse.c index b22c4de194..1fdf22316b 100644 --- a/gst/videoparsers/h263parse.c +++ b/gst/videoparsers/h263parse.c @@ -74,7 +74,7 @@ gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, GstBitReader br; guint8 tr; - guint32 psc, temp32; + guint32 psc = 0, temp32; guint8 temp8, pquant; gboolean hasplusptype; @@ -181,7 +181,7 @@ gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, if (hasplusptype) { guint8 ufep; guint8 cpm; - guint32 opptype, mpptype; + guint32 opptype = 0, mpptype = 0; /* 5.1.4 PLUSPTYPE */ @@ -264,7 +264,7 @@ gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, } if (ufep == 1) { - guint32 cpfmt; + guint32 cpfmt = 0; /* 5.1.5 CPFMT : Custom Picture Format (23 bits) */ if (!gst_bit_reader_get_bits_uint32 (&br, &cpfmt, 23)) @@ -278,7 +278,7 @@ gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, params->height = (cpfmt & 0x1f) * 4; if (temp8 == 0xf) { - guint32 epar; + guint32 epar = 0; /* 5.1.6 EPAR : Extended Pixel Aspect Ratio (16bits) */ if (!gst_bit_reader_get_bits_uint32 (&br, &epar, 16)) goto more;