diff --git a/common b/common
index 1de7f6ab2d..6aec6b9716 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 1de7f6ab2d4bc1af69f06079cf0f4e2cbbfdc178
+Subproject commit 6aec6b9716c184c60c4bc6a5916a2471cfa8c8cd
diff --git a/configure.ac b/configure.ac
index d1bd4a9282..fd1d11a67c 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.11
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
@@ -304,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)
@@ -636,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)
])
@@ -651,6 +661,23 @@ 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"
+ 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)
+ ])
+ 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, [
@@ -1590,6 +1617,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)
@@ -1701,7 +1729,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 ***
@@ -1733,6 +1761,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
@@ -1826,6 +1855,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/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/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-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
+
+ 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/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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
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) \
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;
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..2a448f436c
--- /dev/null
+++ b/ext/curl/gstcurlsink.c
@@ -0,0 +1,1268 @@
+/* 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.
+ */
+
+/**
+ * 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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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",
+ "Upload data over the network to a server using libcurl",
+ "Patricia Muscalu ");
+}
+
+static void
+gst_curl_sink_class_init (GstCurlSinkClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
+
+ 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_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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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));
+}
+
+static void
+gst_curl_sink_init (GstCurlSink * sink, GstCurlSinkClass * klass)
+{
+ 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
+gst_curl_sink_finalize (GObject * gobject)
+{
+ GstCurlSink *this = GST_CURL_SINK (gobject);
+
+ GST_DEBUG ("finalizing curlsink");
+ if (this->transfer_thread != NULL) {
+ g_thread_join (this->transfer_thread);
+ }
+
+ gst_curl_sink_transfer_cleanup (this);
+ g_cond_free (this->transfer_cond->cond);
+ g_free (this->transfer_cond);
+
+ g_free (this->transfer_buf);
+
+ 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->header_list) {
+ curl_slist_free_all (this->header_list);
+ this->header_list = NULL;
+ }
+
+ if (this->fdset != NULL) {
+ gst_poll_free (this->fdset);
+ this->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->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->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->flow_ret != GST_FLOW_OK) {
+ goto done;
+ }
+
+ g_assert (sink->transfer_cond->data_available == FALSE);
+
+ /* if there is no transfer thread created, lets create one */
+ if (sink->transfer_thread == NULL) {
+ if (!gst_curl_sink_transfer_start_unlocked (sink)) {
+ sink->flow_ret = GST_FLOW_ERROR;
+ goto done;
+ }
+ }
+
+ /* make data available for the transfer thread and notify */
+ 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
+ * 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->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->transfer_thread != NULL) {
+ g_thread_join (sink->transfer_thread);
+ sink->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->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->fdset != NULL) {
+ gst_poll_free (sink->fdset);
+ sink->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->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->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->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->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->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->proxy);
+ sink->proxy = g_value_dup_string (value);
+ GST_DEBUG_OBJECT (sink, "proxy set to %s", sink->proxy);
+ break;
+ case PROP_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->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->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->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->timeout = g_value_get_int (value);
+ GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout);
+ break;
+ case PROP_QOS_DSCP:
+ sink->qos_dscp = g_value_get_int (value);
+ gst_curl_sink_setup_dscp_unlocked (sink);
+ GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp);
+ break;
+ case PROP_ACCEPT_SELF_SIGNED:
+ sink->accept_self_signed = g_value_get_boolean (value);
+ GST_DEBUG_OBJECT (sink, "accept_self_signed set to %d",
+ sink->accept_self_signed);
+ break;
+ case PROP_USE_CONTENT_LENGTH:
+ sink->use_content_length = g_value_get_boolean (value);
+ GST_DEBUG_OBJECT (sink, "use_content_length set to %d",
+ sink->use_content_length);
+ break;
+ case PROP_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);
+ 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->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->timeout = g_value_get_int (value);
+ GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout);
+ break;
+ case PROP_QOS_DSCP:
+ sink->qos_dscp = g_value_get_int (value);
+ gst_curl_sink_setup_dscp_unlocked (sink);
+ GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp);
+ break;
+ case PROP_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");
+ 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->url);
+ break;
+ case PROP_USER_NAME:
+ g_value_set_string (value, sink->user);
+ break;
+ case PROP_USER_PASSWD:
+ g_value_set_string (value, sink->passwd);
+ break;
+ case PROP_PROXY:
+ g_value_set_string (value, sink->proxy);
+ break;
+ case PROP_PROXY_PORT:
+ g_value_set_int (value, sink->proxy_port);
+ break;
+ case PROP_PROXY_USER_NAME:
+ g_value_set_string (value, sink->proxy_user);
+ break;
+ case PROP_PROXY_USER_PASSWD:
+ g_value_set_string (value, sink->proxy_passwd);
+ break;
+ case PROP_FILE_NAME:
+ g_value_set_string (value, sink->file_name);
+ break;
+ case PROP_TIMEOUT:
+ g_value_set_int (value, sink->timeout);
+ break;
+ case PROP_QOS_DSCP:
+ g_value_set_int (value, sink->qos_dscp);
+ break;
+ case PROP_ACCEPT_SELF_SIGNED:
+ g_value_set_boolean (value, sink->accept_self_signed);
+ break;
+ case PROP_USE_CONTENT_LENGTH:
+ g_value_set_boolean (value, sink->use_content_length);
+ break;
+ case PROP_CONTENT_TYPE:
+ g_value_set_string (value, sink->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->header_list) {
+ curl_slist_free_all (sink->header_list);
+ sink->header_list = NULL;
+ }
+
+ 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->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->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->header_list = curl_slist_append (sink->header_list,
+ "Transfer-Encoding: chunked");
+ }
+
+ 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->file_name);
+ sink->header_list = curl_slist_append (sink->header_list, tmp);
+ g_free (tmp);
+ 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->curl, CURLOPT_VERBOSE, 1);
+#endif
+
+ curl_easy_setopt (sink->curl, CURLOPT_URL, sink->url);
+ curl_easy_setopt (sink->curl, CURLOPT_CONNECTTIMEOUT, sink->timeout);
+
+ curl_easy_setopt (sink->curl, CURLOPT_SOCKOPTDATA, sink);
+ curl_easy_setopt (sink->curl, CURLOPT_SOCKOPTFUNCTION,
+ gst_curl_sink_transfer_socket_cb);
+
+ 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->accept_self_signed && g_str_has_prefix (sink->url, "https")) {
+ /* TODO verify the authenticity of the peer's certificate */
+ curl_easy_setopt (sink->curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ /* TODO check the servers's claimed identity */
+ curl_easy_setopt (sink->curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
+
+ /* proxy settings */
+ 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->curl, CURLOPT_PROXYPORT, sink->proxy_port)
+ != CURLE_OK) {
+ return FALSE;
+ }
+ 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->curl, CURLOPT_HTTPPROXYTUNNEL, 1L)
+ != CURLE_OK) {
+ return FALSE;
+ }
+ }
+
+ /* POST options */
+ curl_easy_setopt (sink->curl, CURLOPT_POST, 1L);
+
+ curl_easy_setopt (sink->curl, CURLOPT_READFUNCTION,
+ gst_curl_sink_transfer_read_cb);
+ curl_easy_setopt (sink->curl, CURLOPT_READDATA, sink);
+ curl_easy_setopt (sink->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;
+ 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;
+ buffer = sink->transfer_buf;
+
+ buf_len = buffer->len;
+ GST_LOG ("write buf len=%" G_GSIZE_FORMAT ", offset=%" G_GSIZE_FORMAT,
+ 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 : %" G_GSIZE_FORMAT, 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->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->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->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->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->multi_handle, sink->curl);
+ gst_curl_sink_set_http_header_unlocked (sink);
+ curl_multi_add_handle (sink->multi_handle, sink->curl);
+ proxy_conn_established = TRUE;
+ }
+ }
+
+ 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");
+ } 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->multi_handle, &running_handles);
+ } while (m_code == CURLM_CALL_MULTI_PERFORM);
+
+ if (resp != RESPONSE_100_CONTINUE) {
+ curl_easy_getinfo (sink->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->curl, CURLINFO_RESPONSE_CODE, &resp);
+ GST_DEBUG_OBJECT (sink, "response code: %ld", 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, ("%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, ("%s",
+ 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->fd);
+ sink->fd.fd = curlfd;
+
+ 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);
+
+ /* 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->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->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->flow_ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ 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->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->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->multi_handle, sink->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->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->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->transfer_thread_close);
+
+ return NULL;
+}
+
+static gboolean
+gst_curl_sink_transfer_setup_unlocked (GstCurlSink * sink)
+{
+ g_assert (sink);
+
+ if (sink->curl == NULL) {
+ /* curl_easy_init automatically calls curl_global_init(3) */
+ if ((sink->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->multi_handle == NULL) {
+ if ((sink->multi_handle = curl_multi_init ()) == NULL) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gst_curl_sink_transfer_cleanup (GstCurlSink * sink)
+{
+ if (sink->curl != NULL) {
+ if (sink->multi_handle != NULL) {
+ curl_multi_remove_handle (sink->multi_handle, sink->curl);
+ }
+ curl_easy_cleanup (sink->curl);
+ sink->curl = NULL;
+ }
+
+ if (sink->multi_handle != NULL) {
+ curl_multi_cleanup (sink->multi_handle);
+ sink->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->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->transfer_thread_close) {
+ GST_LOG ("wait for data aborted due to thread close");
+ } else if (sink->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->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->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->transfer_thread_close = TRUE;
+ g_cond_signal (sink->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->transfer_cond->data_sent) {
+ g_cond_wait (sink->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->transfer_cond->data_available = FALSE;
+ sink->transfer_cond->data_sent = TRUE;
+ g_cond_signal (sink->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->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->qos_dscp & 0x3f) << 2;
+
+ switch (af) {
+ case AF_INET:
+ ret = setsockopt (sink->fd.fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
+ break;
+ case AF_INET6:
+#ifdef IPV6_TCLASS
+ ret = setsockopt (sink->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..d158577ef5
--- /dev/null
+++ b/ext/curl/gstcurlsink.h
@@ -0,0 +1,100 @@
+/* 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 _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 _GstCurlSink
+{
+ GstBaseSink parent;
+
+ /*< private >*/
+ 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 _GstCurlSinkClass
+{
+ GstBaseSinkClass parent_class;
+};
+
+GType gst_curl_sink_get_type (void);
+
+G_END_DECLS
+
+#endif
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;
}
}
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;
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-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
+
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
+
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;
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/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 ace1e18a2f..1fdf22316b 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);
}
@@ -40,7 +40,7 @@ gst_h263_parse_is_delta_unit (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;
+ guint32 psc = 0, 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);
@@ -185,7 +181,7 @@ gst_h263_parse_get_params (H263Params ** params_p, GstBuffer * buffer,
if (hasplusptype) {
guint8 ufep;
guint8 cpm;
- guint32 opptype, mpptype;
+ guint32 opptype = 0, mpptype = 0;
/* 5.1.4 PLUSPTYPE */
@@ -268,7 +264,7 @@ gst_h263_parse_get_params (H263Params ** params_p, 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))
@@ -282,7 +278,7 @@ gst_h263_parse_get_params (H263Params ** params_p, 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;
@@ -455,7 +451,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 +573,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 +655,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..80eb919ae6 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