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 + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + curlsink + Curl sink + Sink/Network + Upload data over the network to a server using libcurl + Patricia Muscalu <patricia@axis.com> + + + sink + sink + always +
ANY
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-h264parse.xml b/docs/plugins/inspect/plugin-h264parse.xml index 14977a52c8..3862d7ee93 100644 --- a/docs/plugins/inspect/plugin-h264parse.xml +++ b/docs/plugins/inspect/plugin-h264parse.xml @@ -10,7 +10,7 @@ Unknown package origin - h264parse + legacyh264parse H264Parse Codec/Parser/Video Parses raw h264 stream diff --git a/docs/plugins/inspect/plugin-mpegtsdemux.xml b/docs/plugins/inspect/plugin-mpegtsdemux.xml new file mode 100644 index 0000000000..6dbd0669f4 --- /dev/null +++ b/docs/plugins/inspect/plugin-mpegtsdemux.xml @@ -0,0 +1,79 @@ + + mpegtsdemux + MPEG TS demuxer + ../../gst/mpegtsdemux/.libs/libgstmpegtsdemux.so + libgstmpegtsdemux.so + 0.10.21.1 + unknown + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + tsdemux + MPEG transport stream demuxer + Codec/Demuxer + Demuxes MPEG2 transport streams + Zaheer Abbas Merali <zaheerabbas at merali dot org>; Edward Hervey <edward.hervey@collabora.co.uk> + + + sink + sink + always +
video/mpegts, systemstream=(boolean)true
+
+ + audio_%04x + source + sometimes +
audio/mpeg, mpegversion=(int){ 1, 4 }; audio/x-lpcm, width=(int){ 16, 20, 24 }, rate=(int){ 48000, 96000 }, channels=(int)[ 1, 8 ], dynamic_range=(int)[ 0, 255 ], emphasis=(boolean){ false, true }, mute=(boolean){ false, true }; audio/x-ac3; audio/x-eac3; audio/x-dts; audio/x-private-ts-lpcm
+
+ + private_%04x + source + sometimes +
ANY
+
+ + subpicture_%04x + source + sometimes +
subpicture/x-pgs; video/x-dvd-subpicture
+
+ + video_%04x + source + sometimes +
video/mpeg, mpegversion=(int){ 1, 2, 4 }, systemstream=(boolean)false; video/x-h264; video/x-dirac; video/x-wmv, wmvversion=(int)3, format=(fourcc)WVC1
+
+
+
+ + tsparse + MPEG transport stream parser + Codec/Parser + Parses MPEG2 transport streams + Alessandro Decina <alessandro@nnva.org>, Zaheer Abbas Merali <zaheerabbas at merali dot org> + + + sink + sink + always +
video/mpegts, systemstream=(boolean)true
+
+ + program_%d + source + sometimes +
video/mpegts, systemstream=(boolean)true
+
+ + src%d + source + request +
video/mpegts, systemstream=(boolean)true
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-rtmpsrc.xml b/docs/plugins/inspect/plugin-rtmpsrc.xml new file mode 100644 index 0000000000..007979cdcb --- /dev/null +++ b/docs/plugins/inspect/plugin-rtmpsrc.xml @@ -0,0 +1,28 @@ + + rtmpsrc + RTMP source + ../../ext/rtmp/.libs/libgstrtmp.so + libgstrtmp.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + rtmpsrc + RTMP Source + Source/File + Read RTMP streams + Bastien Nocera <hadess@hadess.net>, Sebastian Dröge <sebastian.droege@collabora.co.uk> + + + src + source + always +
ANY
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-rtpvp8.xml b/docs/plugins/inspect/plugin-rtpvp8.xml new file mode 100644 index 0000000000..db2051ec91 --- /dev/null +++ b/docs/plugins/inspect/plugin-rtpvp8.xml @@ -0,0 +1,55 @@ + + rtpvp8 + rtpvp8 + ../../gst/rtpvp8/.libs/libgstrtpvp8.so + libgstrtpvp8.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + rtpvp8depay + RTP VP8 depayloader + Codec/Depayloader/Network/RTP + Extracts VP8 video from RTP packets) + Sjoerd Simons <sjoerd@luon.net> + + + sink + sink + always +
application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, media=(string)video, encoding-name=(string)VP8-DRAFT-0-3-2
+
+ + src + source + always +
video/x-vp8
+
+
+
+ + rtpvp8pay + RTP VP8 payloader + Codec/Payloader/Network/RTP + Puts VP8 video in RTP packets) + Sjoerd Simons <sjoerd@luon.net> + + + sink + sink + always +
video/x-vp8
+
+ + src + source + always +
application/x-rtp, payload=(int)[ 96, 127 ], clock-rate=(int)90000, encoding-name=(string)VP8-DRAFT-0-3-2
+
+
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-schro.xml b/docs/plugins/inspect/plugin-schro.xml index 3bb341ad5c..59e7549e68 100644 --- a/docs/plugins/inspect/plugin-schro.xml +++ b/docs/plugins/inspect/plugin-schro.xml @@ -51,26 +51,5 @@
- - schroparse - Dirac Parser - Codec/Parser/Video - Parse Dirac streams - David Schleef <ds@schleef.org> - - - sink - sink - always -
video/x-dirac
-
- - src - source - always -
video/x-dirac; video/x-qt-part; video/x-avi-part; video/x-mp4-part
-
-
-
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-videoparsersbad.xml b/docs/plugins/inspect/plugin-videoparsersbad.xml new file mode 100644 index 0000000000..c961f44b89 --- /dev/null +++ b/docs/plugins/inspect/plugin-videoparsersbad.xml @@ -0,0 +1,76 @@ + + videoparsersbad + videoparsers + ../../gst/videoparsers/.libs/libgstvideoparsersbad.so + libgstvideoparsersbad.so + 0.10.21.1 + LGPL + gst-plugins-bad + GStreamer Bad Plug-ins git + Unknown package origin + + + diracparse + FIXME + Generic + FIXME + David Schleef <ds@schleef.org> + + + sink + sink + always +
application/unknown
+
+ + src + source + always +
application/unknown
+
+
+
+ + h263parse + H.263 parser + Codec/Parser/Video + Parses H.263 streams + Arun Raghavan <arun.raghavan@collabora.co.uk>,Edward Hervey <edward.hervey@collabora.co.uk> + + + sink + sink + always +
video/x-h263, variant=(string)itu, parsed=(boolean)false
+
+ + src + source + always +
video/x-h263, variant=(string)itu, parsed=(boolean)true
+
+
+
+ + h264parse + H.264 parser + Codec/Parser/Video + Parses H.264 streams + Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + + sink + sink + always +
video/x-h264, parsed=(boolean)false
+
+ + src + source + always +
video/x-h264, parsed=(boolean)true
+
+
+
+
+
\ No newline at end of file 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