summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorDave Robillard <dave@drobilla.net>2009-05-26 19:10:44 -0400
committerDave Robillard <dave@drobilla.net>2009-05-26 19:10:44 -0400
commitb75a26657febaf86c4137b4d41c068926325e316 (patch)
tree65c161824169ac09bf8418244937aec6ab77a270 /gst
parent4e1d3bba9c21cb8bbfe70ffed953a8385fb7314d (diff)
parent8f70498c898a65d0938e3e104e91662ff5b693c3 (diff)
downloadgst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.tar.gz
gst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.tar.bz2
gst-plugins-bad-b75a26657febaf86c4137b4d41c068926325e316.zip
Merge branch 'master' of git://anongit.freedesktop.org/gstreamer/gst-plugins-bad into fdo
Diffstat (limited to 'gst')
-rw-r--r--gst/adpcmdec/Makefile.am12
-rw-r--r--gst/adpcmdec/adpcmdec.c452
-rw-r--r--gst/debugutils/fpsdisplaysink.c16
-rw-r--r--gst/deinterlace/.gitignore7
-rw-r--r--gst/deinterlace/Makefile.am12
-rw-r--r--gst/deinterlace/deinterlace.vcproj148
-rw-r--r--gst/deinterlace/gstdeinterlace.c514
-rw-r--r--gst/deinterlace/gstdeinterlace.h74
-rw-r--r--gst/deinterlace2/Makefile.am48
-rw-r--r--gst/deinterlace2/gstdeinterlace2.c1509
-rw-r--r--gst/deinterlace2/gstdeinterlace2.h258
-rw-r--r--gst/deinterlace2/tvtime/greedy.c488
-rw-r--r--gst/deinterlace2/tvtime/greedyh.asm250
-rw-r--r--gst/deinterlace2/tvtime/greedyh.c420
-rw-r--r--gst/deinterlace2/tvtime/greedyhmacros.h75
-rw-r--r--gst/deinterlace2/tvtime/linear.c214
-rw-r--r--gst/deinterlace2/tvtime/linearblend.c231
-rw-r--r--gst/deinterlace2/tvtime/mmx.h723
-rw-r--r--gst/deinterlace2/tvtime/plugins.h54
-rw-r--r--gst/deinterlace2/tvtime/scalerbob.c74
-rw-r--r--gst/deinterlace2/tvtime/sse.h992
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp.c211
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc15
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc174
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc11
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc12
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc10
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc5
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc11
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc10
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc5
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc254
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc6
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc6
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc435
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc241
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc243
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc286
-rw-r--r--gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h164
-rw-r--r--gst/deinterlace2/tvtime/vfir.c187
-rw-r--r--gst/deinterlace2/tvtime/weave.c82
-rw-r--r--gst/deinterlace2/tvtime/weavebff.c88
-rw-r--r--gst/deinterlace2/tvtime/weavetff.c88
-rw-r--r--gst/deinterlace2/tvtime/x86-64_macros.inc82
-rw-r--r--gst/dvdspu/Makefile.am4
-rw-r--r--gst/dvdspu/gstdvdspu-render.c513
-rw-r--r--gst/dvdspu/gstdvdspu.c883
-rw-r--r--gst/dvdspu/gstdvdspu.h132
-rw-r--r--gst/dvdspu/gstspu-common.h56
-rw-r--r--gst/dvdspu/gstspu-pgs.c762
-rw-r--r--gst/dvdspu/gstspu-pgs.h106
-rw-r--r--gst/dvdspu/gstspu-vobsub-render.c536
-rw-r--r--gst/dvdspu/gstspu-vobsub.c513
-rw-r--r--gst/dvdspu/gstspu-vobsub.h110
-rw-r--r--gst/flv/Makefile.am9
-rw-r--r--gst/flv/gstflvdemux.c1323
-rw-r--r--gst/flv/gstflvdemux.h130
-rw-r--r--gst/flv/gstflvmux.c1040
-rw-r--r--gst/flv/gstflvmux.h89
-rw-r--r--gst/flv/gstflvparse.c1283
-rw-r--r--gst/id3tag/Makefile.am19
-rw-r--r--gst/id3tag/gstid3tag.c229
-rw-r--r--gst/id3tag/gstid3tag.h63
-rw-r--r--gst/id3tag/gsttagmux.c495
-rw-r--r--gst/id3tag/gsttagmux.h79
-rw-r--r--gst/id3tag/id3tag.c1194
-rw-r--r--gst/id3tag/id3tag.h (renamed from gst/flv/gstflvparse.h)28
-rw-r--r--gst/mpeg4videoparse/mpeg4videoparse.c8
-rw-r--r--gst/mpegdemux/gstmpegdefs.h4
-rw-r--r--gst/mpegdemux/gstmpegdemux.c134
-rw-r--r--gst/mpegdemux/gstmpegdemux.h5
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.c375
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.h22
-rw-r--r--gst/mpegdemux/gstpesfilter.c18
-rw-r--r--gst/mpegdemux/gstpesfilter.h2
-rw-r--r--gst/mpegdemux/mpegtspacketizer.c19
-rw-r--r--gst/mpegdemux/mpegtspacketizer.h2
-rw-r--r--gst/mpegdemux/mpegtsparse.c69
-rw-r--r--gst/mpegdemux/mpegtsparse.h2
-rw-r--r--gst/mpegvideoparse/mpegpacketiser.c7
-rw-r--r--gst/mpegvideoparse/mpegpacketiser.h2
-rw-r--r--gst/mpegvideoparse/mpegvideoparse.c1
-rw-r--r--gst/mxf/mxf.c3
-rw-r--r--gst/mxf/mxfdemux.c161
-rw-r--r--gst/mxf/mxfdemux.h2
-rw-r--r--gst/mxf/mxfmetadata.c2
-rw-r--r--gst/mxf/mxfmux.c107
-rw-r--r--gst/mxf/mxfmux.h1
-rw-r--r--gst/qtmux/atoms.c12
-rw-r--r--gst/qtmux/gstqtmux.c2
-rw-r--r--gst/qtmux/gstqtmuxmap.c2
-rw-r--r--gst/rtpmanager/gstrtpbin-marshal.list1
-rw-r--r--gst/rtpmanager/gstrtpbin.c361
-rw-r--r--gst/rtpmanager/gstrtpsession.c60
-rw-r--r--gst/rtpmanager/gstrtpssrcdemux.c82
-rw-r--r--gst/rtpmanager/gstrtpssrcdemux.h6
-rw-r--r--gst/rtpmanager/rtpsource.c49
-rw-r--r--gst/sdp/gstsdpdemux.c76
-rw-r--r--gst/sdp/gstsdpdemux.h1
-rw-r--r--gst/y4m/Makefile.am10
-rw-r--r--gst/y4m/gsty4mencode.c332
-rw-r--r--gst/y4m/gsty4mencode.h67
-rw-r--r--gst/y4m/y4menc.vcproj148
103 files changed, 6218 insertions, 14730 deletions
diff --git a/gst/adpcmdec/Makefile.am b/gst/adpcmdec/Makefile.am
new file mode 100644
index 00000000..5c60ad4f
--- /dev/null
+++ b/gst/adpcmdec/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgstadpcmdec.la
+
+# sources used to compile this plug-in
+libgstadpcmdec_la_SOURCES = adpcmdec.c
+
+# flags used to compile this plugin
+# add other _CFLAGS and _LIBS as needed
+libgstadpcmdec_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgstadpcmdec_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgstadpcmdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstadpcmdec_la_LIBTOOLFLAGS = --tag=disable-static
+
diff --git a/gst/adpcmdec/adpcmdec.c b/gst/adpcmdec/adpcmdec.c
new file mode 100644
index 00000000..c58dc5d8
--- /dev/null
+++ b/gst/adpcmdec/adpcmdec.c
@@ -0,0 +1,452 @@
+/* GStreamer
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * Authors: Michael Smith <msmith@songbirdnest.com>
+ *
+ * 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.
+ */
+
+/* Based on MS-ADPCM decoder in libsndfile,
+ Copyright (C) 1999-2002 Erik de Castro Lopo <erikd@zip.com.au
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+
+#define GST_TYPE_ADPCM_DEC \
+ (adpcmdec_get_type ())
+
+#define GST_ADPCM_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_ADPCM_DEC, ADPCMDec))
+
+#define GST_CAT_DEFAULT adpcmdec_debug
+GST_DEBUG_CATEGORY_STATIC (adpcmdec_debug);
+
+static const GstElementDetails adpcmdec_details =
+GST_ELEMENT_DETAILS ("MS-ADPCM decoder",
+ "Codec/Decoder/Audio",
+ "Decode MS AD-PCM audio",
+ "Pioneers of the Inevitable <songbird@songbirdnest.com");
+
+static GstStaticPadTemplate adpcmdec_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-adpcm, "
+ "layout=(string)microsoft, "
+ "block_align = (int) [64, 8096], "
+ "rate = (int)[ 1, MAX ], " "channels = (int)[1,2]")
+ );
+
+static GstStaticPadTemplate adpcmdec_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "depth = (int)16, "
+ "width = (int)16, "
+ "endianness = (int)" G_STRINGIFY (G_BYTE_ORDER) ", "
+ "signed = (boolean)TRUE, "
+ "channels = (int) [1,2], " "rate = (int)[1, MAX]")
+ );
+
+typedef struct _ADPCMDecClass
+{
+ GstElementClass parent_class;
+} ADPCMDecClass;
+
+typedef struct _ADPCMDec
+{
+ GstElement parent;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ GstCaps *output_caps;
+
+ int rate;
+ int channels;
+ int blocksize;
+
+ gboolean is_setup;
+
+ GstClockTime timestamp;
+
+ guint64 out_samples;
+
+ GstAdapter *adapter;
+
+} ADPCMDec;
+
+GST_BOILERPLATE (ADPCMDec, adpcmdec, GstElement, GST_TYPE_ELEMENT);
+static gboolean
+adpcmdec_setup (ADPCMDec * dec)
+{
+ dec->output_caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, dec->rate,
+ "channels", G_TYPE_INT, dec->channels,
+ "width", G_TYPE_INT, 16,
+ "depth", G_TYPE_INT, 16,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER,
+ "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ if (dec->output_caps) {
+ gst_pad_set_caps (dec->srcpad, dec->output_caps);
+ }
+
+ dec->is_setup = TRUE;
+ dec->timestamp = GST_CLOCK_TIME_NONE;
+ dec->adapter = gst_adapter_new ();
+ dec->out_samples = 0;
+
+ return gst_pad_push_event (dec->srcpad, gst_event_new_new_segment (FALSE,
+ 1.0, GST_FORMAT_TIME, 0, -1, 0));
+}
+
+static void
+adpcmdec_teardown (ADPCMDec * dec)
+{
+ if (dec->output_caps) {
+ gst_caps_unref (dec->output_caps);
+ dec->output_caps = NULL;
+ }
+ if (dec->adapter) {
+ g_object_unref (dec->adapter);
+ dec->adapter = NULL;
+ }
+ dec->is_setup = FALSE;
+}
+
+static gboolean
+adpcmdec_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "block_align", &dec->blocksize))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "rate", &dec->rate))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "channels", &dec->channels))
+ return FALSE;
+
+ if (dec->is_setup)
+ adpcmdec_teardown (dec);
+ gst_object_unref (dec);
+
+ return TRUE;
+}
+
+
+/*=====================================================================
+ * From libsndfile:
+ *
+ * MS ADPCM Block Layout.
+ * ======================
+ * Block is usually 256, 512 or 1024 bytes depending on sample rate.
+ * For a mono file, the block is laid out as follows:
+ * byte purpose
+ * 0 block predictor [0..6]
+ * 1,2 initial idelta (positive)
+ * 3,4 sample 1
+ * 5,6 sample 0
+ * 7..n packed bytecodes
+ *
+ * For a stereo file, the block is laid out as follows:
+ * byte purpose
+ * 0 block predictor [0..6] for left channel
+ * 1 block predictor [0..6] for right channel
+ * 2,3 initial idelta (positive) for left channel
+ * 4,5 initial idelta (positive) for right channel
+ * 6,7 sample 1 for left channel
+ * 8,9 sample 1 for right channel
+ * 10,11 sample 0 for left channel
+ * 12,13 sample 0 for right channel
+ * 14..n packed bytecodes
+ *
+ *=====================================================================
+*/
+static int AdaptationTable[] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+};
+
+static int AdaptCoeff1[] = {
+ 256, 512, 0, 192, 240, 460, 392
+};
+
+static int AdaptCoeff2[] = {
+ 0, -256, 0, 64, 0, -208, -232
+};
+
+static gint16
+read_sample (guint8 * data)
+{
+ guint16 val = data[0] | (data[1] << 8);
+ return *((gint16 *) & val);
+}
+
+/* Decode a single block of data from 'data', storing 'n_samples' decoded 16 bit
+ samples in 'samples'.
+
+ All buffer lengths have been verified by the caller
+ */
+static gboolean
+adpcmdec_decode_ms_block (ADPCMDec * dec, int n_samples, guint8 * data,
+ gint16 * samples)
+{
+ gint16 pred[2];
+ gint16 idelta[2];
+ int idx; /* Current byte offset in 'data' */
+ int i; /* Current sample index in 'samples' */
+
+ /* Read the block header, verify for sanity */
+ if (dec->channels == 1) {
+ pred[0] = data[0];
+ idelta[0] = read_sample (data + 1);
+ samples[1] = read_sample (data + 3);
+ samples[0] = read_sample (data + 5);
+ idx = 7;
+ i = 2;
+ if (pred[0] < 0 || pred[0] > 6) {
+ GST_WARNING_OBJECT (dec, "Invalid block predictor");
+ return FALSE;
+ }
+ }
+
+ else {
+ pred[0] = data[0];
+ pred[1] = data[1];
+ idelta[0] = read_sample (data + 2);
+ idelta[1] = read_sample (data + 4);
+ samples[2] = read_sample (data + 6);
+ samples[3] = read_sample (data + 8);
+ samples[0] = read_sample (data + 10);
+ samples[1] = read_sample (data + 12);
+ idx = 14;
+ i = 4;
+ if (pred[0] < 0 || pred[0] > 6 || pred[1] < 0 || pred[1] > 6) {
+ GST_WARNING_OBJECT (dec, "Invalid block predictor");
+ return FALSE;
+ }
+ }
+ for (; i < n_samples; i++) {
+ int chan = i % dec->channels;
+ int bytecode;
+ int delta;
+ int current;
+ int predict;
+ if (i % 2 == 0) {
+ bytecode = (data[idx] >> 4) & 0x0F;
+ } else {
+ bytecode = data[idx] & 0x0F;
+ idx++;
+ }
+
+ delta = idelta[chan];
+ idelta[chan] = (AdaptationTable[bytecode] * delta) >> 8;
+ if (idelta[chan] < 16)
+ idelta[chan] = 16;
+
+ /* Bytecode is used above as an index into the table. Below, it's used
+ as a signed 4-bit value; convert appropriately */
+ if (bytecode & 0x8)
+ bytecode -= 0x10;
+
+ predict = ((samples[i - dec->channels] * AdaptCoeff1[pred[chan]]) +
+ (samples[i - 2 * dec->channels] * AdaptCoeff2[pred[chan]])
+ ) >> 8;
+
+ current = (bytecode * delta) + predict;
+
+ /* Clamp to 16 bits, store decoded sample */
+ samples[i] = CLAMP (current, G_MININT16, G_MAXINT16);
+ }
+ return TRUE;
+}
+
+static GstFlowReturn
+adpcmdec_chain (GstPad * pad, GstBuffer * buf)
+{
+ ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
+ GstFlowReturn ret = GST_FLOW_OK;
+ guint8 *data;
+ GstBuffer *outbuf = NULL;
+ GstBuffer *databuf = NULL;
+ int outsize;
+ int samples;
+ gboolean res;
+
+ if (!dec->is_setup)
+ adpcmdec_setup (dec);
+
+ if (dec->timestamp == GST_CLOCK_TIME_NONE)
+ dec->timestamp = GST_BUFFER_TIMESTAMP (buf);
+
+ gst_adapter_push (dec->adapter, buf);
+
+ while (gst_adapter_available (dec->adapter) >= dec->blocksize) {
+ databuf = gst_adapter_take_buffer (dec->adapter, dec->blocksize);
+ data = GST_BUFFER_DATA (databuf);
+
+ /* Each block has a 3 byte header per channel, plus 4 bytes per channel to
+ give two initial sample values per channel. Then the remainder gives
+ two samples per byte */
+ samples = (dec->blocksize - 7 * dec->channels) * 2 + 2 * dec->channels;
+ outsize = 2 * samples;
+ outbuf = gst_buffer_new_and_alloc (outsize);
+
+ res = adpcmdec_decode_ms_block (dec, samples, data,
+ (gint16 *) (GST_BUFFER_DATA (outbuf)));
+
+ /* Done with input data, free it */
+ gst_buffer_unref (databuf);
+
+ if (!res) {
+ gst_buffer_unref (outbuf);
+ GST_WARNING_OBJECT (dec, "Decode of block failed");
+ ret = GST_FLOW_ERROR;
+ goto done;
+ }
+
+ gst_buffer_set_caps (outbuf, dec->output_caps);
+ GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp;
+ dec->out_samples += samples / dec->channels;
+ dec->timestamp =
+ gst_util_uint64_scale_int (dec->out_samples, GST_SECOND, dec->rate);
+ GST_BUFFER_DURATION (outbuf) =
+ dec->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
+
+ ret = gst_pad_push (dec->srcpad, outbuf);
+ if (ret != GST_FLOW_OK)
+ goto done;
+ }
+
+done:
+ gst_object_unref (dec);
+
+ return ret;
+}
+
+static gboolean
+adpcmdec_sink_event (GstPad * pad, GstEvent * event)
+{
+ ADPCMDec *dec = (ADPCMDec *) gst_pad_get_parent (pad);
+ gboolean res;
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_STOP:
+ gst_adapter_clear (dec->adapter);
+ /* Fall through */
+ default:
+ res = gst_pad_push_event (dec->srcpad, event);
+ break;
+ }
+ gst_object_unref (dec);
+ return res;
+}
+
+static GstStateChangeReturn
+adpcmdec_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ ADPCMDec *dec = (ADPCMDec *) 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);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ adpcmdec_teardown (dec);
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void
+adpcmdec_dispose (GObject * obj)
+{
+ G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
+static void
+adpcmdec_init (ADPCMDec * dec, ADPCMDecClass * klass)
+{
+ dec->sinkpad =
+ gst_pad_new_from_static_template (&adpcmdec_sink_template, "sink");
+ gst_pad_set_setcaps_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (adpcmdec_sink_setcaps));
+ gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (adpcmdec_chain));
+ gst_pad_set_event_function (dec->sinkpad,
+ GST_DEBUG_FUNCPTR (adpcmdec_sink_event));
+ gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
+ dec->srcpad =
+ gst_pad_new_from_static_template (&adpcmdec_src_template, "src");
+ gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
+}
+
+static void
+adpcmdec_class_init (ADPCMDecClass * klass)
+{
+ GObjectClass *gobjectclass = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+ gobjectclass->dispose = adpcmdec_dispose;
+ gstelement_class->change_state = adpcmdec_change_state;
+} static void
+
+adpcmdec_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&adpcmdec_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&adpcmdec_src_template));
+ gst_element_class_set_details (element_class, &adpcmdec_details);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (adpcmdec_debug, "adpcmdec", 0, "ADPCM Decoders");
+ if (!gst_element_register (plugin, "msadpcmdec", GST_RANK_PRIMARY,
+ GST_TYPE_ADPCM_DEC)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "adpcmdec",
+ "ADPCM decoder", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+ GST_PACKAGE_ORIGIN);
diff --git a/gst/debugutils/fpsdisplaysink.c b/gst/debugutils/fpsdisplaysink.c
index b37ab112..54f5cc54 100644
--- a/gst/debugutils/fpsdisplaysink.c
+++ b/gst/debugutils/fpsdisplaysink.c
@@ -267,11 +267,11 @@ fps_display_sink_start (GstFPSDisplaySink * self)
gst_object_ref (self->text_overlay);
g_object_set (self->text_overlay,
"font-desc", DEFAULT_FONT, "silent", FALSE, NULL);
- }
- gst_bin_add (GST_BIN (self), self->text_overlay);
+ gst_bin_add (GST_BIN (self), self->text_overlay);
- if (!gst_element_link (self->text_overlay, self->video_sink)) {
- GST_ERROR_OBJECT (self, "Could not link elements");
+ if (!gst_element_link (self->text_overlay, self->video_sink)) {
+ GST_ERROR_OBJECT (self, "Could not link elements");
+ }
}
target_pad = gst_element_get_static_pad (self->text_overlay, "video_sink");
}
@@ -280,6 +280,7 @@ no_text_overlay:
if (self->text_overlay) {
gst_element_unlink (self->text_overlay, self->video_sink);
gst_bin_remove (GST_BIN (self), self->text_overlay);
+ self->text_overlay = NULL;
}
target_pad = gst_element_get_static_pad (self->video_sink, "sink");
}
@@ -300,6 +301,13 @@ fps_display_sink_stop (GstFPSDisplaySink * self)
g_source_remove (self->timeout_id);
self->timeout_id = 0;
}
+
+ if (self->text_overlay) {
+ gst_element_unlink (self->text_overlay, self->video_sink);
+ gst_bin_remove (GST_BIN (self), self->text_overlay);
+ gst_object_unref (self->text_overlay);
+ self->text_overlay = NULL;
+ }
}
static void
diff --git a/gst/deinterlace/.gitignore b/gst/deinterlace/.gitignore
deleted file mode 100644
index 08f5ed37..00000000
--- a/gst/deinterlace/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-Makefile
-Makefile.in
-*.o
-*.lo
-*.la
-.deps
-.libs
diff --git a/gst/deinterlace/Makefile.am b/gst/deinterlace/Makefile.am
deleted file mode 100644
index 3d842d01..00000000
--- a/gst/deinterlace/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-plugin_LTLIBRARIES = libgstdeinterlace.la
-
-libgstdeinterlace_la_SOURCES = gstdeinterlace.c
-libgstdeinterlace_la_CFLAGS = \
- $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
-libgstdeinterlace_la_LIBADD = \
- $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS)
-libgstdeinterlace_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstdeinterlace_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = gstdeinterlace.h
-
diff --git a/gst/deinterlace/deinterlace.vcproj b/gst/deinterlace/deinterlace.vcproj
deleted file mode 100644
index 200d88ee..00000000
--- a/gst/deinterlace/deinterlace.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="deinterlace"
- ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678B0}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="../../win32/Debug"
- IntermediateDirectory="../../win32/Debug"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;deinterlace_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
- MinimalRebuild="TRUE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
- OutputFile="$(OutDir)/gstdeinterlace.dll"
- LinkIncremental="2"
- AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
- ModuleDefinitionFile=""
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile="$(OutDir)/deinterlace.pdb"
- SubSystem="2"
- OptimizeReferences="2"
- ImportLibrary="$(OutDir)/gstdeinterlace.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="../../win32/Release"
- IntermediateDirectory="../../win32/Release"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
- PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;deinterlace_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
- RuntimeLibrary="2"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
- OutputFile="$(OutDir)/gstdeinterlace.dll"
- LinkIncremental="1"
- AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
- ModuleDefinitionFile=""
- GenerateDebugInformation="TRUE"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- ImportLibrary="$(OutDir)/gstdeinterlace.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
- <File
- RelativePath=".\gstdeinterlace.c">
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
- <File
- RelativePath=".\gstdeinterlace.h">
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c
deleted file mode 100644
index b2a25afe..00000000
--- a/gst/deinterlace/gstdeinterlace.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/* GStreamer simple deinterlacing plugin
- * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
- *
- * 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.
- */
-/* based on the Area Based Deinterlacer (for RGB frames) */
-/* (a VirtualDub filter) from Gunnar Thalin <guth@home.se> */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include "gstdeinterlace.h"
-#include <gst/video/video.h>
-
-/**
- * SECTION:element-deinterlace
- *
- * Adaptively deinterlaces video frames by detecting interlacing artifacts.
- * An edge detection matrix is used, with a threshold value. Pixels detected
- * as 'interlaced' are replaced with pixels blended from the pixels above and
- * below.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v videotestsrc ! deinterlace ! ffmpegcolorspace ! xvimagesink
- * ]|
- * </refsect2>
- */
-
-GST_DEBUG_CATEGORY_STATIC (deinterlace_debug);
-#define GST_CAT_DEFAULT deinterlace_debug
-
-#define DEFAULT_DI_AREA_ONLY FALSE
-#define DEFAULT_NI_AREA_ONLY FALSE
-#define DEFAULT_BLEND FALSE
-#define DEFAULT_DEINTERLACE TRUE
-#define DEFAULT_THRESHOLD 20
-#define DEFAULT_EDGE_DETECT 25
-
-enum
-{
- ARG_0,
- ARG_DI_ONLY,
- ARG_NI_ONLY,
- ARG_BLEND,
- ARG_THRESHOLD,
- ARG_EDGE_DETECT,
- ARG_DEINTERLACE
-};
-
-static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, Y42B }"))
- );
-
-static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ I420, Y42B }"))
- );
-
-GST_BOILERPLATE (GstDeinterlace, gst_deinterlace, GstBaseTransform,
- GST_TYPE_BASE_TRANSFORM);
-
-static void gst_deinterlace_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_deinterlace_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static GstFlowReturn gst_deinterlace_transform_ip (GstBaseTransform * trans,
- GstBuffer * buf);
-static gboolean gst_deinterlace_stop (GstBaseTransform * trans);
-static gboolean gst_deinterlace_set_caps (GstBaseTransform * trans,
- GstCaps * incaps, GstCaps * outcaps);
-static GstCaps *gst_deinterlace_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * incaps);
-
-static void
-gst_deinterlace_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 (&src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
-
- gst_element_class_set_details_simple (element_class, "Deinterlace",
- "Filter/Effect/Video", "Deinterlace video",
- "Wim Taymans <wim.taymans@gmail.com>");
-}
-
-static void
-gst_deinterlace_class_init (GstDeinterlaceClass * klass)
-{
- GObjectClass *gobject_class;
- GstBaseTransformClass *basetransform_class;
-
- gobject_class = (GObjectClass *) klass;
- basetransform_class = (GstBaseTransformClass *) klass;
-
- gobject_class->set_property = gst_deinterlace_set_property;
- gobject_class->get_property = gst_deinterlace_get_property;
-
- /**
- * GstDeinterlace:deinterlace:
- *
- * Turn processing on/off. When false, no modification of the
- * video frames occurs and they pass through intact.
- */
- g_object_class_install_property (gobject_class, ARG_DEINTERLACE,
- g_param_spec_boolean ("deinterlace", "deinterlace",
- "turn deinterlacing on/off", DEFAULT_DEINTERLACE, G_PARAM_READWRITE));
- /**
- * GstDeinterlace:di-area-only:
- *
- * When set to true, only areas affected by the deinterlacing are output,
- * making it easy to see which regions are being modified.
- *
- * See Also: #GstDeinterlace:ni-area-only
- */
- g_object_class_install_property (gobject_class, ARG_DI_ONLY,
- g_param_spec_boolean ("di-area-only", "di-area-only",
- "displays deinterlaced areas only", DEFAULT_DI_AREA_ONLY,
- G_PARAM_READWRITE));
- /**
- * GstDeinterlace:ni-area-only:
- *
- * When set to true, only areas unaffected by the deinterlacing are output,
- * making it easy to see which regions are being preserved intact.
- *
- * See Also: #GstDeinterlace:di-area-only
- */
- g_object_class_install_property (gobject_class, ARG_NI_ONLY,
- g_param_spec_boolean ("ni-area-only", "ni-area-only",
- "displays non-interlaced areas only", DEFAULT_DI_AREA_ONLY,
- G_PARAM_READWRITE));
- /**
- * GstDeinterlace:blend:
- *
- * Change the blending for pixels which are detected as
- * 'interlacing artifacts'. When true, the output pixel is a weighted
- * average (1,2,1) of the pixel and the pixels above and below it.
- * When false, the odd field lines are preserved, and the even field lines
- * are averaged from the surrounding pixels above and below (the odd field).
- */
- g_object_class_install_property (gobject_class, ARG_BLEND,
- g_param_spec_boolean ("blend", "blend", "blend", DEFAULT_BLEND,
- G_PARAM_READWRITE));
- /**
- * GstDeinterlace:threshold:
- *
- * Affects the threshold of the edge-detection function used for detecting
- * interlacing artifacts.
- */
- g_object_class_install_property (gobject_class, ARG_THRESHOLD,
- g_param_spec_int ("threshold", "Edge-detection threshold",
- "Threshold value for the interlacing artifacts in the output "
- "of the edge detection", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
- /**
- * GstDeinterlace:edge-detect:
- *
- * Affects the weighting of the edge-detection function used for detecting
- * interlacing artifacts.
- */
- g_object_class_install_property (gobject_class, ARG_EDGE_DETECT,
- g_param_spec_int ("edge-detect", "edge detection weighting",
- "Weighting value used for calculating the edge detection matrix",
- G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
-
- basetransform_class->transform_ip =
- GST_DEBUG_FUNCPTR (gst_deinterlace_transform_ip);
- basetransform_class->transform_caps =
- GST_DEBUG_FUNCPTR (gst_deinterlace_transform_caps);
- basetransform_class->stop = GST_DEBUG_FUNCPTR (gst_deinterlace_stop);
- basetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_deinterlace_set_caps);
-}
-
-static void
-gst_deinterlace_init (GstDeinterlace * filter, GstDeinterlaceClass * klass)
-{
- filter->show_deinterlaced_area_only = DEFAULT_DI_AREA_ONLY;
- filter->show_noninterlaced_area_only = DEFAULT_NI_AREA_ONLY;
- filter->blend = DEFAULT_BLEND;
- filter->deinterlace = DEFAULT_DEINTERLACE;
- filter->threshold = DEFAULT_THRESHOLD;
- filter->edge_detect = DEFAULT_EDGE_DETECT;
- /*filter->threshold_blend = 0; */
-
- filter->src = NULL;
- filter->picsize = 0;
-}
-
-static gboolean
-gst_deinterlace_stop (GstBaseTransform * trans)
-{
- GstDeinterlace *filter;
-
- filter = GST_DEINTERLACE (trans);
-
- g_free (filter->src);
- filter->src = NULL;
- filter->picsize = 0;
- filter->width = 0;
- filter->height = 0;
-
- return TRUE;
-}
-
-static GstCaps *
-gst_deinterlace_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * incaps)
-{
- return gst_caps_ref (incaps);
-}
-
-static gboolean
-gst_deinterlace_set_caps (GstBaseTransform * trans, GstCaps * incaps,
- GstCaps * outcaps)
-{
- GstDeinterlace *filter;
- GstVideoFormat fmt;
- GstStructure *s;
- guint32 fourcc;
- gint picsize, w, h;
-
- filter = GST_DEINTERLACE (trans);
-
- g_assert (gst_caps_is_equal_fixed (incaps, outcaps));
-
- s = gst_caps_get_structure (incaps, 0);
- if (!gst_structure_get_int (s, "width", &w) ||
- !gst_structure_get_int (s, "height", &h) ||
- !gst_structure_get_fourcc (s, "format", &fourcc)) {
- return FALSE;
- }
-
- filter->width = w;
- filter->height = h;
- filter->fourcc = fourcc;
-
- GST_DEBUG_OBJECT (filter, "width x height = %d x %d, fourcc: %"
- GST_FOURCC_FORMAT, w, h, GST_FOURCC_ARGS (fourcc));
-
- fmt = gst_video_format_from_fourcc (fourcc);
-
- filter->y_stride = gst_video_format_get_row_stride (fmt, 0, w);
- filter->u_stride = gst_video_format_get_row_stride (fmt, 1, w);
- filter->v_stride = gst_video_format_get_row_stride (fmt, 2, w);
-
- filter->uv_height = gst_video_format_get_component_height (fmt, 1, h);
-
- filter->y_off = gst_video_format_get_component_offset (fmt, 0, w, h);
- filter->u_off = gst_video_format_get_component_offset (fmt, 1, w, h);
- filter->v_off = gst_video_format_get_component_offset (fmt, 2, w, h);
-
- picsize = gst_video_format_get_size (fmt, w, h);
-
- if (filter->picsize != picsize) {
- filter->picsize = picsize;
- g_free (filter->src); /* free + alloc avoids memcpy */
- filter->src = g_malloc0 (filter->picsize);
- GST_LOG_OBJECT (filter, "temp buffer size %d", filter->picsize);
- }
-
- return TRUE;
-}
-
-static GstFlowReturn
-gst_deinterlace_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
-{
- GstDeinterlace *filter;
- gboolean bShowDeinterlacedAreaOnly;
- gboolean bShowNoninterlacedAreaOnly;
- gint y0, y1, y2, y3;
- guchar *psrc1, *pdst1, *yuvptr, *src;
- gint iInterlaceValue0, iInterlaceValue1, iInterlaceValue2;
- gint x, y, p;
- gint y_line;
- guchar *y_dst, *y_src;
- guchar fill_value;
- gboolean bBlend;
- gboolean bDeinterlace;
- gint iThreshold;
- gint iEdgeDetect;
- gint width, height;
-
- /* g_assert (gst_buffer_is_writable (buf)); */
-
- filter = GST_DEINTERLACE (trans);
-
- GST_OBJECT_LOCK (filter);
- bBlend = filter->blend;
- bDeinterlace = filter->deinterlace;
- iThreshold = filter->threshold;
- iEdgeDetect = filter->edge_detect;
- bShowDeinterlacedAreaOnly = filter->show_deinterlaced_area_only;
- bShowNoninterlacedAreaOnly = filter->show_noninterlaced_area_only;
- GST_OBJECT_UNLOCK (filter);
-
- src = filter->src;
- yuvptr = GST_BUFFER_DATA (buf);
-
- memcpy (filter->src, yuvptr, filter->picsize);
-
-
- iThreshold = iThreshold * iThreshold * 4;
- /* We don't want an integer overflow in the interlace calculation. */
- if (iEdgeDetect > 180)
- iEdgeDetect = 180;
- iEdgeDetect = iEdgeDetect * iEdgeDetect;
-
- for (p = 0; p < 3; p++) {
- switch (p) {
- case 0:
- y_dst = yuvptr + filter->y_off; /* dst y pointer */
- y_line = filter->y_stride;
- y_src = src + filter->y_off;
- width = filter->width;
- height = filter->height;
- fill_value = 0;
- break;
- case 1:
- y_dst = yuvptr + filter->u_off; /* dst U pointer */
- y_line = filter->u_stride;
- y_src = src + filter->u_off;
- width = filter->width / 2;
- height = filter->uv_height;
- fill_value = 128;
- break;
- case 2:
- y_dst = yuvptr + filter->v_off; /* dst V pointer */
- y_line = filter->v_stride;
- y_src = src + filter->v_off;
- width = filter->width / 2;
- height = filter->uv_height;
- fill_value = 128;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- for (x = 0; x < width; x++) {
- pdst1 = y_dst + x;
- psrc1 = y_src + x;
- iInterlaceValue1 = iInterlaceValue2 = 0;
-
- for (y = 0; y < height; y++, psrc1 += y_line, pdst1 += y_line) {
- /* current line is 1 */
- y0 = y1 = y2 = y3 = *psrc1;
- if (y > 0)
- y0 = *(psrc1 - y_line);
- if (y < (height - 1))
- y2 = *(psrc1 + y_line);
- if (y < (height - 2))
- y3 = *(psrc1 + 2 * y_line);
-
- iInterlaceValue0 = iInterlaceValue1;
- iInterlaceValue1 = iInterlaceValue2;
-
- if (y < height - 1)
- iInterlaceValue2 =
- (ABS (y1 - y2) * ABS (y3 - y2) - ((iEdgeDetect * (y1 - y3) * (y1 -
- y3)) >> 12)) * 10;
- else
- iInterlaceValue2 = 0;
-
- if ((iInterlaceValue0 + 2 * iInterlaceValue1 + iInterlaceValue2 >
- iThreshold) && (y > 0)) {
- if (bShowNoninterlacedAreaOnly) {
- *pdst1 = fill_value; /* blank the point and so the interlac area */
- } else {
- if (bDeinterlace) {
- if (bBlend) {
- *pdst1 = (unsigned char) ((y0 + 2 * y1 + y2) >> 2);
- } else {
- /* this method seems to work better than blending if the */
- /* quality is pretty bad and the half pics don't fit together */
- if ((y % 2) == 1) { /* if odd simply copy the value */
- *pdst1 = *psrc1;
- } else { /* if even interpolate the line (upper + lower)/2 */
- *pdst1 = (unsigned char) ((y0 + y2) >> 1);
- }
- }
- } else {
- *pdst1 = *psrc1;
- }
- }
-
- } else {
- /* so we went below the treshold and therefore we don't have to */
- /* change anything */
- if (bShowDeinterlacedAreaOnly) {
- /* this is for testing to see how we should tune the treshhold */
- /* and shows as the things that haven't change because the */
- /* threshold was to low?? (or shows that everything is ok :-) */
- *pdst1 = fill_value; /* blank the point and so the non-interlac area */
- } else {
- *pdst1 = *psrc1;
- }
- }
- }
- }
- }
-
- return GST_FLOW_OK;
-}
-
-static void
-gst_deinterlace_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlace *filter;
-
- filter = GST_DEINTERLACE (object);
-
- GST_OBJECT_LOCK (filter);
- switch (prop_id) {
- case ARG_DEINTERLACE:
- filter->deinterlace = g_value_get_boolean (value);
- break;
- case ARG_DI_ONLY:
- filter->show_deinterlaced_area_only = g_value_get_boolean (value);
- break;
- case ARG_NI_ONLY:
- filter->show_noninterlaced_area_only = g_value_get_boolean (value);
- break;
- case ARG_BLEND:
- filter->blend = g_value_get_boolean (value);
- break;
- case ARG_THRESHOLD:
- filter->threshold = g_value_get_int (value);
- break;
- case ARG_EDGE_DETECT:
- filter->edge_detect = g_value_get_int (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- GST_OBJECT_UNLOCK (filter);
-}
-
-static void
-gst_deinterlace_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstDeinterlace *filter;
-
- filter = GST_DEINTERLACE (object);
-
- GST_OBJECT_LOCK (filter);
- switch (prop_id) {
- case ARG_DEINTERLACE:
- g_value_set_boolean (value, filter->deinterlace);
- break;
- case ARG_DI_ONLY:
- g_value_set_boolean (value, filter->show_deinterlaced_area_only);
- break;
- case ARG_NI_ONLY:
- g_value_set_boolean (value, filter->show_noninterlaced_area_only);
- break;
- case ARG_BLEND:
- g_value_set_boolean (value, filter->blend);
- break;
- case ARG_THRESHOLD:
- g_value_set_int (value, filter->threshold);
- break;
- case ARG_EDGE_DETECT:
- g_value_set_int (value, filter->edge_detect);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- GST_OBJECT_UNLOCK (filter);
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (deinterlace_debug, "deinterlace", 0,
- "deinterlace element");
-
- if (!gst_element_register (plugin, "deinterlace", GST_RANK_NONE,
- gst_deinterlace_get_type ()))
- return FALSE;
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "gstinterlace",
- "Deinterlace video", plugin_init, PACKAGE_VERSION, "LGPL", GST_PACKAGE_NAME,
- GST_PACKAGE_ORIGIN);
diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h
deleted file mode 100644
index faa8e811..00000000
--- a/gst/deinterlace/gstdeinterlace.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* GStreamer simple deinterlacing plugin
- * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
- *
- * 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_DEINTERLACE_H__
-#define __GST_DEINTERLACE_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstbasetransform.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_DEINTERLACE (gst_deinterlace_get_type())
-#define GST_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE,GstDeinterlace))
-#define GST_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE,GstDeinterlaceClass))
-#define GST_IS_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE))
-#define GST_IS_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE))
-
-typedef struct _GstDeinterlace GstDeinterlace;
-typedef struct _GstDeinterlaceClass GstDeinterlaceClass;
-
-struct _GstDeinterlace {
- GstBaseTransform basetransform;
-
- /*< private >*/
- gint width;
- gint height;
- gint uv_height;
- guint32 fourcc;
-
- gboolean show_deinterlaced_area_only;
- gboolean show_noninterlaced_area_only;
- gboolean blend;
- gboolean deinterlace;
- gint threshold_blend; /* here we start blending */
- gint threshold; /* here we start interpolating TODO FIXME */
- gint edge_detect;
-
- gint picsize;
- gint y_stride;
- gint u_stride;
- gint v_stride;
- gint y_off;
- gint u_off;
- gint v_off;
-
- guchar *src;
-};
-
-struct _GstDeinterlaceClass {
- GstBaseTransformClass basetransformclass;
-};
-
-GType gst_deinterlace_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_DEINTERLACE_H__ */
diff --git a/gst/deinterlace2/Makefile.am b/gst/deinterlace2/Makefile.am
deleted file mode 100644
index 1de59919..00000000
--- a/gst/deinterlace2/Makefile.am
+++ /dev/null
@@ -1,48 +0,0 @@
-plugin_LTLIBRARIES = libgstdeinterlace2.la
-
-libgstdeinterlace2_la_SOURCES = \
- gstdeinterlace2.c \
- tvtime/greedy.c \
- tvtime/greedyh.c \
- tvtime/vfir.c \
- tvtime/tomsmocomp.c \
- tvtime/weavetff.c \
- tvtime/weavebff.c \
- tvtime/weave.c \
- tvtime/linear.c \
- tvtime/linearblend.c \
- tvtime/scalerbob.c
-
-libgstdeinterlace2_la_CFLAGS = $(GST_CFLAGS) \
- $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(LIBOIL_CFLAGS)
-libgstdeinterlace2_la_LIBADD = $(GST_LIBS) \
- $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(LIBOIL_LIBS)
-libgstdeinterlace2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstdeinterlace2_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = \
- gstdeinterlace2.h \
- tvtime/mmx.h \
- tvtime/sse.h \
- tvtime/greedyh.asm \
- tvtime/greedyhmacros.h \
- tvtime/plugins.h \
- tvtime/x86-64_macros.inc \
- tvtime/tomsmocomp/SearchLoop0A.inc \
- tvtime/tomsmocomp/SearchLoopBottom.inc \
- tvtime/tomsmocomp/SearchLoopEdgeA8.inc \
- tvtime/tomsmocomp/SearchLoopEdgeA.inc \
- tvtime/tomsmocomp/SearchLoopOddA2.inc \
- tvtime/tomsmocomp/SearchLoopOddA6.inc \
- tvtime/tomsmocomp/SearchLoopOddAH2.inc \
- tvtime/tomsmocomp/SearchLoopOddAH.inc \
- tvtime/tomsmocomp/SearchLoopOddA.inc \
- tvtime/tomsmocomp/SearchLoopTop.inc \
- tvtime/tomsmocomp/SearchLoopVAH.inc \
- tvtime/tomsmocomp/SearchLoopVA.inc \
- tvtime/tomsmocomp/StrangeBob.inc \
- tvtime/tomsmocomp/TomsMoCompAll2.inc \
- tvtime/tomsmocomp/TomsMoCompAll.inc \
- tvtime/tomsmocomp/tomsmocompmacros.h \
- tvtime/tomsmocomp/WierdBob.inc
-
diff --git a/gst/deinterlace2/gstdeinterlace2.c b/gst/deinterlace2/gstdeinterlace2.c
deleted file mode 100644
index b293b43e..00000000
--- a/gst/deinterlace2/gstdeinterlace2.c
+++ /dev/null
@@ -1,1509 +0,0 @@
-/*
- * GStreamer
- * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
- * Copyright (C) 2008-2009 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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-deinterlace2
- *
- * deinterlace2 deinterlaces interlaced video frames to progressive video frames.
- * For this different algorithms can be selected which will be described later.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v filesrc location=/path/to/file ! decodebin2 ! ffmpegcolorspace ! deinterlace2 ! ffmpegcolorspace ! autovideosink
- * ]| This pipeline deinterlaces a video file with the default deinterlacing options.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <liboil/liboil.h>
-
-#include "gstdeinterlace2.h"
-#include "tvtime/plugins.h"
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_STATIC (deinterlace2_debug);
-#define GST_CAT_DEFAULT (deinterlace2_debug)
-
-/* Object signals and args */
-enum
-{
- LAST_SIGNAL
-};
-
-/* Properties */
-
-#define DEFAULT_MODE GST_DEINTERLACE2_MODE_INTERLACED
-#define DEFAULT_METHOD GST_DEINTERLACE2_GREEDY_H
-#define DEFAULT_FIELDS GST_DEINTERLACE2_ALL
-#define DEFAULT_FIELD_LAYOUT GST_DEINTERLACE2_LAYOUT_AUTO
-
-enum
-{
- PROP_0,
- PROP_MODE,
- PROP_METHOD,
- PROP_FIELDS,
- PROP_FIELD_LAYOUT,
- PROP_LAST
-};
-
-G_DEFINE_TYPE (GstDeinterlaceMethod, gst_deinterlace_method, GST_TYPE_OBJECT);
-
-static void
-gst_deinterlace_method_class_init (GstDeinterlaceMethodClass * klass)
-{
-
-}
-
-static void
-gst_deinterlace_method_init (GstDeinterlaceMethod * self)
-{
-
-}
-
-static void
-gst_deinterlace_method_deinterlace_frame (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, GstBuffer * outbuf)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- klass->deinterlace_frame (self, parent, outbuf);
-}
-
-static gint
-gst_deinterlace_method_get_fields_required (GstDeinterlaceMethod * self)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- return klass->fields_required;
-}
-
-static gint
-gst_deinterlace_method_get_latency (GstDeinterlaceMethod * self)
-{
- GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);
-
- return klass->latency;
-}
-
-
-G_DEFINE_TYPE (GstDeinterlaceSimpleMethod, gst_deinterlace_simple_method,
- GST_TYPE_DEINTERLACE_METHOD);
-
-static void
-gst_deinterlace_simple_method_interpolate_scanline (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m1, parent->row_stride);
-}
-
-static void
-gst_deinterlace_simple_method_copy_scanline (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m0, parent->row_stride);
-}
-
-static void
-gst_deinterlace_simple_method_deinterlace_frame (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, GstBuffer * outbuf)
-{
- GstDeinterlaceSimpleMethodClass *dsm_class =
- GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS (self);
- GstDeinterlaceMethodClass *dm_class = GST_DEINTERLACE_METHOD_GET_CLASS (self);
- GstDeinterlaceScanlineData scanlines;
- guint8 *out = GST_BUFFER_DATA (outbuf);
- guint8 *field0 = NULL, *field1 = NULL, *field2 = NULL, *field3 = NULL;
- gint cur_field_idx = parent->history_count - dm_class->fields_required;
- guint cur_field_flags = parent->field_history[cur_field_idx].flags;
- gint line;
-
- field0 = GST_BUFFER_DATA (parent->field_history[cur_field_idx].buf);
-
- g_assert (dm_class->fields_required <= 4);
-
- if (dm_class->fields_required >= 2)
- field1 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 1].buf);
- if (dm_class->fields_required >= 3)
- field2 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 2].buf);
- if (dm_class->fields_required >= 4)
- field3 = GST_BUFFER_DATA (parent->field_history[cur_field_idx + 3].buf);
-
-
- if (cur_field_flags == PICTURE_INTERLACED_BOTTOM) {
- /* double the first scanline of the bottom field */
- oil_memcpy (out, field0, parent->row_stride);
- out += parent->row_stride;
- }
-
- oil_memcpy (out, field0, parent->row_stride);
- out += parent->row_stride;
-
- for (line = 2; line <= parent->field_height; line++) {
-
- memset (&scanlines, 0, sizeof (scanlines));
- scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
-
- /* interp. scanline */
- scanlines.t0 = field0;
- scanlines.b0 = field0 + parent->field_stride;
-
- if (field1 != NULL) {
- scanlines.tt1 = field1;
- scanlines.m1 = field1 + parent->field_stride;
- scanlines.bb1 = field1 + parent->field_stride * 2;
- field1 += parent->field_stride;
- }
-
- if (field2 != NULL) {
- scanlines.t2 = field2;
- scanlines.b2 = field2 + parent->field_stride;
- }
-
- if (field3 != NULL) {
- scanlines.tt3 = field3;
- scanlines.m3 = field3 + parent->field_stride;
- scanlines.bb3 = field3 + parent->field_stride * 2;
- field3 += parent->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == 2) {
- scanlines.tt1 = scanlines.bb1;
- scanlines.tt3 = scanlines.bb3;
- } else if (line == parent->field_height) {
- scanlines.bb1 = scanlines.tt1;
- scanlines.bb3 = scanlines.tt3;
- }
-
- dsm_class->interpolate_scanline (self, parent, out, &scanlines,
- parent->frame_width);
- out += parent->row_stride;
-
- memset (&scanlines, 0, sizeof (scanlines));
- scanlines.bottom_field = (cur_field_flags == PICTURE_INTERLACED_BOTTOM);
-
- /* copy a scanline */
- scanlines.tt0 = field0;
- scanlines.m0 = field0 + parent->field_stride;
- scanlines.bb0 = field0 + parent->field_stride * 2;
- field0 += parent->field_stride;
-
- if (field1 != NULL) {
- scanlines.t1 = field1;
- scanlines.b1 = field1 + parent->field_stride;
- }
-
- if (field2 != NULL) {
- scanlines.tt2 = field2;
- scanlines.m2 = field2 + parent->field_stride;
- scanlines.bb2 = field2 + parent->field_stride * 2;
- field2 += parent->field_stride;
- }
-
- if (field3 != NULL) {
- scanlines.t3 = field3;
- scanlines.b3 = field3 + parent->field_stride;
- }
-
- /* set valid data for corner cases */
- if (line == parent->field_height) {
- scanlines.bb0 = scanlines.tt0;
- scanlines.b1 = scanlines.t1;
- scanlines.bb2 = scanlines.tt2;
- scanlines.b3 = scanlines.t3;
- }
-
- dsm_class->copy_scanline (self, parent, out, &scanlines,
- parent->frame_width);
- out += parent->row_stride;
- }
-
- if (cur_field_flags == PICTURE_INTERLACED_TOP) {
- /* double the last scanline of the top field */
- oil_memcpy (out, field0, parent->row_stride);
- }
-}
-
-static void
-gst_deinterlace_simple_method_class_init (GstDeinterlaceSimpleMethodClass *
- klass)
-{
- GstDeinterlaceMethodClass *dm_class = (GstDeinterlaceMethodClass *) klass;
-
- dm_class->deinterlace_frame = gst_deinterlace_simple_method_deinterlace_frame;
- dm_class->fields_required = 2;
-
- klass->interpolate_scanline =
- gst_deinterlace_simple_method_interpolate_scanline;
- klass->copy_scanline = gst_deinterlace_simple_method_copy_scanline;
-}
-
-static void
-gst_deinterlace_simple_method_init (GstDeinterlaceSimpleMethod * self)
-{
-}
-
-#define GST_TYPE_DEINTERLACE2_METHODS (gst_deinterlace2_methods_get_type ())
-static GType
-gst_deinterlace2_methods_get_type (void)
-{
- static GType deinterlace2_methods_type = 0;
-
- static const GEnumValue methods_types[] = {
- {GST_DEINTERLACE2_TOMSMOCOMP, "Motion Adaptive: Motion Search",
- "tomsmocomp"},
- {GST_DEINTERLACE2_GREEDY_H, "Motion Adaptive: Advanced Detection",
- "greedyh"},
- {GST_DEINTERLACE2_GREEDY_L, "Motion Adaptive: Simple Detection", "greedyl"},
- {GST_DEINTERLACE2_VFIR, "Blur Vertical", "vfir"},
- {GST_DEINTERLACE2_LINEAR, "Television: Full resolution", "linear"},
- {GST_DEINTERLACE2_LINEAR_BLEND, "Blur: Temporal", "linearblend"},
- {GST_DEINTERLACE2_SCALER_BOB, "Double lines", "scalerbob"},
- {GST_DEINTERLACE2_WEAVE, "Weave", "weave"},
- {GST_DEINTERLACE2_WEAVE_TFF, "Progressive: Top Field First", "weavetff"},
- {GST_DEINTERLACE2_WEAVE_BFF, "Progressive: Bottom Field First", "weavebff"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_methods_type) {
- deinterlace2_methods_type =
- g_enum_register_static ("GstDeinterlace2Methods", methods_types);
- }
- return deinterlace2_methods_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_FIELDS (gst_deinterlace2_fields_get_type ())
-static GType
-gst_deinterlace2_fields_get_type (void)
-{
- static GType deinterlace2_fields_type = 0;
-
- static const GEnumValue fields_types[] = {
- {GST_DEINTERLACE2_ALL, "All fields", "all"},
- {GST_DEINTERLACE2_TF, "Top fields only", "top"},
- {GST_DEINTERLACE2_BF, "Bottom fields only", "bottom"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_fields_type) {
- deinterlace2_fields_type =
- g_enum_register_static ("GstDeinterlace2Fields", fields_types);
- }
- return deinterlace2_fields_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_FIELD_LAYOUT (gst_deinterlace2_field_layout_get_type ())
-static GType
-gst_deinterlace2_field_layout_get_type (void)
-{
- static GType deinterlace2_field_layout_type = 0;
-
- static const GEnumValue field_layout_types[] = {
- {GST_DEINTERLACE2_LAYOUT_AUTO, "Auto detection", "auto"},
- {GST_DEINTERLACE2_LAYOUT_TFF, "Top field first", "tff"},
- {GST_DEINTERLACE2_LAYOUT_BFF, "Bottom field first", "bff"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_field_layout_type) {
- deinterlace2_field_layout_type =
- g_enum_register_static ("GstDeinterlace2FieldLayout",
- field_layout_types);
- }
- return deinterlace2_field_layout_type;
-}
-
-#define GST_TYPE_DEINTERLACE2_MODES (gst_deinterlace2_modes_get_type ())
-static GType
-gst_deinterlace2_modes_get_type (void)
-{
- static GType deinterlace2_modes_type = 0;
-
- static const GEnumValue modes_types[] = {
- {GST_DEINTERLACE2_MODE_AUTO, "Auto detection", "auto"},
- {GST_DEINTERLACE2_MODE_INTERLACED, "Enfore deinterlacing", "interlaced"},
- {0, NULL, NULL},
- };
-
- if (!deinterlace2_modes_type) {
- deinterlace2_modes_type =
- g_enum_register_static ("GstDeinterlace2Modes", modes_types);
- }
- return deinterlace2_modes_type;
-}
-
-static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";"
- GST_VIDEO_CAPS_YUV ("YVYU"))
- );
-
-static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2") ";"
- GST_VIDEO_CAPS_YUV ("YVYU"))
- );
-
-static void gst_deinterlace2_finalize (GObject * self);
-static void gst_deinterlace2_set_property (GObject * self, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_deinterlace2_get_property (GObject * self, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GstCaps *gst_deinterlace2_getcaps (GstPad * pad);
-static gboolean gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_deinterlace2_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn gst_deinterlace2_change_state (GstElement * element,
- GstStateChange transition);
-
-static gboolean gst_deinterlace2_src_event (GstPad * pad, GstEvent * event);
-static gboolean gst_deinterlace2_src_query (GstPad * pad, GstQuery * query);
-static const GstQueryType *gst_deinterlace2_src_query_types (GstPad * pad);
-
-static void gst_deinterlace2_reset (GstDeinterlace2 * self);
-
-static void gst_deinterlace2_child_proxy_interface_init (gpointer g_iface,
- gpointer iface_data);
-
-static void
-_do_init (GType object_type)
-{
- const GInterfaceInfo child_proxy_interface_info = {
- (GInterfaceInitFunc) gst_deinterlace2_child_proxy_interface_init,
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- g_type_add_interface_static (object_type, GST_TYPE_CHILD_PROXY,
- &child_proxy_interface_info);
-}
-
-GST_BOILERPLATE_FULL (GstDeinterlace2, gst_deinterlace2, GstElement,
- GST_TYPE_ELEMENT, _do_init);
-
-static void
-gst_deinterlace2_set_method (GstDeinterlace2 * self,
- GstDeinterlace2Methods method)
-{
-
- if (self->method) {
- gst_child_proxy_child_removed (GST_OBJECT (self),
- GST_OBJECT (self->method));
- gst_object_unparent (GST_OBJECT (self->method));
- self->method = NULL;
- }
-
- switch (method) {
- case GST_DEINTERLACE2_TOMSMOCOMP:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_TOMSMOCOMP, NULL);
- break;
- case GST_DEINTERLACE2_GREEDY_H:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_H, NULL);
- break;
- case GST_DEINTERLACE2_GREEDY_L:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_GREEDY_L, NULL);
- break;
- case GST_DEINTERLACE2_VFIR:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_VFIR, NULL);
- break;
- case GST_DEINTERLACE2_LINEAR:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR, NULL);
- break;
- case GST_DEINTERLACE2_LINEAR_BLEND:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_LINEAR_BLEND, NULL);
- break;
- case GST_DEINTERLACE2_SCALER_BOB:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_SCALER_BOB, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE_TFF:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_TFF, NULL);
- break;
- case GST_DEINTERLACE2_WEAVE_BFF:
- self->method = g_object_new (GST_TYPE_DEINTERLACE_WEAVE_BFF, NULL);
- break;
- default:
- GST_WARNING_OBJECT (self, "Invalid Deinterlacer Method");
- return;
- }
-
- self->method_id = method;
-
- gst_object_set_name (GST_OBJECT (self->method), "method");
- gst_object_set_parent (GST_OBJECT (self->method), GST_OBJECT (self));
- gst_child_proxy_child_added (GST_OBJECT (self), GST_OBJECT (self->method));
-}
-
-static void
-gst_deinterlace2_base_init (gpointer klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_templ));
-
- gst_element_class_set_details_simple (element_class,
- "Deinterlacer",
- "Filter/Video",
- "Deinterlace Methods ported from DScaler/TvTime",
- "Martin Eikermann <meiker@upb.de>, "
- "Sebastian Dröge <slomo@circular-chaos.org>");
-}
-
-static void
-gst_deinterlace2_class_init (GstDeinterlace2Class * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- GstElementClass *element_class = (GstElementClass *) klass;
-
- gobject_class->set_property = gst_deinterlace2_set_property;
- gobject_class->get_property = gst_deinterlace2_get_property;
- gobject_class->finalize = gst_deinterlace2_finalize;
-
- /**
- * GstDeinterlace2:mode
- *
- * This selects whether the deinterlacing methods should
- * always be applied or if they should only be applied
- * on content that has the "interlaced" flag on the caps.
- *
- */
- g_object_class_install_property (gobject_class, PROP_MODE,
- g_param_spec_enum ("mode",
- "Mode",
- "Deinterlace Mode",
- GST_TYPE_DEINTERLACE2_MODES,
- DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:method
- *
- * Selects the different deinterlacing algorithms that can be used.
- * These provide different quality and CPU usage.
- *
- * Some methods provide parameters which can be set by getting
- * the "method" child via the #GstChildProxy interface and
- * setting the appropiate properties on it.
- *
- * <itemizedlist>
- * <listitem>
- * <para>
- * tomsmocomp
- * Motion Adaptive: Motion Search
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * greedyh
- * Motion Adaptive: Advanced Detection
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * greedyl
- * Motion Adaptive: Simple Detection
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * vfir
- * Blur vertical
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * linear
- * Linear interpolation
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * linearblend
- * Linear interpolation in time domain
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * scalerbob
- * Double lines
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weave
- * Weave
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weavetff
- * Progressive: Top Field First
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * weavebff
- * Progressive: Bottom Field First
- * </para>
- * </listitem>
- * </itemizedlist>
- */
- g_object_class_install_property (gobject_class, PROP_METHOD,
- g_param_spec_enum ("method",
- "Method",
- "Deinterlace Method",
- GST_TYPE_DEINTERLACE2_METHODS,
- DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:fields
- *
- * This selects which fields should be output. If "all" is selected
- * the output framerate will be double.
- *
- */
- g_object_class_install_property (gobject_class, PROP_FIELDS,
- g_param_spec_enum ("fields",
- "fields",
- "Fields to use for deinterlacing",
- GST_TYPE_DEINTERLACE2_FIELDS,
- DEFAULT_FIELDS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- /**
- * GstDeinterlace2:layout
- *
- * This selects which fields is the first in time.
- *
- */
- g_object_class_install_property (gobject_class, PROP_FIELD_LAYOUT,
- g_param_spec_enum ("tff",
- "tff",
- "Deinterlace top field first",
- GST_TYPE_DEINTERLACE2_FIELD_LAYOUT,
- DEFAULT_FIELD_LAYOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- element_class->change_state =
- GST_DEBUG_FUNCPTR (gst_deinterlace2_change_state);
-}
-
-static GstObject *
-gst_deinterlace2_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
- guint index)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (child_proxy);
-
- g_return_val_if_fail (index == 0, NULL);
-
- return gst_object_ref (self->method);
-}
-
-static guint
-gst_deinterlace2_child_proxy_get_children_count (GstChildProxy * child_proxy)
-{
- return 1;
-}
-
-static void
-gst_deinterlace2_child_proxy_interface_init (gpointer g_iface,
- gpointer iface_data)
-{
- GstChildProxyInterface *iface = g_iface;
-
- iface->get_child_by_index = gst_deinterlace2_child_proxy_get_child_by_index;
- iface->get_children_count = gst_deinterlace2_child_proxy_get_children_count;
-}
-
-static void
-gst_deinterlace2_init (GstDeinterlace2 * self, GstDeinterlace2Class * klass)
-{
- self->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
- gst_pad_set_chain_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_chain));
- gst_pad_set_event_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_sink_event));
- gst_pad_set_setcaps_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
- gst_pad_set_getcaps_function (self->sinkpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps));
- gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
-
- self->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
- gst_pad_set_event_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_event));
- gst_pad_set_query_type_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query_types));
- gst_pad_set_query_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_src_query));
- gst_pad_set_setcaps_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_setcaps));
- gst_pad_set_getcaps_function (self->srcpad,
- GST_DEBUG_FUNCPTR (gst_deinterlace2_getcaps));
- gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
-
- gst_element_no_more_pads (GST_ELEMENT (self));
-
- self->mode = DEFAULT_MODE;
- gst_deinterlace2_set_method (self, DEFAULT_METHOD);
- self->fields = DEFAULT_FIELDS;
- self->field_layout = DEFAULT_FIELD_LAYOUT;
-
- gst_deinterlace2_reset (self);
-}
-
-static void
-gst_deinterlace2_reset_history (GstDeinterlace2 * self)
-{
- gint i;
-
- for (i = 0; i < self->history_count; i++) {
- if (self->field_history[i].buf) {
- gst_buffer_unref (self->field_history[i].buf);
- self->field_history[i].buf = NULL;
- }
- }
- memset (self->field_history, 0, MAX_FIELD_HISTORY * sizeof (GstPicture));
- self->history_count = 0;
-}
-
-static void
-gst_deinterlace2_reset (GstDeinterlace2 * self)
-{
- self->row_stride = 0;
- self->frame_width = 0;
- self->frame_height = 0;
- self->frame_rate_n = 0;
- self->frame_rate_d = 0;
- self->field_height = 0;
- self->field_stride = 0;
-
- gst_deinterlace2_reset_history (self);
-}
-
-static void
-gst_deinterlace2_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlace2 *self;
-
- g_return_if_fail (GST_IS_DEINTERLACE2 (object));
- self = GST_DEINTERLACE2 (object);
-
- switch (prop_id) {
- case PROP_MODE:
- if (GST_STATE (self) >= GST_STATE_PAUSED) {
- g_warning ("Setting the 'mode' property is only allowed in "
- "states other than PAUSED and PLAYING");
- } else {
- self->mode = g_value_get_enum (value);
- }
- break;
- case PROP_METHOD:
- gst_deinterlace2_set_method (self, g_value_get_enum (value));
- break;
- case PROP_FIELDS:{
- gint oldfields;
-
- GST_OBJECT_LOCK (self);
- oldfields = self->fields;
- self->fields = g_value_get_enum (value);
- if (self->fields != oldfields && GST_PAD_CAPS (self->srcpad))
- gst_deinterlace2_setcaps (self->sinkpad, GST_PAD_CAPS (self->sinkpad));
- GST_OBJECT_UNLOCK (self);
- break;
- }
- case PROP_FIELD_LAYOUT:
- self->field_layout = g_value_get_enum (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
- }
-
-}
-
-static void
-gst_deinterlace2_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstDeinterlace2 *self;
-
- g_return_if_fail (GST_IS_DEINTERLACE2 (object));
- self = GST_DEINTERLACE2 (object);
-
- switch (prop_id) {
- case PROP_MODE:
- g_value_set_enum (value, self->mode);
- break;
- case PROP_METHOD:
- g_value_set_enum (value, self->method_id);
- break;
- case PROP_FIELDS:
- g_value_set_enum (value, self->fields);
- break;
- case PROP_FIELD_LAYOUT:
- g_value_set_enum (value, self->field_layout);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace2_finalize (GObject * object)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (object);
-
- gst_deinterlace2_reset (self);
-
- if (self->method) {
- gst_object_unparent (GST_OBJECT (self->method));
- self->method = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static GstBuffer *
-gst_deinterlace2_pop_history (GstDeinterlace2 * self)
-{
- GstBuffer *buffer = NULL;
-
- g_assert (self->history_count > 0);
-
- buffer = self->field_history[self->history_count - 1].buf;
-
- self->history_count--;
- GST_DEBUG_OBJECT (self, "pop, size(history): %d", self->history_count);
-
- return buffer;
-}
-
-#if 0
-static GstBuffer *
-gst_deinterlace2_head_history (GstDeinterlace2 * self)
-{
- return self->field_history[self->history_count - 1].buf;
-}
-#endif
-
-
-/* invariant: field with smallest timestamp is self->field_history[self->history_count-1]
-
-*/
-
-static void
-gst_deinterlace2_push_history (GstDeinterlace2 * self, GstBuffer * buffer)
-{
- int i = 1;
- GstClockTime timestamp;
- GstDeinterlace2FieldLayout field_layout = self->field_layout;
- gboolean repeated = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_RFF);
- gboolean tff = GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_TFF);
- gboolean onefield =
- GST_BUFFER_FLAG_IS_SET (buffer, GST_VIDEO_BUFFER_ONEFIELD);
- GstBuffer *field1, *field2;
- guint fields_to_push = (onefield) ? 1 : (!repeated) ? 2 : 3;
- gint field1_flags, field2_flags;
-
- g_assert (self->history_count < MAX_FIELD_HISTORY - fields_to_push);
-
- for (i = MAX_FIELD_HISTORY - 1; i >= fields_to_push; i--) {
- self->field_history[i].buf = self->field_history[i - fields_to_push].buf;
- self->field_history[i].flags =
- self->field_history[i - fields_to_push].flags;
- }
-
- if (field_layout == GST_DEINTERLACE2_LAYOUT_AUTO) {
- if (!self->interlaced) {
- GST_WARNING_OBJECT (self, "Can't detect field layout -- assuming TFF");
- field_layout = GST_DEINTERLACE2_LAYOUT_TFF;
- } else if (tff) {
- field_layout = GST_DEINTERLACE2_LAYOUT_TFF;
- } else {
- field_layout = GST_DEINTERLACE2_LAYOUT_BFF;
- }
- }
-
- if (field_layout == GST_DEINTERLACE2_LAYOUT_TFF) {
- GST_DEBUG_OBJECT (self, "Top field first");
- field1 = gst_buffer_ref (buffer);
- field1_flags = PICTURE_INTERLACED_TOP;
- field2 = gst_buffer_create_sub (buffer, self->row_stride,
- GST_BUFFER_SIZE (buffer) - self->row_stride);
- field2_flags = PICTURE_INTERLACED_BOTTOM;
- } else {
- GST_DEBUG_OBJECT (self, "Bottom field first");
- field1 = gst_buffer_create_sub (buffer, self->row_stride,
- GST_BUFFER_SIZE (buffer) - self->row_stride);
- field1_flags = PICTURE_INTERLACED_BOTTOM;
- field2 = gst_buffer_ref (buffer);
- field2_flags = PICTURE_INTERLACED_TOP;
- }
-
- /* Timestamps are assigned to the field buffers under the assumption that
- the timestamp of the buffer equals the first fields timestamp */
-
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- GST_BUFFER_TIMESTAMP (field1) = timestamp;
- GST_BUFFER_TIMESTAMP (field2) = timestamp + self->field_duration;
- if (repeated)
- GST_BUFFER_TIMESTAMP (field2) += self->field_duration;
-
- if (repeated) {
- self->field_history[0].buf = field2;
- self->field_history[0].flags = field2_flags;
- self->field_history[1].buf = gst_buffer_ref (field1);
- GST_BUFFER_TIMESTAMP (self->field_history[1].buf) += self->field_duration;
- self->field_history[1].flags = field1_flags;
- self->field_history[2].buf = field1;
- self->field_history[2].flags = field1_flags;
- } else if (!onefield) {
- self->field_history[0].buf = field2;
- self->field_history[0].flags = field2_flags;
- self->field_history[1].buf = field1;
- self->field_history[1].flags = field1_flags;
- } else { /* onefield */
- self->field_history[0].buf = field1;
- self->field_history[0].flags = field1_flags;
- gst_buffer_unref (field2);
- }
-
- self->history_count += fields_to_push;
- GST_DEBUG_OBJECT (self, "push, size(history): %d", self->history_count);
-
- gst_buffer_unref (buffer);
-}
-
-static GstFlowReturn
-gst_deinterlace2_chain (GstPad * pad, GstBuffer * buf)
-{
- GstDeinterlace2 *self = NULL;
- GstClockTime timestamp;
- GstFlowReturn ret = GST_FLOW_OK;
- gint fields_required = 0;
- gint cur_field_idx = 0;
- GstBuffer *outbuf;
-
- self = GST_DEINTERLACE2 (GST_PAD_PARENT (pad));
-
- if (!self->interlaced && self->mode != GST_DEINTERLACE2_MODE_INTERLACED)
- return gst_pad_push (self->srcpad, buf);
-
- if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
- GST_DEBUG_OBJECT (self, "DISCONT buffer, resetting history");
- gst_deinterlace2_reset_history (self);
- }
-
- gst_deinterlace2_push_history (self, buf);
- buf = NULL;
-
- fields_required = gst_deinterlace_method_get_fields_required (self->method);
-
- /* Not enough fields in the history */
- if (self->history_count < fields_required + 1) {
- /* TODO: do bob or just forward frame */
- GST_DEBUG_OBJECT (self, "HistoryCount=%d", self->history_count);
- return GST_FLOW_OK;
- }
-
- while (self->history_count >= fields_required) {
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_DEBUG_OBJECT (self, "All fields");
- if (self->fields == GST_DEINTERLACE2_TF)
- GST_DEBUG_OBJECT (self, "Top fields");
- if (self->fields == GST_DEINTERLACE2_BF)
- GST_DEBUG_OBJECT (self, "Bottom fields");
-
- cur_field_idx = self->history_count - fields_required;
-
- if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_TOP
- && self->fields == GST_DEINTERLACE2_TF) ||
- self->fields == GST_DEINTERLACE2_ALL) {
- GST_DEBUG_OBJECT (self, "deinterlacing top field");
-
- /* create new buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
- GST_BUFFER_OFFSET_NONE, self->frame_size,
- GST_PAD_CAPS (self->srcpad), &outbuf);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* do magic calculus */
- gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf);
-
- g_assert (self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method) >= 0);
- buf =
- self->field_history[self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method)].buf;
- timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
-
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_BUFFER_DURATION (outbuf) = self->field_duration;
- else
- GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
-
- ret = gst_pad_push (self->srcpad, outbuf);
- outbuf = NULL;
- if (ret != GST_FLOW_OK)
- return ret;
- }
- /* no calculation done: remove excess field */
- else if (self->field_history[cur_field_idx].flags ==
- PICTURE_INTERLACED_TOP && self->fields == GST_DEINTERLACE2_BF) {
- GST_DEBUG_OBJECT (self, "Removing unused top field");
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
- }
-
- cur_field_idx = self->history_count - fields_required;
- if (self->history_count < fields_required)
- break;
-
- /* deinterlace bottom_field */
- if ((self->field_history[cur_field_idx].flags == PICTURE_INTERLACED_BOTTOM
- && self->fields == GST_DEINTERLACE2_BF) ||
- self->fields == GST_DEINTERLACE2_ALL) {
- GST_DEBUG_OBJECT (self, "deinterlacing bottom field");
-
- /* create new buffer */
- ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
- GST_BUFFER_OFFSET_NONE, self->frame_size,
- GST_PAD_CAPS (self->srcpad), &outbuf);
- if (ret != GST_FLOW_OK)
- return ret;
-
- /* do magic calculus */
- gst_deinterlace_method_deinterlace_frame (self->method, self, outbuf);
-
- g_assert (self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method) >= 0);
- buf =
- self->field_history[self->history_count - 1 -
- gst_deinterlace_method_get_latency (self->method)].buf;
- timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
-
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- if (self->fields == GST_DEINTERLACE2_ALL)
- GST_BUFFER_DURATION (outbuf) = self->field_duration;
- else
- GST_BUFFER_DURATION (outbuf) = 2 * self->field_duration;
-
- ret = gst_pad_push (self->srcpad, outbuf);
- outbuf = NULL;
-
- if (ret != GST_FLOW_OK)
- return ret;
- }
- /* no calculation done: remove excess field */
- else if (self->field_history[cur_field_idx].flags ==
- PICTURE_INTERLACED_BOTTOM && self->fields == GST_DEINTERLACE2_TF) {
- GST_DEBUG_OBJECT (self, "Removing unused bottom field");
- gst_buffer_unref (gst_deinterlace2_pop_history (self));
- }
- }
-
- GST_DEBUG_OBJECT (self, "----chain end ----\n\n");
-
- return ret;
-}
-
-static gint
-gst_greatest_common_divisor (gint a, gint b)
-{
- while (b != 0) {
- int temp = a;
-
- a = b;
- b = temp % b;
- }
-
- return ABS (a);
-}
-
-static gboolean
-gst_fraction_double (gint * n_out, gint * d_out, gboolean half)
-{
- gint n, d, gcd;
-
- n = *n_out;
- d = *d_out;
-
- if (d == 0)
- return FALSE;
-
- if (n == 0 || (n == G_MAXINT && d == 1))
- return TRUE;
-
- gcd = gst_greatest_common_divisor (n, d);
- n /= gcd;
- d /= gcd;
-
- if (!half) {
- if (G_MAXINT / 2 >= ABS (n)) {
- n *= 2;
- } else if (d >= 2) {
- d /= 2;
- } else {
- return FALSE;
- }
- } else {
- if (G_MAXINT / 2 >= ABS (d)) {
- d *= 2;
- } else if (n >= 2) {
- n /= 2;
- } else {
- return FALSE;
- }
- }
-
- *n_out = n;
- *d_out = d;
-
- return TRUE;
-}
-
-static GstCaps *
-gst_deinterlace2_getcaps (GstPad * pad)
-{
- GstCaps *ret;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- GstPad *otherpad;
- gint len;
- const GstCaps *ourcaps;
- GstCaps *peercaps;
-
- GST_OBJECT_LOCK (self);
-
- otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
-
- ourcaps = gst_pad_get_pad_template_caps (pad);
- peercaps = gst_pad_peer_get_caps (otherpad);
-
- if (peercaps) {
- ret = gst_caps_intersect (ourcaps, peercaps);
- gst_caps_unref (peercaps);
- } else {
- ret = gst_caps_copy (ourcaps);
- }
-
- GST_OBJECT_UNLOCK (self);
-
- if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) &&
- self->fields == GST_DEINTERLACE2_ALL) {
- for (len = gst_caps_get_size (ret); len > 0; len--) {
- GstStructure *s = gst_caps_get_structure (ret, len - 1);
- const GValue *val;
-
- val = gst_structure_get_value (s, "framerate");
- if (!val)
- continue;
-
- if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION) {
- gint n, d;
-
- n = gst_value_get_fraction_numerator (val);
- d = gst_value_get_fraction_denominator (val);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- goto error;
- }
-
- gst_structure_set (s, "framerate", GST_TYPE_FRACTION, n, d, NULL);
- } else if (G_VALUE_TYPE (val) == GST_TYPE_FRACTION_RANGE) {
- const GValue *min, *max;
- GValue nrange = { 0, }, nmin = {
- 0,}, nmax = {
- 0,};
- gint n, d;
-
- g_value_init (&nrange, GST_TYPE_FRACTION_RANGE);
- g_value_init (&nmin, GST_TYPE_FRACTION);
- g_value_init (&nmax, GST_TYPE_FRACTION);
-
- min = gst_value_get_fraction_range_min (val);
- max = gst_value_get_fraction_range_max (val);
-
- n = gst_value_get_fraction_numerator (min);
- d = gst_value_get_fraction_denominator (min);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- g_value_unset (&nrange);
- g_value_unset (&nmax);
- g_value_unset (&nmin);
- goto error;
- }
-
- gst_value_set_fraction (&nmin, n, d);
-
- n = gst_value_get_fraction_numerator (max);
- d = gst_value_get_fraction_denominator (max);
-
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- g_value_unset (&nrange);
- g_value_unset (&nmax);
- g_value_unset (&nmin);
- goto error;
- }
-
- gst_value_set_fraction (&nmax, n, d);
- gst_value_set_fraction_range (&nrange, &nmin, &nmax);
-
- gst_structure_set_value (s, "framerate", &nrange);
-
- g_value_unset (&nmin);
- g_value_unset (&nmax);
- g_value_unset (&nrange);
- } else if (G_VALUE_TYPE (val) == GST_TYPE_LIST) {
- const GValue *lval;
- GValue nlist = { 0, };
- GValue nval = { 0, };
- gint i;
-
- g_value_init (&nlist, GST_TYPE_LIST);
- for (i = gst_value_list_get_size (val); i > 0; i--) {
- gint n, d;
-
- lval = gst_value_list_get_value (val, i);
-
- if (G_VALUE_TYPE (lval) != GST_TYPE_FRACTION)
- continue;
-
- n = gst_value_get_fraction_numerator (lval);
- d = gst_value_get_fraction_denominator (lval);
-
- /* Double/Half the framerate but if this fails simply
- * skip this value from the list */
- if (!gst_fraction_double (&n, &d, pad != self->srcpad)) {
- continue;
- }
-
- g_value_init (&nval, GST_TYPE_FRACTION);
-
- gst_value_set_fraction (&nval, n, d);
- gst_value_list_append_value (&nlist, &nval);
- g_value_unset (&nval);
- }
- gst_structure_set_value (s, "framerate", &nlist);
- g_value_unset (&nlist);
- }
- }
- }
-
- GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret);
-
- return ret;
-
-error:
- GST_ERROR_OBJECT (pad, "Unable to transform peer caps");
- gst_caps_unref (ret);
- return NULL;
-}
-
-static gboolean
-gst_deinterlace2_setcaps (GstPad * pad, GstCaps * caps)
-{
- gboolean res = TRUE;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- GstPad *otherpad;
- GstStructure *structure;
- GstVideoFormat fmt;
- guint32 fourcc;
- GstCaps *othercaps;
-
- otherpad = (pad == self->srcpad) ? self->sinkpad : self->srcpad;
-
- structure = gst_caps_get_structure (caps, 0);
-
- res = gst_structure_get_int (structure, "width", &self->frame_width);
- res &= gst_structure_get_int (structure, "height", &self->frame_height);
- res &=
- gst_structure_get_fraction (structure, "framerate", &self->frame_rate_n,
- &self->frame_rate_d);
- res &= gst_structure_get_fourcc (structure, "format", &fourcc);
- res &= gst_video_format_parse_caps_interlaced (caps, &self->interlaced);
- if (!res)
- goto invalid_caps;
-
- if ((self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) &&
- self->fields == GST_DEINTERLACE2_ALL) {
- gint fps_n = self->frame_rate_n, fps_d = self->frame_rate_d;
-
- if (!gst_fraction_double (&fps_n, &fps_d, otherpad != self->srcpad))
- goto invalid_caps;
-
- othercaps = gst_caps_copy (caps);
-
- gst_caps_set_simple (othercaps, "framerate", GST_TYPE_FRACTION, fps_n,
- fps_d, NULL);
- } else {
- othercaps = gst_caps_ref (caps);
- }
-
- if (!gst_pad_set_caps (otherpad, othercaps))
- goto caps_not_accepted;
- gst_caps_unref (othercaps);
-
- self->field_height = self->frame_height / 2;
-
- fmt = gst_video_format_from_fourcc (fourcc);
-
- /* TODO: only true if fields are subbuffers of interlaced frames,
- change when the buffer-fields concept has landed */
- self->field_stride =
- gst_video_format_get_row_stride (fmt, 0, self->frame_width) * 2;
-
- /* in bytes */
- self->row_stride =
- gst_video_format_get_row_stride (fmt, 0, self->frame_width);
- self->frame_size =
- gst_video_format_get_size (fmt, self->frame_width, self->frame_height);
-
- if (self->fields == GST_DEINTERLACE2_ALL && otherpad == self->srcpad)
- self->field_duration =
- gst_util_uint64_scale (GST_SECOND, self->frame_rate_d,
- self->frame_rate_n);
- else
- self->field_duration =
- gst_util_uint64_scale (GST_SECOND, self->frame_rate_d,
- 2 * self->frame_rate_n);
-
- GST_DEBUG_OBJECT (self, "Set caps: %" GST_PTR_FORMAT, caps);
-
-done:
-
- gst_object_unref (self);
- return res;
-
-invalid_caps:
- res = FALSE;
- GST_ERROR_OBJECT (pad, "Invalid caps: %" GST_PTR_FORMAT, caps);
- goto done;
-
-caps_not_accepted:
- res = FALSE;
- GST_ERROR_OBJECT (pad, "Caps not accepted: %" GST_PTR_FORMAT, othercaps);
- gst_caps_unref (othercaps);
- goto done;
-}
-
-static gboolean
-gst_deinterlace2_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_STOP:
- case GST_EVENT_EOS:
- case GST_EVENT_NEWSEGMENT:
- gst_deinterlace2_reset_history (self);
-
- /* fall through */
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (self);
- return res;
-}
-
-static GstStateChangeReturn
-gst_deinterlace2_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret;
- GstDeinterlace2 *self = GST_DEINTERLACE2 (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_deinterlace2_reset (self);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- default:
- break;
- }
-
- return ret;
-}
-
-static gboolean
-gst_deinterlace2_src_event (GstPad * pad, GstEvent * event)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- gboolean res;
-
- GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (self);
-
- return res;
-}
-
-static gboolean
-gst_deinterlace2_src_query (GstPad * pad, GstQuery * query)
-{
- GstDeinterlace2 *self = GST_DEINTERLACE2 (gst_pad_get_parent (pad));
- gboolean res = FALSE;
-
- GST_LOG_OBJECT (self, "%s query", GST_QUERY_TYPE_NAME (query));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_LATENCY:
- if (self->interlaced || self->mode == GST_DEINTERLACE2_MODE_INTERLACED) {
- GstClockTime min, max;
- gboolean live;
- GstPad *peer;
-
- if ((peer = gst_pad_get_peer (self->sinkpad))) {
- if ((res = gst_pad_query (peer, query))) {
- GstClockTime latency;
- gint fields_required = 0;
- gint method_latency = 0;
-
- if (self->method) {
- fields_required =
- gst_deinterlace_method_get_fields_required (self->method);
- method_latency =
- gst_deinterlace_method_get_latency (self->method);
- }
-
- gst_query_parse_latency (query, &live, &min, &max);
-
- GST_DEBUG_OBJECT (self, "Peer latency: min %"
- GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (min), GST_TIME_ARGS (max));
-
- /* add our own latency */
- latency = (fields_required + method_latency) * self->field_duration;
-
- GST_DEBUG_OBJECT (self, "Our latency: min %" GST_TIME_FORMAT
- ", max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (latency), GST_TIME_ARGS (latency));
-
- min += latency;
- if (max != GST_CLOCK_TIME_NONE)
- max += latency;
- else
- max = latency;
-
- GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
- GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (min), GST_TIME_ARGS (max));
-
- gst_query_set_latency (query, live, min, max);
- }
- gst_object_unref (peer);
- } else {
- res = gst_pad_query_default (pad, query);
- }
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
- gst_object_unref (self);
- return res;
-}
-
-static const GstQueryType *
-gst_deinterlace2_src_query_types (GstPad * pad)
-{
- static const GstQueryType types[] = {
- GST_QUERY_LATENCY,
- GST_QUERY_NONE
- };
- return types;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (deinterlace2_debug, "deinterlace2", 0,
- "Deinterlacer");
-
- oil_init ();
-
- if (!gst_element_register (plugin, "deinterlace2", GST_RANK_NONE,
- GST_TYPE_DEINTERLACE2)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "deinterlace2",
- "Deinterlacer", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
- GST_PACKAGE_ORIGIN);
diff --git a/gst/deinterlace2/gstdeinterlace2.h b/gst/deinterlace2/gstdeinterlace2.h
deleted file mode 100644
index de63f54e..00000000
--- a/gst/deinterlace2/gstdeinterlace2.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * GStreamer
- * Copyright (C) 2005 Martin Eikermann <meiker@upb.de>
- * Copyright (C) 2008-2009 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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_DEINTERLACE_2_H__
-#define __GST_DEINTERLACE_2_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstbasetransform.h>
-#include <liboil/liboil.h>
-#include <liboil/liboilcpu.h>
-#include <liboil/liboilfunction.h>
-
-#ifdef HAVE_GCC_ASM
-#if defined(HAVE_CPU_I386) || defined(HAVE_CPU_X86_64)
-#define BUILD_X86_ASM
-#endif
-#endif
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_DEINTERLACE2 \
- (gst_deinterlace2_get_type())
-#define GST_DEINTERLACE2(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLACE2,GstDeinterlace2))
-#define GST_DEINTERLACE2_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLACE2,GstDeinterlace2))
-#define GST_IS_DEINTERLACE2(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE2))
-#define GST_IS_DEINTERLACE2_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE2))
-
-typedef struct _GstDeinterlace2 GstDeinterlace2;
-typedef struct _GstDeinterlace2Class GstDeinterlace2Class;
-
-#define GST_TYPE_DEINTERLACE_METHOD (gst_deinterlace_method_get_type ())
-#define GST_IS_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD))
-#define GST_IS_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD))
-#define GST_DEINTERLACE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
-#define GST_DEINTERLACE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethod))
-#define GST_DEINTERLACE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD, GstDeinterlaceMethodClass))
-#define GST_DEINTERLACE_METHOD_CAST(obj) ((GstDeinterlaceMethod*)(obj))
-
-typedef struct _GstDeinterlaceMethod GstDeinterlaceMethod;
-typedef struct _GstDeinterlaceMethodClass GstDeinterlaceMethodClass;
-
-/*
- * This structure defines the deinterlacer plugin.
- */
-
-struct _GstDeinterlaceMethod {
- GstObject parent;
-};
-
-struct _GstDeinterlaceMethodClass {
- GstObjectClass parent_class;
- guint fields_required;
- guint latency;
-
- void (*deinterlace_frame) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, GstBuffer *outbuf);
-
- const gchar *name;
- const gchar *nick;
-};
-
-GType gst_deinterlace_method_get_type (void);
-
-#define GST_TYPE_DEINTERLACE_SIMPLE_METHOD (gst_deinterlace_simple_method_get_type ())
-#define GST_IS_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
-#define GST_IS_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD))
-#define GST_DEINTERLACE_SIMPLE_METHOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
-#define GST_DEINTERLACE_SIMPLE_METHOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethod))
-#define GST_DEINTERLACE_SIMPLE_METHOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_SIMPLE_METHOD, GstDeinterlaceSimpleMethodClass))
-#define GST_DEINTERLACE_SIMPLE_METHOD_CAST(obj) ((GstDeinterlaceSimpleMethod*)(obj))
-
-typedef struct _GstDeinterlaceSimpleMethod GstDeinterlaceSimpleMethod;
-typedef struct _GstDeinterlaceSimpleMethodClass GstDeinterlaceSimpleMethodClass;
-typedef struct _GstDeinterlaceScanlineData GstDeinterlaceScanlineData;
-
-/*
- * This structure defines the simple deinterlacer plugin.
- */
-
-struct _GstDeinterlaceScanlineData {
- guint8 *tt0, *t0, *m0, *b0, *bb0;
- guint8 *tt1, *t1, *m1, *b1, *bb1;
- guint8 *tt2, *t2, *m2, *b2, *bb2;
- guint8 *tt3, *t3, *m3, *b3, *bb3;
- gboolean bottom_field;
-};
-
-/**
- * For interpolate_scanline the input is:
- *
- * | t-3 t-2 t-1 t
- * | Field 3 | Field 2 | Field 1 | Field 0 |
- * | TT3 | | TT1 | |
- * | | T2 | | T0 |
- * | M3 | | M1 | |
- * | | B2 | | B0 |
- * | BB3 | | BB1 | |
- *
- * For copy_scanline the input is:
- *
- * | t-3 t-2 t-1 t
- * | Field 3 | Field 2 | Field 1 | Field 0 |
- * | | TT2 | | TT0 |
- * | T3 | | T1 | |
- * | | M2 | | M0 |
- * | B3 | | B1 | |
- * | | BB2 | | BB0 |
- *
- * All other values are NULL.
- */
-
-struct _GstDeinterlaceSimpleMethod {
- GstDeinterlaceMethod parent;
-};
-
-struct _GstDeinterlaceSimpleMethodClass {
- GstDeinterlaceMethodClass parent_class;
-
- void (*interpolate_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width);
- void (*copy_scanline) (GstDeinterlaceMethod *self, GstDeinterlace2 * parent, guint8 *out, GstDeinterlaceScanlineData *scanlines, gint width);
-};
-
-GType gst_deinterlace_simple_method_get_type (void);
-
-
-#define MAX_FIELD_HISTORY 10
-
-#define PICTURE_PROGRESSIVE 0
-#define PICTURE_INTERLACED_BOTTOM 1
-#define PICTURE_INTERLACED_TOP 2
-#define PICTURE_INTERLACED_MASK (PICTURE_INTERLACED_BOTTOM | PICTURE_INTERLACED_TOP)
-
-typedef struct
-{
- /* pointer to the start of data for this field */
- GstBuffer *buf;
- /* see PICTURE_ flags */
- guint flags;
-} GstPicture;
-
-typedef enum
-{
- GST_DEINTERLACE2_TOMSMOCOMP,
- GST_DEINTERLACE2_GREEDY_H,
- GST_DEINTERLACE2_GREEDY_L,
- GST_DEINTERLACE2_VFIR,
- GST_DEINTERLACE2_LINEAR,
- GST_DEINTERLACE2_LINEAR_BLEND,
- GST_DEINTERLACE2_SCALER_BOB,
- GST_DEINTERLACE2_WEAVE,
- GST_DEINTERLACE2_WEAVE_TFF,
- GST_DEINTERLACE2_WEAVE_BFF
-} GstDeinterlace2Methods;
-
-typedef enum
-{
- GST_DEINTERLACE2_ALL, /* All (missing data is interp.) */
- GST_DEINTERLACE2_TF, /* Top Fields Only */
- GST_DEINTERLACE2_BF /* Bottom Fields Only */
-} GstDeinterlace2Fields;
-
-typedef enum
-{
- GST_DEINTERLACE2_LAYOUT_AUTO,
- GST_DEINTERLACE2_LAYOUT_TFF,
- GST_DEINTERLACE2_LAYOUT_BFF
-} GstDeinterlace2FieldLayout;
-
-typedef enum {
- GST_DEINTERLACE2_MODE_AUTO,
- GST_DEINTERLACE2_MODE_INTERLACED
-} GstDeinterlace2Mode;
-
-struct _GstDeinterlace2
-{
- GstElement parent;
-
- GstPad *srcpad, *sinkpad;
-
- /* <private> */
-
- GstDeinterlace2Mode mode;
-
- GstDeinterlace2FieldLayout field_layout;
-
- guint frame_size;
- gint frame_rate_n, frame_rate_d;
- gboolean interlaced;
-
- /* Duration of one field */
- GstClockTime field_duration;
-
- GstDeinterlace2Fields fields;
-
- GstDeinterlace2Methods method_id;
- GstDeinterlaceMethod *method;
-
- /* The most recent pictures
- PictureHistory[0] is always the most recent.
- Pointers are NULL if the picture in question isn't valid, e.g. because
- the program just started or a picture was skipped.
- */
- GstPicture field_history[MAX_FIELD_HISTORY];
- guint history_count;
-
- /* Number of bytes of actual data in each scanline. May be less than
- OverlayPitch since the overlay's scanlines might have alignment
- requirements. Generally equal to FrameWidth * 2.
- */
- guint row_stride;
-
- /* Number of pixels in each scanline. */
- gint frame_width;
-
- /* Number of scanlines per frame. */
- gint frame_height;
-
- /* Number of scanlines per field. FrameHeight / 2, mostly for
- cleanliness so we don't have to keep dividing FrameHeight by 2.
- */
- gint field_height;
-
- /* distance between lines in image
- need not match the pixel width
- */
- guint field_stride;
-};
-
-struct _GstDeinterlace2Class
-{
- GstElementClass parent_class;
-};
-
-GType gst_deinterlace2_get_type (void);
-
-G_END_DECLS
-#endif /* __GST_DEINTERLACE_2_H__ */
diff --git a/gst/deinterlace2/tvtime/greedy.c b/gst/deinterlace2/tvtime/greedy.c
deleted file mode 100644
index 7d4e4b3a..00000000
--- a/gst/deinterlace2/tvtime/greedy.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (c) 2000 Tom Barry All rights reserved.
- * mmx.h port copyright (c) 2002 Billy Biggs <vektor@dumbterm.net>.
- *
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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.
- */
-
-/*
- * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry
- * and Billy Biggs.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "_stdint.h"
-
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_GREEDY_L(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L))
-#define GST_IS_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L))
-#define GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass))
-#define GST_DEINTERLACE_METHOD_GREEDY_L(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyL))
-#define GST_DEINTERLACE_METHOD_GREEDY_L_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_L, GstDeinterlaceMethodGreedyLClass))
-#define GST_DEINTERLACE_METHOD_GREEDY_L_CAST(obj) ((GstDeinterlaceMethodGreedyL*)(obj))
-
-GType gst_deinterlace_method_greedy_l_get_type (void);
-
-typedef struct
-{
- GstDeinterlaceMethod parent;
-
- guint max_comb;
-} GstDeinterlaceMethodGreedyL;
-
-typedef struct
-{
- GstDeinterlaceMethodClass parent_class;
- void (*scanline) (GstDeinterlaceMethodGreedyL * self, uint8_t * L2,
- uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size);
-} GstDeinterlaceMethodGreedyLClass;
-
-// This is a simple lightweight DeInterlace method that uses little CPU time
-// but gives very good results for low or intermedite motion.
-// It defers frames by one field, but that does not seem to produce noticeable
-// lip sync problems.
-//
-// The method used is to take either the older or newer weave pixel depending
-// upon which give the smaller comb factor, and then clip to avoid large damage
-// when wrong.
-//
-// I'd intended this to be part of a larger more elaborate method added to
-// Blended Clip but this give too good results for the CPU to ignore here.
-
-static inline void
-deinterlace_greedy_packed422_scanline_c (GstDeinterlaceMethodGreedyL * self,
- uint8_t * m0, uint8_t * t1,
- uint8_t * b1, uint8_t * m2, uint8_t * output, int width)
-{
- int avg, l2_diff, lp2_diff, max, min, best;
- guint max_comb = self->max_comb;
-
- // L2 == m0
- // L1 == t1
- // L3 == b1
- // LP2 == m2
-
- while (width--) {
- avg = (*t1 + *b1) / 2;
-
- l2_diff = ABS (*m0 - avg);
- lp2_diff = ABS (*m2 - avg);
-
- if (l2_diff > lp2_diff)
- best = *m2;
- else
- best = *m0;
-
- max = MAX (*t1, *b1);
- min = MIN (*t1, *b1);
-
- if (max < 256 - max_comb)
- max += max_comb;
- else
- max = 255;
-
- if (min > max_comb)
- min -= max_comb;
- else
- min = 0;
-
- *output = CLAMP (best, min, max);
-
- // Advance to the next set of pixels.
- output += 1;
- m0 += 1;
- t1 += 1;
- b1 += 1;
- m2 += 1;
- }
-}
-
-#ifdef BUILD_X86_ASM
-#include "mmx.h"
-static void
-deinterlace_greedy_packed422_scanline_mmx (GstDeinterlaceMethodGreedyL * self,
- uint8_t * m0, uint8_t * t1,
- uint8_t * b1, uint8_t * m2, uint8_t * output, int width)
-{
- mmx_t MaxComb;
- mmx_t ShiftMask;
-
- // How badly do we let it weave? 0-255
- MaxComb.ub[0] = self->max_comb;
- MaxComb.ub[1] = self->max_comb;
- MaxComb.ub[2] = self->max_comb;
- MaxComb.ub[3] = self->max_comb;
- MaxComb.ub[4] = self->max_comb;
- MaxComb.ub[5] = self->max_comb;
- MaxComb.ub[6] = self->max_comb;
- MaxComb.ub[7] = self->max_comb;
-
- ShiftMask.ub[0] = 0x7f;
- ShiftMask.ub[1] = 0x7f;
- ShiftMask.ub[2] = 0x7f;
- ShiftMask.ub[3] = 0x7f;
- ShiftMask.ub[4] = 0x7f;
- ShiftMask.ub[5] = 0x7f;
- ShiftMask.ub[6] = 0x7f;
- ShiftMask.ub[7] = 0x7f;
-
- // L2 == m0
- // L1 == t1
- // L3 == b1
- // LP2 == m2
-
- movq_m2r (MaxComb, mm6);
-
- for (; width > 7; width -= 8) {
- movq_m2r (*t1, mm1); // L1
- movq_m2r (*m0, mm2); // L2
- movq_m2r (*b1, mm3); // L3
- movq_m2r (*m2, mm0); // LP2
-
- // average L1 and L3 leave result in mm4
- movq_r2r (mm1, mm4); // L1
- movq_r2r (mm3, mm5); // L3
- psrlw_i2r (1, mm4); // L1/2
- pand_m2r (ShiftMask, mm4);
- psrlw_i2r (1, mm5); // L3/2
- pand_m2r (ShiftMask, mm5);
- paddusb_r2r (mm5, mm4); // (L1 + L3) / 2
-
- // get abs value of possible L2 comb
- movq_r2r (mm2, mm7); // L2
- psubusb_r2r (mm4, mm7); // L2 - avg
- movq_r2r (mm4, mm5); // avg
- psubusb_r2r (mm2, mm5); // avg - L2
- por_r2r (mm7, mm5); // abs(avg-L2)
-
- // get abs value of possible LP2 comb
- movq_r2r (mm0, mm7); // LP2
- psubusb_r2r (mm4, mm7); // LP2 - avg
- psubusb_r2r (mm0, mm4); // avg - LP2
- por_r2r (mm7, mm4); // abs(avg-LP2)
-
- // use L2 or LP2 depending upon which makes smaller comb
- psubusb_r2r (mm5, mm4); // see if it goes to zero
- psubusb_r2r (mm5, mm5); // 0
- pcmpeqb_r2r (mm5, mm4); // if (mm4=0) then FF else 0
- pcmpeqb_r2r (mm4, mm5); // opposite of mm4
-
- // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
- pand_r2r (mm2, mm5); // use L2 if mm5 == ff, else 0
- pand_r2r (mm0, mm4); // use LP2 if mm4 = ff, else 0
- por_r2r (mm5, mm4); // may the best win
-
- // Now lets clip our chosen value to be not outside of the range
- // of the high/low range L1-L3 by more than abs(L1-L3)
- // This allows some comb but limits the damages and also allows more
- // detail than a boring oversmoothed clip.
-
- movq_r2r (mm1, mm2); // copy L1
- psubusb_r2r (mm3, mm2); // - L3, with saturation
- paddusb_r2r (mm3, mm2); // now = Max(L1,L3)
-
- pcmpeqb_r2r (mm7, mm7); // all ffffffff
- psubusb_r2r (mm1, mm7); // - L1
- paddusb_r2r (mm7, mm3); // add, may sat at fff..
- psubusb_r2r (mm7, mm3); // now = Min(L1,L3)
-
- // allow the value to be above the high or below the low by amt of MaxComb
- paddusb_r2r (mm6, mm2); // increase max by diff
- psubusb_r2r (mm6, mm3); // lower min by diff
-
- psubusb_r2r (mm3, mm4); // best - Min
- paddusb_r2r (mm3, mm4); // now = Max(best,Min(L1,L3)
-
- pcmpeqb_r2r (mm7, mm7); // all ffffffff
- psubusb_r2r (mm4, mm7); // - Max(best,Min(best,L3)
- paddusb_r2r (mm7, mm2); // add may sat at FFF..
- psubusb_r2r (mm7, mm2); // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
-
- movq_r2m (mm2, *output); // move in our clipped best
-
- // Advance to the next set of pixels.
- output += 8;
- m0 += 8;
- t1 += 8;
- b1 += 8;
- m2 += 8;
- }
- emms ();
- if (width > 0)
- deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output,
- width);
-}
-
-#include "sse.h"
-
-static void
-deinterlace_greedy_packed422_scanline_mmxext (GstDeinterlaceMethodGreedyL *
- self, uint8_t * m0, uint8_t * t1, uint8_t * b1, uint8_t * m2,
- uint8_t * output, int width)
-{
- mmx_t MaxComb;
-
- // How badly do we let it weave? 0-255
- MaxComb.ub[0] = self->max_comb;
- MaxComb.ub[1] = self->max_comb;
- MaxComb.ub[2] = self->max_comb;
- MaxComb.ub[3] = self->max_comb;
- MaxComb.ub[4] = self->max_comb;
- MaxComb.ub[5] = self->max_comb;
- MaxComb.ub[6] = self->max_comb;
- MaxComb.ub[7] = self->max_comb;
-
- // L2 == m0
- // L1 == t1
- // L3 == b1
- // LP2 == m2
-
- movq_m2r (MaxComb, mm6);
-
- for (; width > 7; width -= 8) {
- movq_m2r (*t1, mm1); // L1
- movq_m2r (*m0, mm2); // L2
- movq_m2r (*b1, mm3); // L3
- movq_m2r (*m2, mm0); // LP2
-
- // average L1 and L3 leave result in mm4
- movq_r2r (mm1, mm4); // L1
- pavgb_r2r (mm3, mm4); // (L1 + L3)/2
-
- // get abs value of possible L2 comb
- movq_r2r (mm2, mm7); // L2
- psubusb_r2r (mm4, mm7); // L2 - avg
- movq_r2r (mm4, mm5); // avg
- psubusb_r2r (mm2, mm5); // avg - L2
- por_r2r (mm7, mm5); // abs(avg-L2)
-
- // get abs value of possible LP2 comb
- movq_r2r (mm0, mm7); // LP2
- psubusb_r2r (mm4, mm7); // LP2 - avg
- psubusb_r2r (mm0, mm4); // avg - LP2
- por_r2r (mm7, mm4); // abs(avg-LP2)
-
- // use L2 or LP2 depending upon which makes smaller comb
- psubusb_r2r (mm5, mm4); // see if it goes to zero
- pxor_r2r (mm5, mm5); // 0
- pcmpeqb_r2r (mm5, mm4); // if (mm4=0) then FF else 0
- pcmpeqb_r2r (mm4, mm5); // opposite of mm4
-
- // if Comb(LP2) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
- pand_r2r (mm2, mm5); // use L2 if mm5 == ff, else 0
- pand_r2r (mm0, mm4); // use LP2 if mm4 = ff, else 0
- por_r2r (mm5, mm4); // may the best win
-
- // Now lets clip our chosen value to be not outside of the range
- // of the high/low range L1-L3 by more than abs(L1-L3)
- // This allows some comb but limits the damages and also allows more
- // detail than a boring oversmoothed clip.
-
- movq_r2r (mm1, mm2); // copy L1
- pmaxub_r2r (mm3, mm2); // now = Max(L1,L3)
-
- pminub_r2r (mm1, mm3); // now = Min(L1,L3)
-
- // allow the value to be above the high or below the low by amt of MaxComb
- paddusb_r2r (mm6, mm2); // increase max by diff
- psubusb_r2r (mm6, mm3); // lower min by diff
-
-
- pmaxub_r2r (mm3, mm4); // now = Max(best,Min(L1,L3)
- pminub_r2r (mm4, mm2); // now = Min( Max(best, Min(L1,L3)), L2 )=L2 clipped
-
- movq_r2m (mm2, *output); // move in our clipped best
-
- // Advance to the next set of pixels.
- output += 8;
- m0 += 8;
- t1 += 8;
- b1 += 8;
- m2 += 8;
- }
- emms ();
-
- if (width > 0)
- deinterlace_greedy_packed422_scanline_c (self, m0, t1, b1, m2, output,
- width);
-}
-
-#endif
-
-static void
-deinterlace_frame_di_greedy (GstDeinterlaceMethod * d_method,
- GstDeinterlace2 * object, GstBuffer * outbuf)
-{
- GstDeinterlaceMethodGreedyL *self =
- GST_DEINTERLACE_METHOD_GREEDY_L (d_method);
- GstDeinterlaceMethodGreedyLClass *klass =
- GST_DEINTERLACE_METHOD_GREEDY_L_GET_CLASS (self);
- int InfoIsOdd = 0;
- int Line;
- unsigned int Pitch = object->field_stride;
- unsigned char *L1; // ptr to Line1, of 3
- unsigned char *L2; // ptr to Line2, the weave line
- unsigned char *L3; // ptr to Line3
-
- unsigned char *L2P; // ptr to prev Line2
- unsigned char *Dest = GST_BUFFER_DATA (outbuf);
-
- // copy first even line no matter what, and the first odd line if we're
- // processing an EVEN field. (note diff from other deint rtns.)
-
- if (object->field_history[object->history_count - 1].flags ==
- PICTURE_INTERLACED_BOTTOM) {
- InfoIsOdd = 1;
-
- L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
- L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf);
- L3 = L1 + Pitch;
- L2P =
- GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf);
-
- // copy first even line
- oil_memcpy (Dest, L1, object->row_stride);
- Dest += object->row_stride;
- } else {
- InfoIsOdd = 0;
- L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
- L2 = GST_BUFFER_DATA (object->field_history[object->history_count -
- 1].buf) + Pitch;
- L3 = L1 + Pitch;
- L2P =
- GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) +
- Pitch;
-
- // copy first even line
- oil_memcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf),
- object->row_stride);
- Dest += object->row_stride;
- // then first odd line
- oil_memcpy (Dest, L1, object->row_stride);
- Dest += object->row_stride;
- }
-
- for (Line = 0; Line < (object->field_height - 1); ++Line) {
- klass->scanline (self, L2, L1, L3, L2P, Dest, object->row_stride);
- Dest += object->row_stride;
- oil_memcpy (Dest, L3, object->row_stride);
- Dest += object->row_stride;
-
- L1 += Pitch;
- L2 += Pitch;
- L3 += Pitch;
- L2P += Pitch;
- }
-
- if (InfoIsOdd) {
- oil_memcpy (Dest, L2, object->row_stride);
- }
-}
-
-
-G_DEFINE_TYPE (GstDeinterlaceMethodGreedyL, gst_deinterlace_method_greedy_l,
- GST_TYPE_DEINTERLACE_METHOD);
-
-enum
-{
- ARG_0,
- ARG_MAX_COMB
-};
-
-static void
-gst_deinterlace_method_greedy_l_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
-
- switch (prop_id) {
- case ARG_MAX_COMB:
- self->max_comb = g_value_get_uint (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace_method_greedy_l_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodGreedyL *self = GST_DEINTERLACE_METHOD_GREEDY_L (object);
-
- switch (prop_id) {
- case ARG_MAX_COMB:
- g_value_set_uint (value, self->max_comb);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace_method_greedy_l_class_init (GstDeinterlaceMethodGreedyLClass *
- klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GObjectClass *gobject_class = (GObjectClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- gobject_class->set_property = gst_deinterlace_method_greedy_l_set_property;
- gobject_class->get_property = gst_deinterlace_method_greedy_l_get_property;
-
- g_object_class_install_property (gobject_class, ARG_MAX_COMB,
- g_param_spec_uint ("max-comb",
- "Max comb",
- "Max Comb", 0, 255, 15, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- dim_class->fields_required = 4;
- dim_class->deinterlace_frame = deinterlace_frame_di_greedy;
- dim_class->name = "Motion Adaptive: Simple Detection";
- dim_class->nick = "greedyl";
- dim_class->latency = 1;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
- klass->scanline = deinterlace_greedy_packed422_scanline_mmxext;
- } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
- klass->scanline = deinterlace_greedy_packed422_scanline_mmx;
- } else {
- klass->scanline = deinterlace_greedy_packed422_scanline_c;
- }
-#else
- klass->scanline = deinterlace_greedy_packed422_scanline_c;
-#endif
-}
-
-static void
-gst_deinterlace_method_greedy_l_init (GstDeinterlaceMethodGreedyL * self)
-{
- self->max_comb = 15;
-}
diff --git a/gst/deinterlace2/tvtime/greedyh.asm b/gst/deinterlace2/tvtime/greedyh.asm
deleted file mode 100644
index 86e97c58..00000000
--- a/gst/deinterlace2/tvtime/greedyh.asm
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (c) 2001 Tom Barry. All rights reserved.
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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.
- */
-
-
-/*
- * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-
-#include "x86-64_macros.inc"
-
-void
-FUNCT_NAME (GstDeinterlaceMethodGreedyH *self, uint8_t * L1, uint8_t * L2, uint8_t * L3, uint8_t * L2P,
- uint8_t * Dest, int size)
-{
-
- // in tight loop some vars are accessed faster in local storage
- int64_t YMask = 0x00ff00ff00ff00ffull; // to keep only luma
- int64_t UVMask = 0xff00ff00ff00ff00ull; // to keep only chroma
- int64_t ShiftMask = 0xfefefefefefefefeull; // to avoid shifting chroma to luma
- int64_t QW256 = 0x0100010001000100ull; // 4 256's
- int64_t MaxComb;
- int64_t MotionThreshold;
- int64_t MotionSense;
- int64_t i;
- long LoopCtr;
- long oldbx;
-
- int64_t QW256B;
- int64_t LastAvg = 0; //interp value from left qword
-
- // FIXME: Use C implementation if the width is not a multiple of 4
- // Do something more optimal later
- if (size % 8 != 0)
- greedyDScaler_C (self, L1, L2, L3, L2P, Dest, size);
-
- // Set up our two parms that are actually evaluated for each pixel
- i = self->max_comb;
- MaxComb =
- i << 56 | i << 48 | i << 40 | i << 32 | i << 24 | i << 16 | i << 8 | i;
-
- i = self->motion_threshold; // scale to range of 0-257
- MotionThreshold = i << 48 | i << 32 | i << 16 | i | UVMask;
-
- i = self->motion_sense; // scale to range of 0-257
- MotionSense = i << 48 | i << 32 | i << 16 | i;
-
- i = 0xffffffff - 256;
- QW256B = i << 48 | i << 32 | i << 16 | i; // save a couple instr on PMINSW instruct.
-
- LoopCtr = size / 8 - 1; // there are LineLength / 8 qwords per line but do 1 less, adj at end of loop
-
- // For ease of reading, the comments below assume that we're operating on an odd
- // field (i.e., that InfoIsOdd is true). Assume the obvious for even lines..
- __asm__ __volatile__ (
- // save ebx (-fPIC)
- MOVX " %%" XBX ", %[oldbx]\n\t"
- MOVX " %[L1], %%" XAX "\n\t"
- LEAX " 8(%%" XAX "), %%" XBX "\n\t" // next qword needed by DJR
- MOVX " %[L3], %%" XCX "\n\t"
- SUBX " %%" XAX ", %%" XCX "\n\t" // carry L3 addr as an offset
- MOVX " %[L2P], %%" XDX "\n\t"
- MOVX " %[L2], %%" XSI "\n\t"
- MOVX " %[Dest], %%" XDI "\n\t" // DL1 if Odd or DL2 if Even
-
- ".align 8\n\t"
- "1:\n\t"
- "movq (%%" XSI "), %%mm0\n\t" // L2 - the newest weave pixel value
- "movq (%%" XAX "), %%mm1\n\t" // L1 - the top pixel
- "movq (%%" XDX "), %%mm2\n\t" // L2P - the prev weave pixel
- "movq (%%" XAX ", %%" XCX "), %%mm3\n\t" // L3, next odd row
- "movq %%mm1, %%mm6\n\t" // L1 - get simple single pixel interp
-
- // pavgb mm6, mm3 // use macro below
- V_PAVGB ("%%mm6", "%%mm3", "%%mm4", "%[ShiftMask]")
-
- // DJR - Diagonal Jaggie Reduction
- // In the event that we are going to use an average (Bob) pixel we do not want a jagged
- // stair step effect. To combat this we avg in the 2 horizontally adjacen pixels into the
- // interpolated Bob mix. This will do horizontal smoothing for only the Bob'd pixels.
-
- "movq %[LastAvg], %%mm4\n\t" // the bob value from prev qword in row
- "movq %%mm6, %[LastAvg]\n\t" // save for next pass
- "psrlq $48, %%mm4\n\t" // right justify 1 pixel
- "movq %%mm6, %%mm7\n\t" // copy of simple bob pixel
- "psllq $16, %%mm7\n\t" // left justify 3 pixels
- "por %%mm7, %%mm4\n\t" // and combine
- "movq (%%" XBX "), %%mm5\n\t" // next horiz qword from L1
- // pavgb mm5, qword ptr[ebx+ecx] // next horiz qword from L3, use macro below
-
- V_PAVGB ("%%mm5", "(%%" XBX ",%%" XCX ")", "%%mm7", "%[ShiftMask]")
- "psllq $48, %%mm5\n\t" // left just 1 pixel
- "movq %%mm6, %%mm7\n\t" // another copy of simple bob pixel
- "psrlq $16, %%mm7\n\t" // right just 3 pixels
- "por %%mm7, %%mm5\n\t" // combine
- // pavgb mm4, mm5 // avg of forward and prev by 1 pixel, use macro
- V_PAVGB ("%%mm4", "%%mm5", "%%mm5", "%[ShiftMask]") // mm5 gets modified if MMX
- // pavgb mm6, mm4 // avg of center and surround interp vals, use macro
- V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
-
- // Don't do any more averaging than needed for mmx. It hurts performance and causes rounding errors.
-#ifndef IS_MMX
- // pavgb mm4, mm6 // 1/4 center, 3/4 adjacent
- V_PAVGB ("%%mm4", "%%mm6", "%%mm7", "%[ShiftMask]")
- // pavgb mm6, mm4 // 3/8 center, 5/8 adjacent
- V_PAVGB ("%%mm6", "%%mm4", "%%mm7", "%[ShiftMask]")
-#endif
-
- // get abs value of possible L2 comb
- "movq %%mm6, %%mm4\n\t" // work copy of interp val
- "movq %%mm2, %%mm7\n\t" // L2
- "psubusb %%mm4, %%mm7\n\t" // L2 - avg
- "movq %%mm4, %%mm5\n\t" // avg
- "psubusb %%mm2, %%mm5\n\t" // avg - L2
- "por %%mm7, %%mm5\n\t" // abs(avg-L2)
-
- // get abs value of possible L2P comb
- "movq %%mm0, %%mm7\n\t" // L2P
- "psubusb %%mm4, %%mm7\n\t" // L2P - avg
- "psubusb %%mm0, %%mm4\n\t" // avg - L2P
- "por %%mm7, %%mm4\n\t" // abs(avg-L2P)
-
- // use L2 or L2P depending upon which makes smaller comb
- "psubusb %%mm5, %%mm4\n\t" // see if it goes to zero
- "psubusb %%mm5, %%mm5\n\t" // 0
- "pcmpeqb %%mm5, %%mm4\n\t" // if (mm4=0) then FF else 0
- "pcmpeqb %%mm4, %%mm5\n\t" // opposite of mm4
-
- // if Comb(L2P) <= Comb(L2) then mm4=ff, mm5=0 else mm4=0, mm5 = 55
- "pand %%mm2, %%mm5\n\t" // use L2 if mm5 == ff, else 0
- "pand %%mm0, %%mm4\n\t" // use L2P if mm4 = ff, else 0
- "por %%mm5, %%mm4\n\t" // may the best win
-
- // Inventory: at this point we have the following values:
- // mm0 = L2P (or L2)
- // mm1 = L1
- // mm2 = L2 (or L2P)
- // mm3 = L3
- // mm4 = the best of L2,L2P weave pixel, base upon comb
- // mm6 = the avg interpolated value, if we need to use it
- // Let's measure movement, as how much the weave pixel has changed
-
- "movq %%mm2, %%mm7\n\t"
- "psubusb %%mm0, %%mm2\n\t"
- "psubusb %%mm7, %%mm0\n\t"
- "por %%mm2, %%mm0\n\t" // abs value of change, used later
-
- // Now lets clip our chosen value to be not outside of the range
- // of the high/low range L1-L3 by more than MaxComb.
- // This allows some comb but limits the damages and also allows more
- // detail than a boring oversmoothed clip.
-
- "movq %%mm1, %%mm2\n\t" // copy L1
- // pmaxub mm2, mm3 // use macro
- V_PMAXUB ("%%mm2", "%%mm3") // now = Max(L1,L3)
- "movq %%mm1, %%mm5\n\t" // copy L1
- // pminub mm5, mm3 // now = Min(L1,L3), use macro
- V_PMINUB ("%%mm5", "%%mm3", "%%mm7")
-
- // allow the value to be above the high or below the low by amt of MaxComb
- "psubusb %[MaxComb], %%mm5\n\t" // lower min by diff
- "paddusb %[MaxComb], %%mm2\n\t" // increase max by diff
- // pmaxub mm4, mm5 // now = Max(best,Min(L1,L3) use macro
- V_PMAXUB ("%%mm4", "%%mm5")
- // pminub mm4, mm2 // now = Min( Max(best, Min(L1,L3), L2 )=L2 clipped
- V_PMINUB ("%%mm4", "%%mm2", "%%mm7")
-
- // Blend weave pixel with bob pixel, depending on motion val in mm0
- "psubusb %[MotionThreshold], %%mm0\n\t" // test Threshold, clear chroma change >>>??
- "pmullw %[MotionSense], %%mm0\n\t" // mul by user factor, keep low 16 bits
- "movq %[QW256], %%mm7\n\t"
-#ifdef IS_MMXEXT
- "pminsw %%mm7, %%mm0\n\t" // max = 256
-#else
- "paddusw %[QW256B], %%mm0\n\t" // add, may sat at fff..
- "psubusw %[QW256B], %%mm0\n\t" // now = Min(L1,256)
-#endif
- "psubusw %%mm0, %%mm7\n\t" // so the 2 sum to 256, weighted avg
- "movq %%mm4, %%mm2\n\t" // save weave chroma info before trashing
- "pand %[YMask], %%mm4\n\t" // keep only luma from calc'd value
- "pmullw %%mm7, %%mm4\n\t" // use more weave for less motion
- "pand %[YMask], %%mm6\n\t" // keep only luma from calc'd value
- "pmullw %%mm0, %%mm6\n\t" // use more bob for large motion
- "paddusw %%mm6, %%mm4\n\t" // combine
- "psrlw $8, %%mm4\n\t" // div by 256 to get weighted avg
- // chroma comes from weave pixel
- "pand %[UVMask], %%mm2\n\t" // keep chroma
- "por %%mm4, %%mm2\n\t" // and combine
- V_MOVNTQ ("(%%" XDI ")", "%%mm2") // move in our clipped best, use macro
- // bump ptrs and loop
- LEAX " 8(%%" XAX "), %%" XAX "\n\t"
- LEAX " 8(%%" XBX "), %%" XBX "\n\t"
- LEAX " 8(%%" XDX "), %%" XDX "\n\t"
- LEAX " 8(%%" XDI "), %%" XDI "\n\t"
- LEAX " 8(%%" XSI "), %%" XSI "\n\t"
- DECX " %[LoopCtr]\n\t"
-
- "jg 1b\n\t" // loop if not to last line
- // note P-III default assumes backward branches taken
- "jl 1f\n\t" // done
- MOVX " %%" XAX ", %%" XBX "\n\t" // sharpness lookahead 1 byte only, be wrong on 1
- "jmp 1b\n\t"
-
- "1:\n\t"
- MOVX " %[oldbx], %%" XBX "\n\t"
- "emms\n\t": /* no outputs */
-
- :[LastAvg] "m" (LastAvg),
- [L1] "m" (L1),
- [L3] "m" (L3),
- [L2P] "m" (L2P),
- [L2] "m" (L2),
- [Dest] "m" (Dest),
- [ShiftMask] "m" (ShiftMask),
- [MaxComb] "m" (MaxComb),
- [MotionThreshold] "m" (MotionThreshold),
- [MotionSense] "m" (MotionSense),
- [QW256B] "m" (QW256B),
- [YMask] "m" (YMask),
- [UVMask] "m" (UVMask),
- [LoopCtr] "m" (LoopCtr),
- [QW256] "m" (QW256),
- [oldbx] "m" (oldbx)
- : XAX, XCX, XDX, XSI, XDI,
- "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
-#ifdef __MMX__
- "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
-#endif
- "memory", "cc");
-}
diff --git a/gst/deinterlace2/tvtime/greedyh.c b/gst/deinterlace2/tvtime/greedyh.c
deleted file mode 100644
index a5aafd18..00000000
--- a/gst/deinterlace2/tvtime/greedyh.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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.
- */
-
-/*
- * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "greedyhmacros.h"
-
-#include <stdlib.h>
-#include "_stdint.h"
-#include <string.h>
-
-#include "gst/gst.h"
-#include "plugins.h"
-#include "gstdeinterlace2.h"
-
-#define GST_TYPE_DEINTERLACE_METHOD_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
-#define GST_IS_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H))
-#define GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
-#define GST_DEINTERLACE_METHOD_GREEDY_H(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyH))
-#define GST_DEINTERLACE_METHOD_GREEDY_H_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_GREEDY_H, GstDeinterlaceMethodGreedyHClass))
-#define GST_DEINTERLACE_METHOD_GREEDY_H_CAST(obj) ((GstDeinterlaceMethodGreedyH*)(obj))
-
-GType gst_deinterlace_method_greedy_h_get_type (void);
-
-typedef struct
-{
- GstDeinterlaceMethod parent;
-
- guint max_comb, motion_threshold, motion_sense;
-} GstDeinterlaceMethodGreedyH;
-
-typedef struct
-{
- GstDeinterlaceMethodClass parent_class;
- void (*scanline) (GstDeinterlaceMethodGreedyH * self, uint8_t * L2,
- uint8_t * L1, uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size);
-} GstDeinterlaceMethodGreedyHClass;
-
-void
-greedyDScaler_C (GstDeinterlaceMethodGreedyH * self, uint8_t * L1, uint8_t * L2,
- uint8_t * L3, uint8_t * L2P, uint8_t * Dest, int size)
-{
- int Pos;
- uint8_t l1_l, l1_1_l, l3_l, l3_1_l;
- uint8_t l1_c, l1_1_c, l3_c, l3_1_c;
- uint8_t avg_l, avg_c, avg_l_1, avg_c_1;
- uint8_t avg_l__1 = 0, avg_c__1 = 0;
- uint8_t avg_s_l, avg_s_c;
- uint8_t avg_sc_l, avg_sc_c;
- uint8_t best_l, best_c;
- uint16_t mov_l;
- uint8_t out_l, out_c;
- uint8_t l2_l, l2_c, lp2_l, lp2_c;
- uint8_t l2_l_diff, l2_c_diff, lp2_l_diff, lp2_c_diff;
- uint8_t min_l, min_c, max_l, max_c;
- guint max_comb = self->max_comb;
- guint motion_sense = self->motion_sense;
- guint motion_threshold = self->motion_threshold;
-
- for (Pos = 0; Pos < size; Pos += 2) {
- l1_l = L1[0];
- l1_c = L1[1];
- l3_l = L3[0];
- l3_c = L3[1];
-
- if (Pos == size - 1) {
- l1_1_l = l1_l;
- l1_1_c = l1_c;
- l3_1_l = l3_l;
- l3_1_c = l3_c;
- } else {
- l1_1_l = L1[2];
- l1_1_c = L1[3];
- l3_1_l = L3[2];
- l3_1_c = L3[3];
- }
-
- /* Average of L1 and L3 */
- avg_l = (l1_l + l3_l) / 2;
- avg_c = (l1_c + l3_c) / 2;
-
- if (Pos == 0) {
- avg_l__1 = avg_l;
- avg_c__1 = avg_c;
- }
-
- /* Average of next L1 and next L3 */
- avg_l_1 = (l1_1_l + l3_1_l) / 2;
- avg_c_1 = (l1_1_c + l3_1_c) / 2;
-
- /* Calculate average of one pixel forward and previous */
- avg_s_l = (avg_l__1 + avg_l_1) / 2;
- avg_s_c = (avg_c__1 + avg_c_1) / 2;
-
- /* Calculate average of center and surrounding pixels */
- avg_sc_l = (avg_l + avg_s_l) / 2;
- avg_sc_c = (avg_c + avg_s_c) / 2;
-
- /* move forward */
- avg_l__1 = avg_l;
- avg_c__1 = avg_c;
-
- /* Get best L2/L2P, i.e. least diff from above average */
- l2_l = L2[0];
- l2_c = L2[1];
- lp2_l = L2P[0];
- lp2_c = L2P[1];
-
- l2_l_diff = ABS (l2_l - avg_sc_l);
- l2_c_diff = ABS (l2_c - avg_sc_c);
-
- lp2_l_diff = ABS (lp2_l - avg_sc_l);
- lp2_c_diff = ABS (lp2_c - avg_sc_c);
-
- if (l2_l_diff > lp2_l_diff)
- best_l = lp2_l;
- else
- best_l = l2_l;
-
- if (l2_c_diff > lp2_c_diff)
- best_c = lp2_c;
- else
- best_c = l2_c;
-
- /* Clip this best L2/L2P by L1/L3 and allow to differ by GreedyMaxComb */
- max_l = MAX (l1_l, l3_l);
- min_l = MIN (l1_l, l3_l);
-
- if (max_l < 256 - max_comb)
- max_l += max_comb;
- else
- max_l = 255;
-
- if (min_l > max_comb)
- min_l -= max_comb;
- else
- min_l = 0;
-
- max_c = MAX (l1_c, l3_c);
- min_c = MIN (l1_c, l3_c);
-
- if (max_c < 256 - max_comb)
- max_c += max_comb;
- else
- max_c = 255;
-
- if (min_c > max_comb)
- min_c -= max_comb;
- else
- min_c = 0;
-
- out_l = CLAMP (best_l, min_l, max_l);
- out_c = CLAMP (best_c, min_c, max_c);
-
- /* Do motion compensation for luma, i.e. how much
- * the weave pixel differs */
- mov_l = ABS (l2_l - lp2_l);
- if (mov_l > motion_threshold)
- mov_l -= motion_threshold;
- else
- mov_l = 0;
-
- mov_l = mov_l * motion_sense;
- if (mov_l > 256)
- mov_l = 256;
-
- /* Weighted sum on clipped weave pixel and average */
- out_l = (out_l * (256 - mov_l) + avg_sc_l * mov_l) / 256;
-
- Dest[0] = out_l;
- Dest[1] = out_c;
-
- Dest += 2;
- L1 += 2;
- L2 += 2;
- L3 += 2;
- L2P += 2;
- }
-}
-
-#ifdef BUILD_X86_ASM
-
-#define IS_MMXEXT
-#define SIMD_TYPE MMXEXT
-#define FUNCT_NAME greedyDScaler_MMXEXT
-#include "greedyh.asm"
-#undef SIMD_TYPE
-#undef IS_MMXEXT
-#undef FUNCT_NAME
-
-#define IS_3DNOW
-#define SIMD_TYPE 3DNOW
-#define FUNCT_NAME greedyDScaler_3DNOW
-#include "greedyh.asm"
-#undef SIMD_TYPE
-#undef IS_3DNOW
-#undef FUNCT_NAME
-
-#define IS_MMX
-#define SIMD_TYPE MMX
-#define FUNCT_NAME greedyDScaler_MMX
-#include "greedyh.asm"
-#undef SIMD_TYPE
-#undef IS_MMX
-#undef FUNCT_NAME
-
-#endif
-
-static void
-deinterlace_frame_di_greedyh (GstDeinterlaceMethod * d_method,
- GstDeinterlace2 * object, GstBuffer * outbuf)
-{
- GstDeinterlaceMethodGreedyH *self =
- GST_DEINTERLACE_METHOD_GREEDY_H (d_method);
- GstDeinterlaceMethodGreedyHClass *klass =
- GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self);
- int InfoIsOdd = 0;
- int Line;
- unsigned int Pitch = object->field_stride;
-
- unsigned char *L1; // ptr to Line1, of 3
- unsigned char *L2; // ptr to Line2, the weave line
- unsigned char *L3; // ptr to Line3
-
- unsigned char *L2P; // ptr to prev Line2
- unsigned char *Dest = GST_BUFFER_DATA (outbuf);
-
- // copy first even line no matter what, and the first odd line if we're
- // processing an EVEN field. (note diff from other deint rtns.)
-
- if (object->field_history[object->history_count - 1].flags ==
- PICTURE_INTERLACED_BOTTOM) {
- InfoIsOdd = 1;
-
- L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
- L2 = GST_BUFFER_DATA (object->field_history[object->history_count - 1].buf);
- L3 = L1 + Pitch;
- L2P =
- GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf);
-
- // copy first even line
- oil_memcpy (Dest, L1, object->row_stride);
- Dest += object->row_stride;
- } else {
- InfoIsOdd = 0;
- L1 = GST_BUFFER_DATA (object->field_history[object->history_count - 2].buf);
- L2 = GST_BUFFER_DATA (object->field_history[object->history_count -
- 1].buf) + Pitch;
- L3 = L1 + Pitch;
- L2P =
- GST_BUFFER_DATA (object->field_history[object->history_count - 3].buf) +
- Pitch;
-
- // copy first even line
- oil_memcpy (Dest, GST_BUFFER_DATA (object->field_history[0].buf),
- object->row_stride);
- Dest += object->row_stride;
- // then first odd line
- oil_memcpy (Dest, L1, object->row_stride);
- Dest += object->row_stride;
- }
-
- for (Line = 0; Line < (object->field_height - 1); ++Line) {
- klass->scanline (self, L1, L2, L3, L2P, Dest, object->row_stride);
- Dest += object->row_stride;
- oil_memcpy (Dest, L3, object->row_stride);
- Dest += object->row_stride;
-
- L1 += Pitch;
- L2 += Pitch;
- L3 += Pitch;
- L2P += Pitch;
- }
-
- if (InfoIsOdd) {
- oil_memcpy (Dest, L2, object->row_stride);
- }
-}
-
-G_DEFINE_TYPE (GstDeinterlaceMethodGreedyH, gst_deinterlace_method_greedy_h,
- GST_TYPE_DEINTERLACE_METHOD);
-
-enum
-{
- ARG_0,
- ARG_MAX_COMB,
- ARG_MOTION_THRESHOLD,
- ARG_MOTION_SENSE
-};
-
-static void
-gst_deinterlace_method_greedy_h_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
-
- switch (prop_id) {
- case ARG_MAX_COMB:
- self->max_comb = g_value_get_uint (value);
- break;
- case ARG_MOTION_THRESHOLD:
- self->motion_threshold = g_value_get_uint (value);
- break;
- case ARG_MOTION_SENSE:
- self->motion_sense = g_value_get_uint (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace_method_greedy_h_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (object);
-
- switch (prop_id) {
- case ARG_MAX_COMB:
- g_value_set_uint (value, self->max_comb);
- break;
- case ARG_MOTION_THRESHOLD:
- g_value_set_uint (value, self->motion_threshold);
- break;
- case ARG_MOTION_SENSE:
- g_value_set_uint (value, self->motion_sense);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace_method_greedy_h_class_init (GstDeinterlaceMethodGreedyHClass *
- klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GObjectClass *gobject_class = (GObjectClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- gobject_class->set_property = gst_deinterlace_method_greedy_h_set_property;
- gobject_class->get_property = gst_deinterlace_method_greedy_h_get_property;
-
- g_object_class_install_property (gobject_class, ARG_MAX_COMB,
- g_param_spec_uint ("max-comb",
- "Max comb",
- "Max Comb", 0, 255, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- g_object_class_install_property (gobject_class, ARG_MOTION_THRESHOLD,
- g_param_spec_uint ("motion-threshold",
- "Motion Threshold",
- "Motion Threshold",
- 0, 255, 25, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- g_object_class_install_property (gobject_class, ARG_MOTION_SENSE,
- g_param_spec_uint ("motion-sense",
- "Motion Sense",
- "Motion Sense",
- 0, 255, 30, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- dim_class->fields_required = 4;
- dim_class->deinterlace_frame = deinterlace_frame_di_greedyh;
- dim_class->name = "Motion Adaptive: Advanced Detection";
- dim_class->nick = "greedyh";
- dim_class->latency = 1;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
- klass->scanline = greedyDScaler_MMXEXT;
- } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) {
- klass->scanline = greedyDScaler_3DNOW;
- } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
- klass->scanline = greedyDScaler_MMX;
- } else {
- klass->scanline = greedyDScaler_C;
- }
-#else
- klass->scanline = greedyDScaler_C;
-#endif
-}
-
-static void
-gst_deinterlace_method_greedy_h_init (GstDeinterlaceMethodGreedyH * self)
-{
- self->max_comb = 5;
- self->motion_threshold = 25;
- self->motion_sense = 30;
-}
diff --git a/gst/deinterlace2/tvtime/greedyhmacros.h b/gst/deinterlace2/tvtime/greedyhmacros.h
deleted file mode 100644
index 0386c28e..00000000
--- a/gst/deinterlace2/tvtime/greedyhmacros.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-// Copyright (c) 2001 Tom Barry. All rights reserved.
-/////////////////////////////////////////////////////////////////////////////
-//
-// This file is subject to the terms of the GNU General Public License as
-// published by the Free Software Foundation. A copy of this license is
-// included with this software distribution in the file COPYING. If you
-// do not have a copy, you may obtain a copy by writing to the Free
-// Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-// This software 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 General Public License for more details
-//
-/////////////////////////////////////////////////////////////////////////////
-
-// Define a few macros for CPU dependent instructions.
-// I suspect I don't really understand how the C macro preprocessor works but
-// this seems to get the job done. // TRB 7/01
-
-// BEFORE USING THESE YOU MUST SET:
-
-// #define SIMD_TYPE MMXEXT (or MMX or 3DNOW)
-
-// some macros for pavgb instruction
-// V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it
-
-#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \
- "movq "mmr2", "mmrw"\n\t" \
- "pand "smask", "mmrw"\n\t" \
- "psrlw $1, "mmrw"\n\t" \
- "pand "smask", "mmr1"\n\t" \
- "psrlw $1, "mmr1"\n\t" \
- "paddusb "mmrw", "mmr1"\n\t"
-#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask) "pavgb "mmr2", "mmr1"\n\t"
-#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask) "pavgusb "mmr2", "mmr1"\n\t"
-#define V_PAVGB(mmr1, mmr2, mmrw, smask) V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE)
-#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type)
-#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask)
-
-// some macros for pmaxub instruction
-#define V_PMAXUB_MMX(mmr1, mmr2) \
- "psubusb "mmr2", "mmr1"\n\t" \
- "paddusb "mmr2", "mmr1"\n\t"
-#define V_PMAXUB_MMXEXT(mmr1, mmr2) "pmaxub "mmr2", "mmr1"\n\t"
-#define V_PMAXUB_3DNOW(mmr1, mmr2) V_PMAXUB_MMX(mmr1, mmr2) // use MMX version
-#define V_PMAXUB(mmr1, mmr2) V_PMAXUB2(mmr1, mmr2, SIMD_TYPE)
-#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type)
-#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2)
-
-// some macros for pminub instruction
-// V_PMINUB(mmr1, mmr2, mmr work register) mmr2 may NOT = mmrw
-#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \
- "pcmpeqb "mmrw", "mmrw"\n\t" \
- "psubusb "mmr2", "mmrw"\n\t" \
- "paddusb "mmrw", "mmr1"\n\t" \
- "psubusb "mmrw", "mmr1"\n\t"
-#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw) "pminub "mmr2", "mmr1"\n\t"
-#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw) V_PMINUB_MMX(mmr1, mmr2, mmrw) // use MMX version
-#define V_PMINUB(mmr1, mmr2, mmrw) V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE)
-#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type)
-#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw)
-
-// some macros for movntq instruction
-// V_MOVNTQ(mmr1, mmr2)
-#define V_MOVNTQ_MMX(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ_3DNOW(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ_MMXEXT(mmr1, mmr2) "movntq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ(mmr1, mmr2) V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE)
-#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type)
-#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2)
-
-// end of macros
-
diff --git a/gst/deinterlace2/tvtime/linear.c b/gst/deinterlace2/tvtime/linear.c
deleted file mode 100644
index 42403e49..00000000
--- a/gst/deinterlace2/tvtime/linear.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/**
- * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_LINEAR (gst_deinterlace_method_linear_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_LINEAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR))
-#define GST_IS_DEINTERLACE_METHOD_LINEAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR))
-#define GST_DEINTERLACE_METHOD_LINEAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass))
-#define GST_DEINTERLACE_METHOD_LINEAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinear))
-#define GST_DEINTERLACE_METHOD_LINEAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR, GstDeinterlaceMethodLinearClass))
-#define GST_DEINTERLACE_METHOD_LINEAR_CAST(obj) ((GstDeinterlaceMethodLinear*)(obj))
-
-GType gst_deinterlace_method_linear_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinear;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearClass;
-
-static void
-deinterlace_scanline_linear_c (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- gint i;
-
- width *= 2;
- for (i = 0; i < width; i++)
- out[i] = (scanlines->t0[i] + scanlines->b0[i]) / 2;
-}
-
-#ifdef BUILD_X86_ASM
-#include "mmx.h"
-static void
-deinterlace_scanline_linear_mmx (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- const mmx_t shiftmask = { 0xfefffefffefffeffULL }; /* To avoid shifting chroma to luma. */
- int i;
- guint8 *bot = scanlines->b0, *top = scanlines->t0;
-
- for (i = width / 16; i; --i) {
- movq_m2r (*bot, mm0);
- movq_m2r (*top, mm1);
- movq_m2r (*(bot + 8), mm2);
- movq_m2r (*(top + 8), mm3);
- movq_m2r (*(bot + 16), mm4);
- movq_m2r (*(top + 16), mm5);
- movq_m2r (*(bot + 24), mm6);
- movq_m2r (*(top + 24), mm7);
- pand_m2r (shiftmask, mm0);
- pand_m2r (shiftmask, mm1);
- pand_m2r (shiftmask, mm2);
- pand_m2r (shiftmask, mm3);
- pand_m2r (shiftmask, mm4);
- pand_m2r (shiftmask, mm5);
- pand_m2r (shiftmask, mm6);
- pand_m2r (shiftmask, mm7);
- psrlw_i2r (1, mm0);
- psrlw_i2r (1, mm1);
- psrlw_i2r (1, mm2);
- psrlw_i2r (1, mm3);
- psrlw_i2r (1, mm4);
- psrlw_i2r (1, mm5);
- psrlw_i2r (1, mm6);
- psrlw_i2r (1, mm7);
- paddb_r2r (mm1, mm0);
- paddb_r2r (mm3, mm2);
- paddb_r2r (mm5, mm4);
- paddb_r2r (mm7, mm6);
- movq_r2m (mm0, *out);
- movq_r2m (mm2, *(out + 8));
- movq_r2m (mm4, *(out + 16));
- movq_r2m (mm6, *(out + 24));
- out += 32;
- top += 32;
- bot += 32;
- }
- width = (width & 0xf);
-
- for (i = width / 4; i; --i) {
- movq_m2r (*bot, mm0);
- movq_m2r (*top, mm1);
- pand_m2r (shiftmask, mm0);
- pand_m2r (shiftmask, mm1);
- psrlw_i2r (1, mm0);
- psrlw_i2r (1, mm1);
- paddb_r2r (mm1, mm0);
- movq_r2m (mm0, *out);
- out += 8;
- top += 8;
- bot += 8;
- }
- width = width & 0x7;
-
- /* Handle last few pixels. */
- for (i = width * 2; i; --i) {
- *out++ = ((*top++) + (*bot++)) >> 1;
- }
-
- emms ();
-}
-
-#include "sse.h"
-static void
-deinterlace_scanline_linear_mmxext (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- gint i;
- guint8 *bot = scanlines->b0, *top = scanlines->t0;
-
- for (i = width / 16; i; --i) {
- movq_m2r (*bot, mm0);
- movq_m2r (*top, mm1);
- movq_m2r (*(bot + 8), mm2);
- movq_m2r (*(top + 8), mm3);
- movq_m2r (*(bot + 16), mm4);
- movq_m2r (*(top + 16), mm5);
- movq_m2r (*(bot + 24), mm6);
- movq_m2r (*(top + 24), mm7);
- pavgb_r2r (mm1, mm0);
- pavgb_r2r (mm3, mm2);
- pavgb_r2r (mm5, mm4);
- pavgb_r2r (mm7, mm6);
- movntq_r2m (mm0, *out);
- movntq_r2m (mm2, *(out + 8));
- movntq_r2m (mm4, *(out + 16));
- movntq_r2m (mm6, *(out + 24));
- out += 32;
- top += 32;
- bot += 32;
- }
- width = (width & 0xf);
-
- for (i = width / 4; i; --i) {
- movq_m2r (*bot, mm0);
- movq_m2r (*top, mm1);
- pavgb_r2r (mm1, mm0);
- movntq_r2m (mm0, *out);
- out += 8;
- top += 8;
- bot += 8;
- }
- width = width & 0x7;
-
- /* Handle last few pixels. */
- for (i = width * 2; i; --i) {
- *out++ = ((*top++) + (*bot++)) >> 1;
- }
-
- emms ();
-}
-
-#endif
-
-G_DEFINE_TYPE (GstDeinterlaceMethodLinear, gst_deinterlace_method_linear,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_linear_class_init (GstDeinterlaceMethodLinearClass *
- klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- dim_class->fields_required = 1;
- dim_class->name = "Television: Full resolution";
- dim_class->nick = "linear";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_linear_c;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
- dism_class->interpolate_scanline = deinterlace_scanline_linear_mmxext;
- } else if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
- dism_class->interpolate_scanline = deinterlace_scanline_linear_mmx;
- }
-#endif
-}
-
-static void
-gst_deinterlace_method_linear_init (GstDeinterlaceMethodLinear * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/linearblend.c b/gst/deinterlace2/tvtime/linearblend.c
deleted file mode 100644
index c25c4d0e..00000000
--- a/gst/deinterlace2/tvtime/linearblend.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Linear blend deinterlacing plugin. The idea for this algorithm came
- * from the linear blend deinterlacer which originated in the mplayer
- * sources.
- *
- * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND))
-#define GST_IS_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND))
-#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass))
-#define GST_DEINTERLACE_METHOD_LINEAR_BLEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlend))
-#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_LINEAR_BLEND, GstDeinterlaceMethodLinearBlendClass))
-#define GST_DEINTERLACE_METHOD_LINEAR_BLEND_CAST(obj) ((GstDeinterlaceMethodLinearBlend*)(obj))
-
-GType gst_deinterlace_method_linear_blend_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodLinearBlend;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodLinearBlendClass;
-
-
-static inline void
-deinterlace_scanline_linear_blend_c (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- guint8 *t0 = scanlines->t0;
- guint8 *b0 = scanlines->b0;
- guint8 *m1 = scanlines->m1;
-
- width *= 2;
-
- while (width--) {
- *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2;
- }
-}
-
-static inline void
-deinterlace_scanline_linear_blend2_c (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- guint8 *m0 = scanlines->m0;
- guint8 *t1 = scanlines->t1;
- guint8 *b1 = scanlines->b1;
-
- width *= 2;
- while (width--) {
- *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2;
- }
-}
-
-#ifdef BUILD_X86_ASM
-#include "mmx.h"
-static inline void
-deinterlace_scanline_linear_blend_mmx (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- guint8 *t0 = scanlines->t0;
- guint8 *b0 = scanlines->b0;
- guint8 *m1 = scanlines->m1;
- gint i;
-
- // Get width in bytes.
- width *= 2;
- i = width / 8;
- width -= i * 8;
-
- pxor_r2r (mm7, mm7);
- while (i--) {
- movd_m2r (*t0, mm0);
- movd_m2r (*b0, mm1);
- movd_m2r (*m1, mm2);
-
- movd_m2r (*(t0 + 4), mm3);
- movd_m2r (*(b0 + 4), mm4);
- movd_m2r (*(m1 + 4), mm5);
-
- punpcklbw_r2r (mm7, mm0);
- punpcklbw_r2r (mm7, mm1);
- punpcklbw_r2r (mm7, mm2);
-
- punpcklbw_r2r (mm7, mm3);
- punpcklbw_r2r (mm7, mm4);
- punpcklbw_r2r (mm7, mm5);
-
- psllw_i2r (1, mm2);
- psllw_i2r (1, mm5);
- paddw_r2r (mm0, mm2);
- paddw_r2r (mm3, mm5);
- paddw_r2r (mm1, mm2);
- paddw_r2r (mm4, mm5);
- psrlw_i2r (2, mm2);
- psrlw_i2r (2, mm5);
- packuswb_r2r (mm2, mm2);
- packuswb_r2r (mm5, mm5);
-
- movd_r2m (mm2, *out);
- movd_r2m (mm5, *(out + 4));
- out += 8;
- t0 += 8;
- b0 += 8;
- m1 += 8;
- }
- while (width--) {
- *out++ = (*t0++ + *b0++ + (*m1++ << 1)) >> 2;
- }
- emms ();
-}
-
-static inline void
-deinterlace_scanline_linear_blend2_mmx (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- guint8 *m0 = scanlines->m0;
- guint8 *t1 = scanlines->t1;
- guint8 *b1 = scanlines->b1;
- gint i;
-
- // Get width in bytes.
- width *= 2;
- i = width / 8;
- width -= i * 8;
-
- pxor_r2r (mm7, mm7);
- while (i--) {
- movd_m2r (*t1, mm0);
- movd_m2r (*b1, mm1);
- movd_m2r (*m0, mm2);
-
- movd_m2r (*(t1 + 4), mm3);
- movd_m2r (*(b1 + 4), mm4);
- movd_m2r (*(m0 + 4), mm5);
-
- punpcklbw_r2r (mm7, mm0);
- punpcklbw_r2r (mm7, mm1);
- punpcklbw_r2r (mm7, mm2);
-
- punpcklbw_r2r (mm7, mm3);
- punpcklbw_r2r (mm7, mm4);
- punpcklbw_r2r (mm7, mm5);
-
- psllw_i2r (1, mm2);
- psllw_i2r (1, mm5);
- paddw_r2r (mm0, mm2);
- paddw_r2r (mm3, mm5);
- paddw_r2r (mm1, mm2);
- paddw_r2r (mm4, mm5);
- psrlw_i2r (2, mm2);
- psrlw_i2r (2, mm5);
- packuswb_r2r (mm2, mm2);
- packuswb_r2r (mm5, mm5);
-
- movd_r2m (mm2, *out);
- movd_r2m (mm5, *(out + 4));
- out += 8;
- t1 += 8;
- b1 += 8;
- m0 += 8;
- }
- while (width--) {
- *out++ = (*t1++ + *b1++ + (*m0++ << 1)) >> 2;
- }
- emms ();
-}
-
-#endif
-
-G_DEFINE_TYPE (GstDeinterlaceMethodLinearBlend,
- gst_deinterlace_method_linear_blend, GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
- gst_deinterlace_method_linear_blend_class_init
- (GstDeinterlaceMethodLinearBlendClass * klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- dim_class->fields_required = 2;
- dim_class->name = "Blur: Temporal";
- dim_class->nick = "linearblend";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_c;
- dism_class->copy_scanline = deinterlace_scanline_linear_blend2_c;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMX) {
- dism_class->interpolate_scanline = deinterlace_scanline_linear_blend_mmx;
- dism_class->copy_scanline = deinterlace_scanline_linear_blend2_mmx;
- }
-#endif
-}
-
-static void
-gst_deinterlace_method_linear_blend_init (GstDeinterlaceMethodLinearBlend *
- self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/mmx.h b/gst/deinterlace2/tvtime/mmx.h
deleted file mode 100644
index 3627e61b..00000000
--- a/gst/deinterlace2/tvtime/mmx.h
+++ /dev/null
@@ -1,723 +0,0 @@
-/* mmx.h
-
- MultiMedia eXtensions GCC interface library for IA32.
-
- To use this library, simply include this header file
- and compile with GCC. You MUST have inlining enabled
- in order for mmx_ok() to work; this can be done by
- simply using -O on the GCC command line.
-
- Compiling with -DMMX_TRACE will cause detailed trace
- output to be sent to stderr for each mmx operation.
- This adds lots of code, and obviously slows execution to
- a crawl, but can be very useful for debugging.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
- LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR ANY PARTICULAR PURPOSE.
-
- 1997-98 by H. Dietz and R. Fisher
-
- History:
- 97-98* R.Fisher Early versions
- 980501 R.Fisher Original Release
- 980611* H.Dietz Rewrite, correctly implementing inlines, and
- R.Fisher including direct register accesses.
- 980616 R.Fisher Release of 980611 as 980616.
- 980714 R.Fisher Minor corrections to Makefile, etc.
- 980715 R.Fisher mmx_ok() now prevents optimizer from using
- clobbered values.
- mmx_ok() now checks if cpuid instruction is
- available before trying to use it.
- 980726* R.Fisher mm_support() searches for AMD 3DNow, Cyrix
- Extended MMX, and standard MMX. It returns a
- value which is positive if any of these are
- supported, and can be masked with constants to
- see which. mmx_ok() is now a call to this
- 980726* R.Fisher Added i2r support for shift functions
- 980919 R.Fisher Fixed AMD extended feature recognition bug.
- 980921 R.Fisher Added definition/check for _MMX_H.
- Added "float s[2]" to mmx_t for use with
- 3DNow and EMMX. So same mmx_t can be used.
- 981013 R.Fisher Fixed cpuid function 1 bug (looked at wrong reg)
- Fixed psllq_i2r error in mmxtest.c
-
- * Unreleased (internal or interim) versions
-
- Notes:
- It appears that the latest gas has the pand problem fixed, therefore
- I'll undefine BROKEN_PAND by default.
- String compares may be quicker than the multiple test/jumps in vendor
- test sequence in mmx_ok(), but I'm not concerned with that right now.
-
- Acknowledgments:
- Jussi Laako for pointing out the errors ultimately found to be
- connected to the failure to notify the optimizer of clobbered values.
- Roger Hardiman for reminding us that CPUID isn't everywhere, and that
- someone may actually try to use this on a machine without CPUID.
- Also for suggesting code for checking this.
- Robert Dale for pointing out the AMD recognition bug.
- Jimmy Mayfield and Carl Witty for pointing out the Intel recognition
- bug.
- Carl Witty for pointing out the psllq_i2r test bug.
-*/
-
-#ifndef _MMX_H
-#define _MMX_H
-
-/*#define MMX_TRACE */
-
-/* Warning: at this writing, the version of GAS packaged
- with most Linux distributions does not handle the
- parallel AND operation mnemonic correctly. If the
- symbol BROKEN_PAND is defined, a slower alternative
- coding will be used. If execution of mmxtest results
- in an illegal instruction fault, define this symbol.
-*/
-#undef BROKEN_PAND
-
-
-/* The type of an value that fits in an MMX register
- (note that long long constant values MUST be suffixed
- by LL and unsigned long long values by ULL, lest
- they be truncated by the compiler)
-*/
-typedef union {
- long long q; /* Quadword (64-bit) value */
- unsigned long long uq; /* Unsigned Quadword */
- int d[2]; /* 2 Doubleword (32-bit) values */
- unsigned int ud[2]; /* 2 Unsigned Doubleword */
- short w[4]; /* 4 Word (16-bit) values */
- unsigned short uw[4]; /* 4 Unsigned Word */
- char b[8]; /* 8 Byte (8-bit) values */
- unsigned char ub[8]; /* 8 Unsigned Byte */
- float s[2]; /* Single-precision (32-bit) value */
-} mmx_t;
-
-
-/* Function to test if multimedia instructions are supported...
-*/
-inline extern int
-mm_support(void)
-{
- /* Returns 1 if MMX instructions are supported,
- 3 if Cyrix MMX and Extended MMX instructions are supported
- 5 if AMD MMX and 3DNow! instructions are supported
- 0 if hardware does not support any of these
- */
- register int rval = 0;
-
- __asm__ __volatile__ (
- /* See if CPUID instruction is supported ... */
- /* ... Get copies of EFLAGS into eax and ecx */
- "pushf\n\t"
- "popl %%eax\n\t"
- "movl %%eax, %%ecx\n\t"
-
- /* ... Toggle the ID bit in one copy and store */
- /* to the EFLAGS reg */
- "xorl $0x200000, %%eax\n\t"
- "push %%eax\n\t"
- "popf\n\t"
-
- /* ... Get the (hopefully modified) EFLAGS */
- "pushf\n\t"
- "popl %%eax\n\t"
-
- /* ... Compare and test result */
- "xorl %%eax, %%ecx\n\t"
- "testl $0x200000, %%ecx\n\t"
- "jz NotSupported1\n\t" /* Nothing supported */
-
-
- /* Get standard CPUID information, and
- go to a specific vendor section */
- "movl $0, %%eax\n\t"
- "cpuid\n\t"
-
- /* Check for Intel */
- "cmpl $0x756e6547, %%ebx\n\t"
- "jne TryAMD\n\t"
- "cmpl $0x49656e69, %%edx\n\t"
- "jne TryAMD\n\t"
- "cmpl $0x6c65746e, %%ecx\n"
- "jne TryAMD\n\t"
- "jmp Intel\n\t"
-
- /* Check for AMD */
- "\nTryAMD:\n\t"
- "cmpl $0x68747541, %%ebx\n\t"
- "jne TryCyrix\n\t"
- "cmpl $0x69746e65, %%edx\n\t"
- "jne TryCyrix\n\t"
- "cmpl $0x444d4163, %%ecx\n"
- "jne TryCyrix\n\t"
- "jmp AMD\n\t"
-
- /* Check for Cyrix */
- "\nTryCyrix:\n\t"
- "cmpl $0x69727943, %%ebx\n\t"
- "jne NotSupported2\n\t"
- "cmpl $0x736e4978, %%edx\n\t"
- "jne NotSupported3\n\t"
- "cmpl $0x64616574, %%ecx\n\t"
- "jne NotSupported4\n\t"
- /* Drop through to Cyrix... */
-
-
- /* Cyrix Section */
- /* See if extended CPUID is supported */
- "movl $0x80000000, %%eax\n\t"
- "cpuid\n\t"
- "cmpl $0x80000000, %%eax\n\t"
- "jl MMXtest\n\t" /* Try standard CPUID instead */
-
- /* Extended CPUID supported, so get extended features */
- "movl $0x80000001, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%eax\n\t" /* Test for MMX */
- "jz NotSupported5\n\t" /* MMX not supported */
- "testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */
- "jnz EMMXSupported\n\t"
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\n"
- "EMMXSupported:\n\t"
- "movl $3, %0:\n\n\t" /* EMMX and MMX Supported */
- "jmp Return\n\t"
-
-
- /* AMD Section */
- "AMD:\n\t"
-
- /* See if extended CPUID is supported */
- "movl $0x80000000, %%eax\n\t"
- "cpuid\n\t"
- "cmpl $0x80000000, %%eax\n\t"
- "jl MMXtest\n\t" /* Try standard CPUID instead */
-
- /* Extended CPUID supported, so get extended features */
- "movl $0x80000001, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%edx\n\t" /* Test for MMX */
- "jz NotSupported6\n\t" /* MMX not supported */
- "testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */
- "jnz ThreeDNowSupported\n\t"
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\n"
- "ThreeDNowSupported:\n\t"
- "movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */
- "jmp Return\n\t"
-
-
- /* Intel Section */
- "Intel:\n\t"
-
- /* Check for MMX */
- "MMXtest:\n\t"
- "movl $1, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%edx\n\t" /* Test for MMX */
- "jz NotSupported7\n\t" /* MMX Not supported */
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\t"
-
- /* Nothing supported */
- "\nNotSupported1:\n\t"
- "#movl $101, %0:\n\n\t"
- "\nNotSupported2:\n\t"
- "#movl $102, %0:\n\n\t"
- "\nNotSupported3:\n\t"
- "#movl $103, %0:\n\n\t"
- "\nNotSupported4:\n\t"
- "#movl $104, %0:\n\n\t"
- "\nNotSupported5:\n\t"
- "#movl $105, %0:\n\n\t"
- "\nNotSupported6:\n\t"
- "#movl $106, %0:\n\n\t"
- "\nNotSupported7:\n\t"
- "#movl $107, %0:\n\n\t"
- "movl $0, %0:\n\n\t"
-
- "Return:\n\t"
- : "=a" (rval)
- : /* no input */
- : "eax", "ebx", "ecx", "edx"
- );
-
- /* Return */
- return(rval);
-}
-
-/* Function to test if mmx instructions are supported...
-*/
-inline extern int
-mmx_ok(void)
-{
- /* Returns 1 if MMX instructions are supported, 0 otherwise */
- return ( mm_support() & 0x1 );
-}
-
-
-/* Helper functions for the instruction macros that follow...
- (note that memory-to-register, m2r, instructions are nearly
- as efficient as register-to-register, r2r, instructions;
- however, memory-to-memory instructions are really simulated
- as a convenience, and are only 1/3 as efficient)
-*/
-#ifdef MMX_TRACE
-
-/* Include the stuff for printing a trace to stderr...
-*/
-
-#include <stdio.h>
-
-#define mmx_i2r(op, imm, reg) \
- { \
- mmx_t mmx_trace; \
- mmx_trace = (imm); \
- fprintf(stderr, #op "_i2r(" #imm "=0x%016llx, ", mmx_trace.q); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (imm)); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
- }
-
-#define mmx_m2r(op, mem, reg) \
- { \
- mmx_t mmx_trace; \
- mmx_trace = (mem); \
- fprintf(stderr, #op "_m2r(" #mem "=0x%016llx, ", mmx_trace.q); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%016llx) => ", mmx_trace.q); \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (mem)); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%016llx\n", mmx_trace.q); \
- }
-
-#define mmx_r2m(op, reg, mem) \
- { \
- mmx_t mmx_trace; \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #op "_r2m(" #reg "=0x%016llx, ", mmx_trace.q); \
- mmx_trace = (mem); \
- fprintf(stderr, #mem "=0x%016llx) => ", mmx_trace.q); \
- __asm__ __volatile__ (#op " %%" #reg ", %0" \
- : "=X" (mem) \
- : /* nothing */ ); \
- mmx_trace = (mem); \
- fprintf(stderr, #mem "=0x%016llx\n", mmx_trace.q); \
- }
-
-#define mmx_r2r(op, regs, regd) \
- { \
- mmx_t mmx_trace; \
- __asm__ __volatile__ ("movq %%" #regs ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #op "_r2r(" #regs "=0x%016llx, ", mmx_trace.q); \
- __asm__ __volatile__ ("movq %%" #regd ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #regd "=0x%016llx) => ", mmx_trace.q); \
- __asm__ __volatile__ (#op " %" #regs ", %" #regd); \
- __asm__ __volatile__ ("movq %%" #regd ", %0" \
- : "=X" (mmx_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #regd "=0x%016llx\n", mmx_trace.q); \
- }
-
-#define mmx_m2m(op, mems, memd) \
- { \
- mmx_t mmx_trace; \
- mmx_trace = (mems); \
- fprintf(stderr, #op "_m2m(" #mems "=0x%016llx, ", mmx_trace.q); \
- mmx_trace = (memd); \
- fprintf(stderr, #memd "=0x%016llx) => ", mmx_trace.q); \
- __asm__ __volatile__ ("movq %0, %%mm0\n\t" \
- #op " %1, %%mm0\n\t" \
- "movq %%mm0, %0" \
- : "=X" (memd) \
- : "X" (mems)); \
- mmx_trace = (memd); \
- fprintf(stderr, #memd "=0x%016llx\n", mmx_trace.q); \
- }
-
-#else
-
-/* These macros are a lot simpler without the tracing...
-*/
-
-#define mmx_i2r(op, imm, reg) \
- __asm__ __volatile__ (#op " $" #imm ", %%" #reg \
- : /* nothing */ \
- : /* nothing */);
-
-#define mmx_m2r(op, mem, reg) \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "m" (mem))
-
-#define mmx_r2m(op, reg, mem) \
- __asm__ __volatile__ (#op " %%" #reg ", %0" \
- : "=m" (mem) \
- : /* nothing */ )
-
-#define mmx_r2r(op, regs, regd) \
- __asm__ __volatile__ (#op " %" #regs ", %" #regd)
-
-#define mmx_m2m(op, mems, memd) \
- __asm__ __volatile__ ("movq %0, %%mm0\n\t" \
- #op " %1, %%mm0\n\t" \
- "movq %%mm0, %0" \
- : "=m" (memd) \
- : "m" (mems))
-
-#endif
-
-
-/* 1x64 MOVe Quadword
- (this is both a load and a store...
- in fact, it is the only way to store)
-*/
-#define movq_m2r(var, reg) mmx_m2r(movq, var, reg)
-#define movq_r2m(reg, var) mmx_r2m(movq, reg, var)
-#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd)
-#define movq(vars, vard) \
- __asm__ __volatile__ ("movq %1, %%mm0\n\t" \
- "movq %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* 1x32 MOVe Doubleword
- (like movq, this is both load and store...
- but is most useful for moving things between
- mmx registers and ordinary registers)
-*/
-#define movd_m2r(var, reg) mmx_m2r(movd, var, reg)
-#define movd_r2m(reg, var) mmx_r2m(movd, reg, var)
-#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd)
-#define movd(vars, vard) \
- __asm__ __volatile__ ("movd %1, %%mm0\n\t" \
- "movd %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* 2x32, 4x16, and 8x8 Parallel ADDs
-*/
-#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg)
-#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd)
-#define paddd(vars, vard) mmx_m2m(paddd, vars, vard)
-
-#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg)
-#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd)
-#define paddw(vars, vard) mmx_m2m(paddw, vars, vard)
-
-#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg)
-#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd)
-#define paddb(vars, vard) mmx_m2m(paddb, vars, vard)
-
-
-/* 4x16 and 8x8 Parallel ADDs using Saturation arithmetic
-*/
-#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg)
-#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd)
-#define paddsw(vars, vard) mmx_m2m(paddsw, vars, vard)
-
-#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg)
-#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd)
-#define paddsb(vars, vard) mmx_m2m(paddsb, vars, vard)
-
-
-/* 4x16 and 8x8 Parallel ADDs using Unsigned Saturation arithmetic
-*/
-#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg)
-#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd)
-#define paddusw(vars, vard) mmx_m2m(paddusw, vars, vard)
-
-#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg)
-#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd)
-#define paddusb(vars, vard) mmx_m2m(paddusb, vars, vard)
-
-
-/* 2x32, 4x16, and 8x8 Parallel SUBs
-*/
-#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg)
-#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd)
-#define psubd(vars, vard) mmx_m2m(psubd, vars, vard)
-
-#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg)
-#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd)
-#define psubw(vars, vard) mmx_m2m(psubw, vars, vard)
-
-#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg)
-#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd)
-#define psubb(vars, vard) mmx_m2m(psubb, vars, vard)
-
-
-/* 4x16 and 8x8 Parallel SUBs using Saturation arithmetic
-*/
-#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg)
-#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd)
-#define psubsw(vars, vard) mmx_m2m(psubsw, vars, vard)
-
-#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg)
-#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd)
-#define psubsb(vars, vard) mmx_m2m(psubsb, vars, vard)
-
-
-/* 4x16 and 8x8 Parallel SUBs using Unsigned Saturation arithmetic
-*/
-#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg)
-#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd)
-#define psubusw(vars, vard) mmx_m2m(psubusw, vars, vard)
-
-#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg)
-#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd)
-#define psubusb(vars, vard) mmx_m2m(psubusb, vars, vard)
-
-
-/* 4x16 Parallel MULs giving Low 4x16 portions of results
-*/
-#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg)
-#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd)
-#define pmullw(vars, vard) mmx_m2m(pmullw, vars, vard)
-
-
-/* 4x16 Parallel MULs giving High 4x16 portions of results
-*/
-#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg)
-#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd)
-#define pmulhw(vars, vard) mmx_m2m(pmulhw, vars, vard)
-
-
-/* 4x16->2x32 Parallel Mul-ADD
- (muls like pmullw, then adds adjacent 16-bit fields
- in the multiply result to make the final 2x32 result)
-*/
-#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg)
-#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd)
-#define pmaddwd(vars, vard) mmx_m2m(pmaddwd, vars, vard)
-
-
-/* 1x64 bitwise AND
-*/
-#ifdef BROKEN_PAND
-#define pand_m2r(var, reg) \
- { \
- mmx_m2r(pandn, (mmx_t) -1LL, reg); \
- mmx_m2r(pandn, var, reg); \
- }
-#define pand_r2r(regs, regd) \
- { \
- mmx_m2r(pandn, (mmx_t) -1LL, regd); \
- mmx_r2r(pandn, regs, regd); \
- }
-#define pand(vars, vard) \
- { \
- movq_m2r(vard, mm0); \
- mmx_m2r(pandn, (mmx_t) -1LL, mm0); \
- mmx_m2r(pandn, vars, mm0); \
- movq_r2m(mm0, vard); \
- }
-#else
-#define pand_m2r(var, reg) mmx_m2r(pand, var, reg)
-#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd)
-#define pand(vars, vard) mmx_m2m(pand, vars, vard)
-#endif
-
-
-/* 1x64 bitwise AND with Not the destination
-*/
-#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg)
-#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd)
-#define pandn(vars, vard) mmx_m2m(pandn, vars, vard)
-
-
-/* 1x64 bitwise OR
-*/
-#define por_m2r(var, reg) mmx_m2r(por, var, reg)
-#define por_r2r(regs, regd) mmx_r2r(por, regs, regd)
-#define por(vars, vard) mmx_m2m(por, vars, vard)
-
-
-/* 1x64 bitwise eXclusive OR
-*/
-#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg)
-#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd)
-#define pxor(vars, vard) mmx_m2m(pxor, vars, vard)
-
-
-/* 2x32, 4x16, and 8x8 Parallel CoMPare for EQuality
- (resulting fields are either 0 or -1)
-*/
-#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg)
-#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd)
-#define pcmpeqd(vars, vard) mmx_m2m(pcmpeqd, vars, vard)
-
-#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg)
-#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd)
-#define pcmpeqw(vars, vard) mmx_m2m(pcmpeqw, vars, vard)
-
-#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg)
-#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd)
-#define pcmpeqb(vars, vard) mmx_m2m(pcmpeqb, vars, vard)
-
-
-/* 2x32, 4x16, and 8x8 Parallel CoMPare for Greater Than
- (resulting fields are either 0 or -1)
-*/
-#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg)
-#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd)
-#define pcmpgtd(vars, vard) mmx_m2m(pcmpgtd, vars, vard)
-
-#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg)
-#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd)
-#define pcmpgtw(vars, vard) mmx_m2m(pcmpgtw, vars, vard)
-
-#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg)
-#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd)
-#define pcmpgtb(vars, vard) mmx_m2m(pcmpgtb, vars, vard)
-
-
-/* 1x64, 2x32, and 4x16 Parallel Shift Left Logical
-*/
-#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg)
-#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg)
-#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd)
-#define psllq(vars, vard) mmx_m2m(psllq, vars, vard)
-
-#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg)
-#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg)
-#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd)
-#define pslld(vars, vard) mmx_m2m(pslld, vars, vard)
-
-#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg)
-#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg)
-#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd)
-#define psllw(vars, vard) mmx_m2m(psllw, vars, vard)
-
-
-/* 1x64, 2x32, and 4x16 Parallel Shift Right Logical
-*/
-#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg)
-#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg)
-#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd)
-#define psrlq(vars, vard) mmx_m2m(psrlq, vars, vard)
-
-#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg)
-#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg)
-#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd)
-#define psrld(vars, vard) mmx_m2m(psrld, vars, vard)
-
-#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg)
-#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg)
-#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd)
-#define psrlw(vars, vard) mmx_m2m(psrlw, vars, vard)
-
-
-/* 2x32 and 4x16 Parallel Shift Right Arithmetic
-*/
-#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg)
-#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg)
-#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd)
-#define psrad(vars, vard) mmx_m2m(psrad, vars, vard)
-
-#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg)
-#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg)
-#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd)
-#define psraw(vars, vard) mmx_m2m(psraw, vars, vard)
-
-
-/* 2x32->4x16 and 4x16->8x8 PACK and Signed Saturate
- (packs source and dest fields into dest in that order)
-*/
-#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg)
-#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
-#define packssdw(vars, vard) mmx_m2m(packssdw, vars, vard)
-
-#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg)
-#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
-#define packsswb(vars, vard) mmx_m2m(packsswb, vars, vard)
-
-
-/* 4x16->8x8 PACK and Unsigned Saturate
- (packs source and dest fields into dest in that order)
-*/
-#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg)
-#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
-#define packuswb(vars, vard) mmx_m2m(packuswb, vars, vard)
-
-
-/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK Low
- (interleaves low half of dest with low half of source
- as padding in each result field)
-*/
-#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg)
-#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
-#define punpckldq(vars, vard) mmx_m2m(punpckldq, vars, vard)
-
-#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg)
-#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
-#define punpcklwd(vars, vard) mmx_m2m(punpcklwd, vars, vard)
-
-#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg)
-#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
-#define punpcklbw(vars, vard) mmx_m2m(punpcklbw, vars, vard)
-
-
-/* 2x32->1x64, 4x16->2x32, and 8x8->4x16 UNPaCK High
- (interleaves high half of dest with high half of source
- as padding in each result field)
-*/
-#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg)
-#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
-#define punpckhdq(vars, vard) mmx_m2m(punpckhdq, vars, vard)
-
-#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg)
-#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
-#define punpckhwd(vars, vard) mmx_m2m(punpckhwd, vars, vard)
-
-#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg)
-#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
-#define punpckhbw(vars, vard) mmx_m2m(punpckhbw, vars, vard)
-
-
-/* Empty MMx State
- (used to clean-up when going from mmx to float use
- of the registers that are shared by both; note that
- there is no float-to-mmx operation needed, because
- only the float tag word info is corruptible)
-*/
-#ifdef MMX_TRACE
-
-#define emms() \
- { \
- fprintf(stderr, "emms()\n"); \
- __asm__ __volatile__ ("emms"); \
- }
-
-#else
-
-#define emms() __asm__ __volatile__ ("emms")
-
-#endif
-
-#endif
diff --git a/gst/deinterlace2/tvtime/plugins.h b/gst/deinterlace2/tvtime/plugins.h
deleted file mode 100644
index 8fb01af5..00000000
--- a/gst/deinterlace2/tvtime/plugins.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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.
- */
-
-/*
- * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-#ifndef TVTIME_PLUGINS_H_INCLUDED
-#define TVTIME_PLUGINS_H_INCLUDED
-
-#define GST_TYPE_DEINTERLACE_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ())
-#define GST_TYPE_DEINTERLACE_GREEDY_H (gst_deinterlace_method_greedy_h_get_type ())
-#define GST_TYPE_DEINTERLACE_GREEDY_L (gst_deinterlace_method_greedy_l_get_type ())
-#define GST_TYPE_DEINTERLACE_VFIR (gst_deinterlace_method_vfir_get_type ())
-#define GST_TYPE_DEINTERLACE_LINEAR (gst_deinterlace_method_linear_get_type ())
-#define GST_TYPE_DEINTERLACE_LINEAR_BLEND (gst_deinterlace_method_linear_blend_get_type ())
-#define GST_TYPE_DEINTERLACE_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ())
-#define GST_TYPE_DEINTERLACE_WEAVE (gst_deinterlace_method_weave_get_type ())
-#define GST_TYPE_DEINTERLACE_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ())
-#define GST_TYPE_DEINTERLACE_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ())
-
-GType gst_deinterlace_method_tomsmocomp_get_type (void);
-GType gst_deinterlace_method_greedy_h_get_type (void);
-GType gst_deinterlace_method_greedy_l_get_type (void);
-GType gst_deinterlace_method_vfir_get_type (void);
-
-GType gst_deinterlace_method_linear_get_type (void);
-GType gst_deinterlace_method_linear_blend_get_type (void);
-GType gst_deinterlace_method_scaler_bob_get_type (void);
-GType gst_deinterlace_method_weave_get_type (void);
-GType gst_deinterlace_method_weave_tff_get_type (void);
-GType gst_deinterlace_method_weave_bff_get_type (void);
-
-#endif /* TVTIME_PLUGINS_H_INCLUDED */
diff --git a/gst/deinterlace2/tvtime/scalerbob.c b/gst/deinterlace2/tvtime/scalerbob.c
deleted file mode 100644
index a37792ab..00000000
--- a/gst/deinterlace2/tvtime/scalerbob.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Double lines
- * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB (gst_deinterlace_method_scaler_bob_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB))
-#define GST_IS_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB))
-#define GST_DEINTERLACE_METHOD_SCALER_BOB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass))
-#define GST_DEINTERLACE_METHOD_SCALER_BOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBob))
-#define GST_DEINTERLACE_METHOD_SCALER_BOB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_SCALER_BOB, GstDeinterlaceMethodScalerBobClass))
-#define GST_DEINTERLACE_METHOD_SCALER_BOB_CAST(obj) ((GstDeinterlaceMethodScalerBob*)(obj))
-
-GType gst_deinterlace_method_scaler_bob_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodScalerBob;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodScalerBobClass;
-
-
-static void
-deinterlace_scanline_scaler_bob (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->t0, parent->row_stride);
-}
-
-G_DEFINE_TYPE (GstDeinterlaceMethodScalerBob, gst_deinterlace_method_scaler_bob,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_scaler_bob_class_init (GstDeinterlaceMethodScalerBobClass
- * klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-
- dim_class->fields_required = 1;
- dim_class->name = "Double lines";
- dim_class->nick = "scalerbob";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_scaler_bob;
-}
-
-static void
-gst_deinterlace_method_scaler_bob_init (GstDeinterlaceMethodScalerBob * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/sse.h b/gst/deinterlace2/tvtime/sse.h
deleted file mode 100644
index 2e00ee0c..00000000
--- a/gst/deinterlace2/tvtime/sse.h
+++ /dev/null
@@ -1,992 +0,0 @@
-/* sse.h
-
- Streaming SIMD Extenstions (a.k.a. Katmai New Instructions)
- GCC interface library for IA32.
-
- To use this library, simply include this header file
- and compile with GCC. You MUST have inlining enabled
- in order for sse_ok() to work; this can be done by
- simply using -O on the GCC command line.
-
- Compiling with -DSSE_TRACE will cause detailed trace
- output to be sent to stderr for each sse operation.
- This adds lots of code, and obviously slows execution to
- a crawl, but can be very useful for debugging.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
- LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR ANY PARTICULAR PURPOSE.
-
- 1999 by R. Fisher
- Based on libmmx by H. Dietz and R. Fisher
-
- Notes:
- This is still extremely alpha.
- Because this library depends on an assembler which understands the
- SSE opcodes, you probably won't be able to use this yet.
- For now, do not use TRACE versions. These both make use
- of the MMX registers, not the SSE registers. This will be resolved
- at a later date.
- ToDo:
- Rewrite TRACE macros
- Major Debugging Work
-*/
-
-#ifndef _SSE_H
-#define _SSE_H
-
-
-
-/* The type of an value that fits in an SSE register
- (note that long long constant values MUST be suffixed
- by LL and unsigned long long values by ULL, lest
- they be truncated by the compiler)
-*/
-typedef union {
- float sf[4]; /* Single-precision (32-bit) value */
-} __attribute__ ((aligned (16))) sse_t; /* On a 16 byte (128-bit) boundary */
-
-
-#if 0
-/* Function to test if multimedia instructions are supported...
-*/
-inline extern int
-mm_support(void)
-{
- /* Returns 1 if MMX instructions are supported,
- 3 if Cyrix MMX and Extended MMX instructions are supported
- 5 if AMD MMX and 3DNow! instructions are supported
- 9 if MMX and SSE instructions are supported
- 0 if hardware does not support any of these
- */
- register int rval = 0;
-
- __asm__ __volatile__ (
- /* See if CPUID instruction is supported ... */
- /* ... Get copies of EFLAGS into eax and ecx */
- "pushf\n\t"
- "popl %%eax\n\t"
- "movl %%eax, %%ecx\n\t"
-
- /* ... Toggle the ID bit in one copy and store */
- /* to the EFLAGS reg */
- "xorl $0x200000, %%eax\n\t"
- "push %%eax\n\t"
- "popf\n\t"
-
- /* ... Get the (hopefully modified) EFLAGS */
- "pushf\n\t"
- "popl %%eax\n\t"
-
- /* ... Compare and test result */
- "xorl %%eax, %%ecx\n\t"
- "testl $0x200000, %%ecx\n\t"
- "jz NotSupported1\n\t" /* CPUID not supported */
-
-
- /* Get standard CPUID information, and
- go to a specific vendor section */
- "movl $0, %%eax\n\t"
- "cpuid\n\t"
-
- /* Check for Intel */
- "cmpl $0x756e6547, %%ebx\n\t"
- "jne TryAMD\n\t"
- "cmpl $0x49656e69, %%edx\n\t"
- "jne TryAMD\n\t"
- "cmpl $0x6c65746e, %%ecx\n"
- "jne TryAMD\n\t"
- "jmp Intel\n\t"
-
- /* Check for AMD */
- "\nTryAMD:\n\t"
- "cmpl $0x68747541, %%ebx\n\t"
- "jne TryCyrix\n\t"
- "cmpl $0x69746e65, %%edx\n\t"
- "jne TryCyrix\n\t"
- "cmpl $0x444d4163, %%ecx\n"
- "jne TryCyrix\n\t"
- "jmp AMD\n\t"
-
- /* Check for Cyrix */
- "\nTryCyrix:\n\t"
- "cmpl $0x69727943, %%ebx\n\t"
- "jne NotSupported2\n\t"
- "cmpl $0x736e4978, %%edx\n\t"
- "jne NotSupported3\n\t"
- "cmpl $0x64616574, %%ecx\n\t"
- "jne NotSupported4\n\t"
- /* Drop through to Cyrix... */
-
-
- /* Cyrix Section */
- /* See if extended CPUID level 80000001 is supported */
- /* The value of CPUID/80000001 for the 6x86MX is undefined
- according to the Cyrix CPU Detection Guide (Preliminary
- Rev. 1.01 table 1), so we'll check the value of eax for
- CPUID/0 to see if standard CPUID level 2 is supported.
- According to the table, the only CPU which supports level
- 2 is also the only one which supports extended CPUID levels.
- */
- "cmpl $0x2, %%eax\n\t"
- "jne MMXtest\n\t" /* Use standard CPUID instead */
-
- /* Extended CPUID supported (in theory), so get extended
- features */
- "movl $0x80000001, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%eax\n\t" /* Test for MMX */
- "jz NotSupported5\n\t" /* MMX not supported */
- "testl $0x01000000, %%eax\n\t" /* Test for Ext'd MMX */
- "jnz EMMXSupported\n\t"
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\n"
- "EMMXSupported:\n\t"
- "movl $3, %0:\n\n\t" /* EMMX and MMX Supported */
- "jmp Return\n\t"
-
-
- /* AMD Section */
- "AMD:\n\t"
-
- /* See if extended CPUID is supported */
- "movl $0x80000000, %%eax\n\t"
- "cpuid\n\t"
- "cmpl $0x80000000, %%eax\n\t"
- "jl MMXtest\n\t" /* Use standard CPUID instead */
-
- /* Extended CPUID supported, so get extended features */
- "movl $0x80000001, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%edx\n\t" /* Test for MMX */
- "jz NotSupported6\n\t" /* MMX not supported */
- "testl $0x80000000, %%edx\n\t" /* Test for 3DNow! */
- "jnz ThreeDNowSupported\n\t"
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\n"
- "ThreeDNowSupported:\n\t"
- "movl $5, %0:\n\n\t" /* 3DNow! and MMX Supported */
- "jmp Return\n\t"
-
-
- /* Intel Section */
- "Intel:\n\t"
-
- /* Check for SSE */
- "SSEtest:\n\t"
- "movl $1, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x02000000, %%edx\n\t" /* Test for SSE */
- "jz MMXtest\n\t" /* SSE Not supported */
- "movl $9, %0:\n\n\t" /* SSE Supported */
- "jmp Return\n\t"
-
- /* Check for MMX */
- "MMXtest:\n\t"
- "movl $1, %%eax\n\t"
- "cpuid\n\t"
- "testl $0x00800000, %%edx\n\t" /* Test for MMX */
- "jz NotSupported7\n\t" /* MMX Not supported */
- "movl $1, %0:\n\n\t" /* MMX Supported */
- "jmp Return\n\t"
-
- /* Nothing supported */
- "\nNotSupported1:\n\t"
- "#movl $101, %0:\n\n\t"
- "\nNotSupported2:\n\t"
- "#movl $102, %0:\n\n\t"
- "\nNotSupported3:\n\t"
- "#movl $103, %0:\n\n\t"
- "\nNotSupported4:\n\t"
- "#movl $104, %0:\n\n\t"
- "\nNotSupported5:\n\t"
- "#movl $105, %0:\n\n\t"
- "\nNotSupported6:\n\t"
- "#movl $106, %0:\n\n\t"
- "\nNotSupported7:\n\t"
- "#movl $107, %0:\n\n\t"
- "movl $0, %0:\n\n\t"
-
- "Return:\n\t"
- : "=a" (rval)
- : /* no input */
- : "eax", "ebx", "ecx", "edx"
- );
-
- /* Return */
- return(rval);
-}
-
-/* Function to test if sse instructions are supported...
-*/
-inline extern int
-sse_ok(void)
-{
- /* Returns 1 if SSE instructions are supported, 0 otherwise */
- return ( (mm_support() & 0x8) >> 3 );
-}
-#endif
-
-
-
-/* Helper functions for the instruction macros that follow...
- (note that memory-to-register, m2r, instructions are nearly
- as efficient as register-to-register, r2r, instructions;
- however, memory-to-memory instructions are really simulated
- as a convenience, and are only 1/3 as efficient)
-*/
-#ifdef SSE_TRACE
-
-/* Include the stuff for printing a trace to stderr...
-*/
-
-#include <stdio.h>
-
-#define sse_i2r(op, imm, reg) \
- { \
- sse_t sse_trace; \
- sse_trace.uq = (imm); \
- fprintf(stderr, #op "_i2r(" #imm "=0x%08x%08x, ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%08x%08x) => ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (imm)); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%08x%08x\n", \
- sse_trace.d[1], sse_trace.d[0]); \
- }
-
-#define sse_m2r(op, mem, reg) \
- { \
- sse_t sse_trace; \
- sse_trace = (mem); \
- fprintf(stderr, #op "_m2r(" #mem "=0x%08x%08x, ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%08x%08x) => ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (mem)); \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #reg "=0x%08x%08x\n", \
- sse_trace.d[1], sse_trace.d[0]); \
- }
-
-#define sse_r2m(op, reg, mem) \
- { \
- sse_t sse_trace; \
- __asm__ __volatile__ ("movq %%" #reg ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #op "_r2m(" #reg "=0x%08x%08x, ", \
- sse_trace.d[1], sse_trace.d[0]); \
- sse_trace = (mem); \
- fprintf(stderr, #mem "=0x%08x%08x) => ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ (#op " %%" #reg ", %0" \
- : "=X" (mem) \
- : /* nothing */ ); \
- sse_trace = (mem); \
- fprintf(stderr, #mem "=0x%08x%08x\n", \
- sse_trace.d[1], sse_trace.d[0]); \
- }
-
-#define sse_r2r(op, regs, regd) \
- { \
- sse_t sse_trace; \
- __asm__ __volatile__ ("movq %%" #regs ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #op "_r2r(" #regs "=0x%08x%08x, ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ ("movq %%" #regd ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #regd "=0x%08x%08x) => ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ (#op " %" #regs ", %" #regd); \
- __asm__ __volatile__ ("movq %%" #regd ", %0" \
- : "=X" (sse_trace) \
- : /* nothing */ ); \
- fprintf(stderr, #regd "=0x%08x%08x\n", \
- sse_trace.d[1], sse_trace.d[0]); \
- }
-
-#define sse_m2m(op, mems, memd) \
- { \
- sse_t sse_trace; \
- sse_trace = (mems); \
- fprintf(stderr, #op "_m2m(" #mems "=0x%08x%08x, ", \
- sse_trace.d[1], sse_trace.d[0]); \
- sse_trace = (memd); \
- fprintf(stderr, #memd "=0x%08x%08x) => ", \
- sse_trace.d[1], sse_trace.d[0]); \
- __asm__ __volatile__ ("movq %0, %%mm0\n\t" \
- #op " %1, %%mm0\n\t" \
- "movq %%mm0, %0" \
- : "=X" (memd) \
- : "X" (mems)); \
- sse_trace = (memd); \
- fprintf(stderr, #memd "=0x%08x%08x\n", \
- sse_trace.d[1], sse_trace.d[0]); \
- }
-
-#else
-
-/* These macros are a lot simpler without the tracing...
-*/
-
-#define sse_i2r(op, imm, reg) \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (imm) )
-
-#define sse_m2r(op, mem, reg) \
- __asm__ __volatile__ (#op " %0, %%" #reg \
- : /* nothing */ \
- : "X" (mem))
-
-#define sse_r2m(op, reg, mem) \
- __asm__ __volatile__ (#op " %%" #reg ", %0" \
- : "=X" (mem) \
- : /* nothing */ )
-
-#define sse_r2r(op, regs, regd) \
- __asm__ __volatile__ (#op " %" #regs ", %" #regd)
-
-#define sse_r2ri(op, regs, regd, imm) \
- __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
- : /* nothing */ \
- : "X" (imm) )
-
-/* Load data from mems to xmmreg, operate on xmmreg, and store data to memd */
-#define sse_m2m(op, mems, memd, xmmreg) \
- __asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
- #op " %1, %%xmm0\n\t" \
- "movups %%mm0, %0" \
- : "=X" (memd) \
- : "X" (mems))
-
-#define sse_m2ri(op, mem, reg, subop) \
- __asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \
- : /* nothing */ \
- : "X" (mem))
-
-#define sse_m2mi(op, mems, memd, xmmreg, subop) \
- __asm__ __volatile__ ("movups %0, %%xmm0\n\t" \
- #op " %1, %%xmm0, " #subop "\n\t" \
- "movups %%mm0, %0" \
- : "=X" (memd) \
- : "X" (mems))
-#endif
-
-
-
-
-/* 1x128 MOVe Aligned four Packed Single-fp
-*/
-#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg)
-#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var)
-#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd)
-#define movaps(vars, vard) \
- __asm__ __volatile__ ("movaps %1, %%mm0\n\t" \
- "movaps %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* 1x128 MOVe aligned Non-Temporal four Packed Single-fp
-*/
-#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var)
-
-
-/* 1x64 MOVe Non-Temporal Quadword
-*/
-#define movntq_r2m(mmreg, var) sse_r2m(movntq, mmreg, var)
-
-
-/* 1x128 MOVe Unaligned four Packed Single-fp
-*/
-#define movups_m2r(var, reg) sse_m2r(movups, var, reg)
-#define movups_r2m(reg, var) sse_r2m(movups, reg, var)
-#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd)
-#define movups(vars, vard) \
- __asm__ __volatile__ ("movups %1, %%mm0\n\t" \
- "movups %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* MOVe High to Low Packed Single-fp
- high half of 4x32f (x) -> low half of 4x32f (y)
-*/
-#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd)
-
-
-/* MOVe Low to High Packed Single-fp
- low half of 4x32f (x) -> high half of 4x32f (y)
-*/
-#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd)
-
-
-/* MOVe High Packed Single-fp
- 2x32f -> high half of 4x32f
-*/
-#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg)
-#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var)
-#define movhps(vars, vard) \
- __asm__ __volatile__ ("movhps %1, %%mm0\n\t" \
- "movhps %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* MOVe Low Packed Single-fp
- 2x32f -> low half of 4x32f
-*/
-#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg)
-#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var)
-#define movlps(vars, vard) \
- __asm__ __volatile__ ("movlps %1, %%mm0\n\t" \
- "movlps %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* MOVe Scalar Single-fp
- lowest field of 4x32f (x) -> lowest field of 4x32f (y)
-*/
-#define movss_m2r(var, reg) sse_m2r(movss, var, reg)
-#define movss_r2m(reg, var) sse_r2m(movss, reg, var)
-#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd)
-#define movss(vars, vard) \
- __asm__ __volatile__ ("movss %1, %%mm0\n\t" \
- "movss %%mm0, %0" \
- : "=X" (vard) \
- : "X" (vars))
-
-
-/* 4x16 Packed SHUFfle Word
-*/
-#define pshufw_m2r(var, reg, index) sse_m2ri(pshufw, var, reg, index)
-#define pshufw_r2r(regs, regd, index) sse_r2ri(pshufw, regs, regd, index)
-
-
-/* 1x128 SHUFfle Packed Single-fp
-*/
-#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index)
-#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index)
-
-
-/* ConVerT Packed signed Int32 to(2) Packed Single-fp
-*/
-#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg)
-#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg)
-
-
-/* ConVerT Packed Single-fp to(2) Packed signed Int32
-*/
-#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg)
-#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg)
-
-
-/* ConVerT with Truncate Packed Single-fp to(2) Packed Int32
-*/
-#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg)
-#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg)
-
-
-/* ConVerT Signed Int32 to(2) Single-fp (Scalar)
-*/
-#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg)
-#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg)
-
-
-/* ConVerT Scalar Single-fp to(2) Signed Int32
-*/
-#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
-#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
-
-
-/* ConVerT with Truncate Scalar Single-fp to(2) Signed Int32
-*/
-#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
-#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
-
-
-/* Parallel EXTRact Word from 4x16
-*/
-#define pextrw_r2r(mmreg, reg, field) sse_r2ri(pextrw, mmreg, reg, field)
-
-
-/* Parallel INSeRt Word from 4x16
-*/
-#define pinsrw_r2r(reg, mmreg, field) sse_r2ri(pinsrw, reg, mmreg, field)
-
-
-
-/* MOVe MaSK from Packed Single-fp
-*/
-#ifdef SSE_TRACE
- #define movmskps(xmmreg, reg) \
- { \
- fprintf(stderr, "movmskps()\n"); \
- __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg) \
- }
-#else
- #define movmskps(xmmreg, reg) \
- __asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg)
-#endif
-
-
-/* Parallel MOVe MaSK from mmx reg to 32-bit reg
-*/
-#ifdef SSE_TRACE
- #define pmovmskb(mmreg, reg) \
- { \
- fprintf(stderr, "movmskps()\n"); \
- __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg) \
- }
-#else
- #define pmovmskb(mmreg, reg) \
- __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
-#endif
-
-
-/* MASKed MOVe from 8x8 to memory pointed to by (e)di register
-*/
-#define maskmovq(mmregs, fieldreg) sse_r2ri(maskmovq, mmregs, fieldreg)
-
-
-
-
-/* 4x32f Parallel ADDs
-*/
-#define addps_m2r(var, reg) sse_m2r(addps, var, reg)
-#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd)
-#define addps(vars, vard, xmmreg) sse_m2m(addps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel ADDs
-*/
-#define addss_m2r(var, reg) sse_m2r(addss, var, reg)
-#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd)
-#define addss(vars, vard, xmmreg) sse_m2m(addss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel SUBs
-*/
-#define subps_m2r(var, reg) sse_m2r(subps, var, reg)
-#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd)
-#define subps(vars, vard, xmmreg) sse_m2m(subps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel SUBs
-*/
-#define subss_m2r(var, reg) sse_m2r(subss, var, reg)
-#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd)
-#define subss(vars, vard, xmmreg) sse_m2m(subss, vars, vard, xmmreg)
-
-
-/* 8x8u -> 4x16u Packed Sum of Absolute Differences
-*/
-#define psadbw_m2r(var, reg) sse_m2r(psadbw, var, reg)
-#define psadbw_r2r(regs, regd) sse_r2r(psadbw, regs, regd)
-#define psadbw(vars, vard, mmreg) sse_m2m(psadbw, vars, vard, mmreg)
-
-
-/* 4x16u Parallel MUL High Unsigned
-*/
-#define pmulhuw_m2r(var, reg) sse_m2r(pmulhuw, var, reg)
-#define pmulhuw_r2r(regs, regd) sse_r2r(pmulhuw, regs, regd)
-#define pmulhuw(vars, vard, mmreg) sse_m2m(pmulhuw, vars, vard, mmreg)
-
-
-/* 4x32f Parallel MULs
-*/
-#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg)
-#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd)
-#define mulps(vars, vard, xmmreg) sse_m2m(mulps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel MULs
-*/
-#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg)
-#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd)
-#define mulss(vars, vard, xmmreg) sse_m2m(mulss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel DIVs
-*/
-#define divps_m2r(var, reg) sse_m2r(divps, var, reg)
-#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd)
-#define divps(vars, vard, xmmreg) sse_m2m(divps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel DIVs
-*/
-#define divss_m2r(var, reg) sse_m2r(divss, var, reg)
-#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd)
-#define divss(vars, vard, xmmreg) sse_m2m(divss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel Reciprocals
-*/
-#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg)
-#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd)
-#define rcpps(vars, vard, xmmreg) sse_m2m(rcpps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel Reciprocals
-*/
-#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg)
-#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd)
-#define rcpss(vars, vard, xmmreg) sse_m2m(rcpss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel Square Root of Reciprocals
-*/
-#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg)
-#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd)
-#define rsqrtps(vars, vard, xmmreg) sse_m2m(rsqrtps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel Square Root of Reciprocals
-*/
-#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg)
-#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd)
-#define rsqrtss(vars, vard, xmmreg) sse_m2m(rsqrtss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel Square Roots
-*/
-#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg)
-#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd)
-#define sqrtps(vars, vard, xmmreg) sse_m2m(sqrtps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel Square Roots
-*/
-#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg)
-#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd)
-#define sqrtss(vars, vard, xmmreg) sse_m2m(sqrtss, vars, vard, xmmreg)
-
-
-/* 8x8u and 4x16u Parallel AVeraGe
-*/
-#define pavgb_m2r(var, reg) sse_m2r(pavgb, var, reg)
-#define pavgb_r2r(regs, regd) sse_r2r(pavgb, regs, regd)
-#define pavgb(vars, vard, mmreg) sse_m2m(pavgb, vars, vard, mmreg)
-
-#define pavgw_m2r(var, reg) sse_m2r(pavgw, var, reg)
-#define pavgw_r2r(regs, regd) sse_r2r(pavgw, regs, regd)
-#define pavgw(vars, vard, mmreg) sse_m2m(pavgw, vars, vard, mmreg)
-
-
-/* 1x128 bitwise AND
-*/
-#define andps_m2r(var, reg) sse_m2r(andps, var, reg)
-#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd)
-#define andps(vars, vard, xmmreg) sse_m2m(andps, vars, vard, xmmreg)
-
-
-/* 1x128 bitwise AND with Not the destination
-*/
-#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg)
-#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd)
-#define andnps(vars, vard, xmmreg) sse_m2m(andnps, vars, vard, xmmreg)
-
-
-/* 1x128 bitwise OR
-*/
-#define orps_m2r(var, reg) sse_m2r(orps, var, reg)
-#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd)
-#define orps(vars, vard, xmmreg) sse_m2m(orps, vars, vard, xmmreg)
-
-
-/* 1x128 bitwise eXclusive OR
-*/
-#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg)
-#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd)
-#define xorps(vars, vard, xmmreg) sse_m2m(xorps, vars, vard, xmmreg)
-
-
-/* 8x8u, 4x16, and 4x32f Parallel Maximum
-*/
-#define pmaxub_m2r(var, reg) sse_m2r(pmaxub, var, reg)
-#define pmaxub_r2r(regs, regd) sse_r2r(pmaxub, regs, regd)
-#define pmaxub(vars, vard, mmreg) sse_m2m(pmaxub, vars, vard, mmreg)
-
-#define pmaxsw_m2r(var, reg) sse_m2r(pmaxsw, var, reg)
-#define pmaxsw_r2r(regs, regd) sse_r2r(pmaxsw, regs, regd)
-#define pmaxsw(vars, vard, mmreg) sse_m2m(pmaxsw, vars, vard, mmreg)
-
-#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg)
-#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd)
-#define maxps(vars, vard, xmmreg) sse_m2m(maxps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel Maximum
-*/
-#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg)
-#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd)
-#define maxss(vars, vard, xmmreg) sse_m2m(maxss, vars, vard, xmmreg)
-
-
-/* 8x8u, 4x16, and 4x32f Parallel Minimum
-*/
-#define pminub_m2r(var, reg) sse_m2r(pminub, var, reg)
-#define pminub_r2r(regs, regd) sse_r2r(pminub, regs, regd)
-#define pminub(vars, vard, mmreg) sse_m2m(pminub, vars, vard, mmreg)
-
-#define pminsw_m2r(var, reg) sse_m2r(pminsw, var, reg)
-#define pminsw_r2r(regs, regd) sse_r2r(pminsw, regs, regd)
-#define pminsw(vars, vard, mmreg) sse_m2m(pminsw, vars, vard, mmreg)
-
-#define minps_m2r(var, reg) sse_m2r(minps, var, reg)
-#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd)
-#define minps(vars, vard, xmmreg) sse_m2m(minps, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Parallel Minimum
-*/
-#define minss_m2r(var, reg) sse_m2r(minss, var, reg)
-#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd)
-#define minss(vars, vard, xmmreg) sse_m2m(minss, vars, vard, xmmreg)
-
-
-/* 4x32f Parallel CoMPares
- (resulting fields are either 0 or -1)
-*/
-#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op)
-#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op)
-#define cmpps(vars, vard, op, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, op)
-
-#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0)
-#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0)
-#define cmpeqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 0)
-
-#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1)
-#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1)
-#define cmpltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 1)
-
-#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2)
-#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2)
-#define cmpleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 2)
-
-#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3)
-#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3)
-#define cmpunordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 3)
-
-#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4)
-#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4)
-#define cmpneqps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 4)
-
-#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5)
-#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5)
-#define cmpnltps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 5)
-
-#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6)
-#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6)
-#define cmpnleps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 6)
-
-#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7)
-#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7)
-#define cmpordps(vars, vard, xmmreg) sse_m2mi(cmpps, vars, vard, xmmreg, 7)
-
-
-/* Lowest Field of 4x32f Parallel CoMPares
- (resulting fields are either 0 or -1)
-*/
-#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op)
-#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op)
-#define cmpss(vars, vard, op, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, op)
-
-#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0)
-#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0)
-#define cmpeqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 0)
-
-#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1)
-#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1)
-#define cmpltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 1)
-
-#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2)
-#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2)
-#define cmpless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 2)
-
-#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3)
-#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3)
-#define cmpunordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 3)
-
-#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4)
-#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4)
-#define cmpneqss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 4)
-
-#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5)
-#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5)
-#define cmpnltss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 5)
-
-#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6)
-#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6)
-#define cmpnless(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 6)
-
-#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7)
-#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7)
-#define cmpordss(vars, vard, xmmreg) sse_m2mi(cmpss, vars, vard, xmmreg, 7)
-
-
-/* Lowest Field of 4x32f Parallel CoMPares to set EFLAGS
- (resulting fields are either 0 or -1)
-*/
-#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg)
-#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd)
-#define comiss(vars, vard, xmmreg) sse_m2m(comiss, vars, vard, xmmreg)
-
-
-/* Lowest Field of 4x32f Unordered Parallel CoMPares to set EFLAGS
- (resulting fields are either 0 or -1)
-*/
-#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg)
-#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd)
-#define ucomiss(vars, vard, xmmreg) sse_m2m(ucomiss, vars, vard, xmmreg)
-
-
-/* 2-(4x32f) -> 4x32f UNPaCK Low Packed Single-fp
- (interleaves low half of dest with low half of source
- as padding in each result field)
-*/
-#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg)
-#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd)
-
-
-/* 2-(4x32f) -> 4x32f UNPaCK High Packed Single-fp
- (interleaves high half of dest with high half of source
- as padding in each result field)
-*/
-#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg)
-#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd)
-
-
-
-/* Fp and mmX ReSTORe state
-*/
-#ifdef SSE_TRACE
- #define fxrstor(mem) \
- { \
- fprintf(stderr, "fxrstor()\n"); \
- __asm__ __volatile__ ("fxrstor %0" \
- : /* nothing */ \
- : "X" (mem)) \
- }
-#else
- #define fxrstor(mem) \
- __asm__ __volatile__ ("fxrstor %0" \
- : /* nothing */ \
- : "X" (mem))
-#endif
-
-
-/* Fp and mmX SAVE state
-*/
-#ifdef SSE_TRACE
- #define fxsave(mem) \
- { \
- fprintf(stderr, "fxsave()\n"); \
- __asm__ __volatile__ ("fxsave %0" \
- : /* nothing */ \
- : "X" (mem)) \
- }
-#else
- #define fxsave(mem) \
- __asm__ __volatile__ ("fxsave %0" \
- : /* nothing */ \
- : "X" (mem))
-#endif
-
-
-/* STore streaMing simd eXtensions Control/Status Register
-*/
-#ifdef SSE_TRACE
- #define stmxcsr(mem) \
- { \
- fprintf(stderr, "stmxcsr()\n"); \
- __asm__ __volatile__ ("stmxcsr %0" \
- : /* nothing */ \
- : "X" (mem)) \
- }
-#else
- #define stmxcsr(mem) \
- __asm__ __volatile__ ("stmxcsr %0" \
- : /* nothing */ \
- : "X" (mem))
-#endif
-
-
-/* LoaD streaMing simd eXtensions Control/Status Register
-*/
-#ifdef SSE_TRACE
- #define ldmxcsr(mem) \
- { \
- fprintf(stderr, "ldmxcsr()\n"); \
- __asm__ __volatile__ ("ldmxcsr %0" \
- : /* nothing */ \
- : "X" (mem)) \
- }
-#else
- #define ldmxcsr(mem) \
- __asm__ __volatile__ ("ldmxcsr %0" \
- : /* nothing */ \
- : "X" (mem))
-#endif
-
-
-/* Store FENCE - enforce ordering of stores before fence vs. stores
- occuring after fence in source code.
-*/
-#ifdef SSE_TRACE
- #define sfence() \
- { \
- fprintf(stderr, "sfence()\n"); \
- __asm__ __volatile__ ("sfence\n\t") \
- }
-#else
- #define sfence() \
- __asm__ __volatile__ ("sfence\n\t")
-#endif
-
-
-/* PREFETCH data using T0, T1, T2, or NTA hint
- T0 = Prefetch into all cache levels
- T1 = Prefetch into all cache levels except 0th level
- T2 = Prefetch into all cache levels except 0th and 1st levels
- NTA = Prefetch data into non-temporal cache structure
-*/
-#ifdef SSE_TRACE
-#else
- #define prefetch(mem, hint) \
- __asm__ __volatile__ ("prefetch" #hint " %0" \
- : /* nothing */ \
- : "X" (mem))
-
- #define prefetcht0(mem) prefetch(mem, t0)
- #define prefetcht1(mem) prefetch(mem, t1)
- #define prefetcht2(mem) prefetch(mem, t2)
- #define prefetchnta(mem) prefetch(mem, nta)
-#endif
-
-
-
-#endif
diff --git a/gst/deinterlace2/tvtime/tomsmocomp.c b/gst/deinterlace2/tvtime/tomsmocomp.c
deleted file mode 100644
index 64e78c5b..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include "_stdint.h"
-#include <string.h>
-
-#include "gst/gst.h"
-#include "gstdeinterlace2.h"
-#include "plugins.h"
-
-#define GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP (gst_deinterlace_method_tomsmocomp_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP))
-#define GST_IS_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP))
-#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass))
-#define GST_DEINTERLACE_METHOD_TOMSMOCOMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoComp))
-#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_TOMSMOCOMP, GstDeinterlaceMethodTomsMoCompClass))
-#define GST_DEINTERLACE_METHOD_TOMSMOCOMP_CAST(obj) ((GstDeinterlaceMethodTomsMoComp*)(obj))
-
-GType gst_deinterlace_method_tomsmocomp_get_type (void);
-
-typedef struct
-{
- GstDeinterlaceMethod parent;
-
- guint search_effort;
- gboolean strange_bob;
-} GstDeinterlaceMethodTomsMoComp;
-
-typedef struct
-{
- GstDeinterlaceMethodClass parent_class;
-} GstDeinterlaceMethodTomsMoCompClass;
-
-static int
-Fieldcopy (void *dest, const void *src, size_t count,
- int rows, int dst_pitch, int src_pitch)
-{
- unsigned char *pDest = (unsigned char *) dest;
- unsigned char *pSrc = (unsigned char *) src;
-
- int i;
-
- for (i = 0; i < rows; i++) {
- oil_memcpy (pDest, pSrc, count);
- pSrc += src_pitch;
- pDest += dst_pitch;
- }
- return 0;
-}
-
-#define USE_FOR_DSCALER
-
-#define IS_C
-#define SIMD_TYPE C
-#define FUNCT_NAME tomsmocompDScaler_C
-#include "tomsmocomp/TomsMoCompAll.inc"
-#undef IS_C
-#undef SIMD_TYPE
-#undef FUNCT_NAME
-
-#ifdef BUILD_X86_ASM
-
-#include "tomsmocomp/tomsmocompmacros.h"
-#include "x86-64_macros.inc"
-
-#define IS_MMX
-#define SIMD_TYPE MMX
-#define FUNCT_NAME tomsmocompDScaler_MMX
-#include "tomsmocomp/TomsMoCompAll.inc"
-#undef IS_MMX
-#undef SIMD_TYPE
-#undef FUNCT_NAME
-
-#define IS_3DNOW
-#define SIMD_TYPE 3DNOW
-#define FUNCT_NAME tomsmocompDScaler_3DNOW
-#include "tomsmocomp/TomsMoCompAll.inc"
-#undef IS_3DNOW
-#undef SIMD_TYPE
-#undef FUNCT_NAME
-
-#define IS_MMXEXT
-#define SIMD_TYPE MMXEXT
-#define FUNCT_NAME tomsmocompDScaler_MMXEXT
-#include "tomsmocomp/TomsMoCompAll.inc"
-#undef IS_MMXEXT
-#undef SIMD_TYPE
-#undef FUNCT_NAME
-
-#endif
-
-G_DEFINE_TYPE (GstDeinterlaceMethodTomsMoComp,
- gst_deinterlace_method_tomsmocomp, GST_TYPE_DEINTERLACE_METHOD);
-
-enum
-{
- ARG_0,
- ARG_SEARCH_EFFORT,
- ARG_STRANGE_BOB
-};
-
-static void
-gst_deinterlace_method_tomsmocomp_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodTomsMoComp *self =
- GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
-
- switch (prop_id) {
- case ARG_SEARCH_EFFORT:
- self->search_effort = g_value_get_uint (value);
- break;
- case ARG_STRANGE_BOB:
- self->strange_bob = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-gst_deinterlace_method_tomsmocomp_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstDeinterlaceMethodTomsMoComp *self =
- GST_DEINTERLACE_METHOD_TOMSMOCOMP (object);
-
- switch (prop_id) {
- case ARG_SEARCH_EFFORT:
- g_value_set_uint (value, self->search_effort);
- break;
- case ARG_STRANGE_BOB:
- g_value_set_boolean (value, self->strange_bob);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
- gst_deinterlace_method_tomsmocomp_class_init
- (GstDeinterlaceMethodTomsMoCompClass * klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GObjectClass *gobject_class = (GObjectClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- gobject_class->set_property = gst_deinterlace_method_tomsmocomp_set_property;
- gobject_class->get_property = gst_deinterlace_method_tomsmocomp_get_property;
-
- g_object_class_install_property (gobject_class, ARG_SEARCH_EFFORT,
- g_param_spec_uint ("search-effort",
- "Search Effort",
- "Search Effort", 0, 27, 5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- g_object_class_install_property (gobject_class, ARG_STRANGE_BOB,
- g_param_spec_boolean ("strange-bob",
- "Strange Bob",
- "Use strange bob", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
- );
-
- dim_class->fields_required = 4;
- dim_class->name = "Motion Adaptive: Motion Search";
- dim_class->nick = "tomsmocomp";
- dim_class->latency = 1;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMXEXT) {
- dim_class->deinterlace_frame = tomsmocompDScaler_MMXEXT;
- } else if (cpu_flags & OIL_IMPL_FLAG_3DNOW) {
- dim_class->deinterlace_frame = tomsmocompDScaler_3DNOW;
- } else if (cpu_flags & OIL_IMPL_FLAG_MMX) {
- dim_class->deinterlace_frame = tomsmocompDScaler_MMX;
- } else {
- dim_class->deinterlace_frame = tomsmocompDScaler_C;
- }
-#else
- dim_class->deinterlace_frame = tomsmocompDScaler_C;
-#endif
-}
-
-static void
-gst_deinterlace_method_tomsmocomp_init (GstDeinterlaceMethodTomsMoComp * self)
-{
- self->search_effort = 5;
- self->strange_bob = FALSE;
-}
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc
deleted file mode 100644
index b1d9aeca..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoop0A.inc
+++ /dev/null
@@ -1,15 +0,0 @@
-// -*- c++ -*-
-
-// Searches just the center pixel, in both the old
-// and new fields, but takes averages. This is an even
-// pixel address. Any chroma match will be used. (YUY2)
-// We best like finding 0 motion so we will bias everything we found previously
-// up by a little, and adjust later
-
-#ifdef IS_SSE2
- "paddusb "_ONES", %%xmm7\n\t" // bias toward no motion
-#else
- "paddusb "_ONES", %%mm7\n\t" // bias toward no motion
-#endif
-
- MERGE4PIXavg("(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")") // center, in old and new
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc
deleted file mode 100644
index e1560353..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopBottom.inc
+++ /dev/null
@@ -1,174 +0,0 @@
-// -*- c++ -*-
-
-// Version for non-SSE2
-
-#ifndef IS_C
-
-#ifdef SKIP_SEARCH
- "movq %%mm6, %%mm0\n\t" // just use the results of our wierd bob
-#else
-
-
- // JA 9/Dec/2002
- // failed experiment
- // but leave in placeholder for me to play about
-#ifdef DONT_USE_STRANGE_BOB
- // Use the best weave if diffs less than 10 as that
- // means the image is still or moving cleanly
- // if there is motion we will clip which will catch anything
- "psubusb "_FOURS", %%mm7\n\t" // sets bits to zero if weave diff < 4
- "pxor %%mm0, %%mm0\n\t"
- "pcmpeqb %%mm0, %%mm7\n\t" // all ff where weave better, else 00
- "pcmpeqb %%mm7, %%mm0\n\t" // all ff where bob better, else 00
- "pand %%mm6, %%mm0\n\t" // use bob for these pixel values
- "pand %%mm5, %%mm7\n\t" // use weave for these
- "por %%mm7, %%mm0\n\t" // combine both
-#else
- // Use the better of bob or weave
- // pminub mm4, TENS // the most we care about
- V_PMINUB ("%%mm4", _TENS, "%%mm0") // the most we care about
-
- "psubusb %%mm4, %%mm7\n\t" // foregive that much from weave est?
- "psubusb "_FOURS", %%mm7\n\t" // bias it a bit toward weave
- "pxor %%mm0, %%mm0\n\t"
- "pcmpeqb %%mm0, %%mm7\n\t" // all ff where weave better, else 00
- "pcmpeqb %%mm7, %%mm0\n\t" // all ff where bob better, else 00
- "pand %%mm6, %%mm0\n\t" // use bob for these pixel values
- "pand %%mm5, %%mm7\n\t" // use weave for these
- "por %%mm7, %%mm0\n\t" // combine both
-#endif
-
-
- // pminub mm0, Max_Vals // but clip to catch the stray error
- V_PMINUB ("%%mm0", _Max_Vals, "%%mm1") // but clip to catch the stray error
- // pmaxub mm0, Min_Vals
- V_PMAXUB ("%%mm0", _Min_Vals)
-
-#endif
-
-
- MOVX" "_pDest", %%"XAX"\n\t"
-
-#ifdef USE_VERTICAL_FILTER
- "movq %%mm0, %%mm1\n\t"
- // pavgb mm0, qword ptr["XBX"]
- V_PAVGB ("%%mm0", "(%%"XBX")", "%%mm2", _ShiftMask)
- // movntq qword ptr["XAX"+"XDX"], mm0
- V_MOVNTQ ("(%"XAX", %%"XDX")", "%%mm0")
- // pavgb mm1, qword ptr["XBX"+"XCX"]
- V_PAVGB ("%%mm1", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask)
- //FIXME: XDX or XAX!!
- "addq "_dst_pitchw", %%"XBX
- // movntq qword ptr["XAX"+"XDX"], mm1
- V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm1")
-#else
-
- // movntq qword ptr["XAX"+"XDX"], mm0
- V_MOVNTQ ("(%%"XAX", %%"XDX")", "%%mm0")
-#endif
-
- LEAX" 8(%%"XDX"), %%"XDX"\n\t" // bump offset pointer
- CMPX" "_Last8", %%"XDX"\n\t" // done with line?
- "jb 1b\n\t" // y
-
- MOVX" "_oldbx", %%"XBX"\n\t"
-
- : /* no outputs */
-
- : "m"(pBob),
- "m"(src_pitch2),
- "m"(ShiftMask),
- "m"(pDest),
- "m"(dst_pitchw),
- "m"(Last8),
- "m"(pSrc),
- "m"(pSrcP),
- "m"(pBobP),
- "m"(DiffThres),
- "m"(Min_Vals),
- "m"(Max_Vals),
- "m"(FOURS),
- "m"(TENS),
- "m"(ONES),
- "m"(UVMask),
- "m"(Max_Mov),
- "m"(YMask),
- "m"(oldbx)
-
- : XAX, XCX, XDX, XSI, XDI,
- "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)",
-#ifdef __MMX__
- "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
-#endif
- "memory", "cc"
- );
-
- // adjust for next line
- pSrc += src_pitch2;
- pSrcP += src_pitch2;
- pDest += dst_pitch2;
- pBob += src_pitch2;
- pBobP += src_pitch2;
- }
-
- return 0;
-#else
-#ifdef SKIP_SEARCH
- out[0] = best[0]; // just use the results of our wierd bob
- out[1] = best[1];
-#else
- diff[0] = diff[0] - MIN (diff[0], 10) - 4;
- diff[1] = diff[1] - MIN (diff[1] - 10) - 4;
- if (diff[0] < 0)
- out[0] = weave[0];
- else
- out[0] = best[0];
-
- if (diff[1] < 0)
- out[1] = weave[1];
- else
- out[1] = best[1];
-
-
- out[0] = CLAMP (out[0], MinVals[0], MaxVals[0]);
- out[1] = CLAMP (out[1], MinVals[1], MaxVals[1]);
-#endif
-
-#ifdef USE_VERTICAL_FILTER
- pDest[x] = (out[0] + pBob[0]) / 2;
- pDest[x + dst_pitchw] = (pBob[src_pitch2] + out[0]) / 2;
- pDest[x + 1] = (out[1] + pBob[1]) / 2;
- pDest[x + 1 + dst_pitchw] = (pBob[src_pitch2 + 1] + out[1]) / 2;
-#else
- pDest[x] = out[0];
- pDest[x+1] = out[1];
-#endif
- pBob += 2;
- pBobP += 2;
- pSrc += 2;
- pSrcP += 2;
- }
- // adjust for next line
- pSrc = src_pitch2 * (y+1) + pWeaveSrc;
- pSrcP = src_pitch2 * (y+1) + pWeaveSrcP;
- pDest = dst_pitch2 * (y+1) + pWeaveDest + dst_pitch2;
-
-
- if (TopFirst)
- {
- pBob = pCopySrc + src_pitch2;
- pBobP = pCopySrcP + src_pitch2;
- }
- else
- {
- pBob = pCopySrc;
- pBobP = pCopySrcP;
- }
-
- pBob += src_pitch2 * (y+1);
- pBobP += src_pitch2 * (y+1);
- }
-
- return 0;
-
-#endif
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc
deleted file mode 100644
index 6208fe8c..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-// -*- c++ -*-
-
-// Searches 2 pixel to the left and right, in both the old
-// and new fields, but takes averages. These are even
-// pixel addresses. Chroma match will be used. (YUY2)
- MERGE4PIXavg("-4(%%"XDI")", "4(%%"XSI", %%"XCX", 2)") // up left, down right
- MERGE4PIXavg("4(%%"XDI")", "-4(%%"XSI", %%"XCX", 2)") // up right, down left
- MERGE4PIXavg("-4(%%"XDI", %%"XCX")", "4(%%"XSI", %%"XCX")") // left, right
- MERGE4PIXavg("4(%%"XDI", %%"XCX")", "-4(%%"XSI", %%"XCX")") // right, left
- MERGE4PIXavg("-4(%%"XDI", %%"XCX", 2)", "4(%%"XSI")") // down left, up right
- MERGE4PIXavg("4(%%"XDI", %%"XCX", 2)", "-4(%%"XSI")") // down right, up left
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc
deleted file mode 100644
index 2841c3f6..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopEdgeA8.inc
+++ /dev/null
@@ -1,12 +0,0 @@
-// -*- c++ -*-
-
-// Searches 4 pixel to the left and right, in both the old
-// and new fields, but takes averages. These are even
-// pixel addresses. Chroma match will be used. (YUY2)
- MERGE4PIXavg("-8(%%"XDI")", "8(%%"XSI", %%"XCX", 2)") // up left, down right
- MERGE4PIXavg("8(%%"XDI")", "-8(%%"XSI", %%"XCX", 2)") // up right, down left
- MERGE4PIXavg("-8(%%"XDI", %%"XCX")", "8(%%"XSI", %%"XCX")") // left, right
- MERGE4PIXavg("8(%%"XDI", %%"XCX")", "-8(%%"XSI", %%"XCX")") // right, left
- MERGE4PIXavg("-8(%%"XDI", %%"XCX", 2)", "8(%%"XSI")") // down left, up right
- MERGE4PIXavg("8(%%"XDI", %%"XCX", 2)", "-8(%%"XSI")") // down right, up left
-
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc
deleted file mode 100644
index ab5375f4..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-// -*- c++ -*-
-
-// Searches 1 pixel to the left and right, in both the old
-// and new fields, but takes averages. These are odd
-// pixel addresses. Any chroma match will not be used. (YUY2)
- MERGE4PIXavg("-2(%%"XDI")", "2(%%"XSI", %%"XCX", 2)") // up left, down right
- MERGE4PIXavg("2(%%"XDI")", "-2(%%"XSI", %%"XCX", 2)") // up right, down left
- MERGE4PIXavg("-2(%%"XDI", %%"XCX", 2)", "2(%%"XSI")") // down left, up right
- MERGE4PIXavg("2(%%"XDI", %%"XCX", 2)", "-2(%%"XSI")") // down right, up left
-#include "SearchLoopOddA2.inc"
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc
deleted file mode 100644
index fd3f6fb0..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA2.inc
+++ /dev/null
@@ -1,5 +0,0 @@
-// Searches 1 pixel to the left and right, in both the old
-// and new fields, but takes averages. These are odd
-// pixel addresses. Any chroma match will not be used. (YUY2)
- MERGE4PIXavg("-2(%%"XDI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right
- MERGE4PIXavg("2(%%"XDI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc
deleted file mode 100644
index cbae014e..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddA6.inc
+++ /dev/null
@@ -1,11 +0,0 @@
-// -*- c++ -*-
-
-// Searches 3 pixels to the left and right, in both the old
-// and new fields, but takes averages. These are odd
-// pixel addresses. Any chroma match will not be used. (YUY2)
- MERGE4PIXavg("-6(%%"XDI")", "6(%%"XSI", %%"XCX", 2)") // up left, down right
- MERGE4PIXavg("6(%%"XDI")", "-6(%%"XSI", %%"XCX", 2)") // up right, down left
- MERGE4PIXavg("-6(%%"XDI", %%"XCX")", "6(%%"XSI", %%"XCX")") // left, right
- MERGE4PIXavg("6(%%"XDI", %%"XCX")", "-6(%%"XSI", %%"XCX")") // right, left
- MERGE4PIXavg("-6(%%"XDI", %%"XCX", 2)", "6(%%"XSI")") // down left, up right
- MERGE4PIXavg("6(%%"XDI", %%"XCX", 2)", "-6(%%"XSI")") // down right, up left
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc
deleted file mode 100644
index e59e3c7e..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH.inc
+++ /dev/null
@@ -1,10 +0,0 @@
-// Searches 1 pixel to the left and right, in both the old
-// and new fields, but takes v-half pel averages. These are odd
-// pixel addresses. Any chroma match will not be used. (YUY2)
- __asm
- {
- MERGE4PIXavgH("XDI"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2*"XCX"+2) // up left, down right
- MERGE4PIXavgH("XDI"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"+2*"XCX"-2) // up right, down left
- MERGE4PIXavgH("XDI"+2*"XCX"-2, "XDI"+"XCX"-2, "XSI"+"XCX"+2, "XSI"+2) // down left, up right
- MERGE4PIXavgH("XDI"+2*"XCX"+2, "XDI"+"XCX"+2, "XSI"+"XCX"-2, "XSI"-2) // down right, up left
- }
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc
deleted file mode 100644
index cd7d812a..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopOddAH2.inc
+++ /dev/null
@@ -1,5 +0,0 @@
-// Searches 1 pixel to the left and right, in both the old
-// and new fields, but takes vertical averages. These are odd
-// pixel addresses. Any chroma match will not be used. (YUY2)
- MERGE4PIXavgH("-2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "2(%%"XSI", %%"XCX")") // left, right
- MERGE4PIXavgH("2(%%"XDI", %%"XCX")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "-2(%%"XSI", %%"XCX")") // right, left
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc
deleted file mode 100644
index 9d6a490f..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopTop.inc
+++ /dev/null
@@ -1,254 +0,0 @@
-// -*- c++ -*-
-
-unsigned char* pDest;
-const unsigned char* pSrcP;
-const unsigned char* pSrc;
-const unsigned char* pBob;
-const unsigned char* pBobP;
-
-// long is int32 on ARCH_368, int64 on ARCH_AMD64. Declaring it this way
-// saves a lot of xor's to delete 64bit garbage.
-
-#if defined(DBL_RESIZE) || defined(USE_FOR_DSCALER)
-long src_pitch2 = src_pitch; // even & odd lines are not interleaved in DScaler
-#else
-long src_pitch2 = 2 * src_pitch; // even & odd lines are interleaved in Avisynth
-#endif
-
-
-long dst_pitch2 = 2 * dst_pitch;
-long y;
-
-long Last8;
-
- pSrc = pWeaveSrc; // points 1 weave line above
- pSrcP = pWeaveSrcP; // "
-
-#ifdef DBL_RESIZE
-
-#ifdef USE_VERTICAL_FILTER
- pDest = pWeaveDest + dst_pitch2;
-#else
- pDest = pWeaveDest + 3*dst_pitch;
-#endif
-
-#else
-
-#ifdef USE_VERTICAL_FILTER
- pDest = pWeaveDest + dst_pitch;
-#else
- pDest = pWeaveDest + dst_pitch2;
-#endif
-
-#endif
-
- if (TopFirst)
- {
- pBob = pCopySrc + src_pitch2; // remember one weave line just copied previously
- pBobP = pCopySrcP + src_pitch2;
- }
- else
- {
- pBob = pCopySrc;
- pBobP = pCopySrcP;
- }
-
-#ifndef IS_C
-
-#ifndef _pBob
-#define _pBob "%0"
-#define _src_pitch2 "%1"
-#define _ShiftMask "%2"
-#define _pDest "%3"
-#define _dst_pitchw "%4"
-#define _Last8 "%5"
-#define _pSrc "%6"
-#define _pSrcP "%7"
-#define _pBobP "%8"
-#define _DiffThres "%9"
-#define _Min_Vals "%10"
-#define _Max_Vals "%11"
-#define _FOURS "%12"
-#define _TENS "%13"
-#define _ONES "%14"
-#define _UVMask "%15"
-#define _Max_Mov "%16"
-#define _YMask "%17"
-#define _oldbx "%18"
-#endif
- Last8 = (rowsize-8);
-
- for (y=1; y < FldHeight-1; y++)
- {
- long dst_pitchw = dst_pitch; // local stor so asm can ref
- int64_t Max_Mov = 0x0404040404040404ull;
- int64_t DiffThres = 0x0f0f0f0f0f0f0f0full;
- int64_t YMask = 0x00ff00ff00ff00ffull; // keeps only luma
- int64_t UVMask = 0xff00ff00ff00ff00ull; // keeps only chroma
- int64_t TENS = 0x0a0a0a0a0a0a0a0aull;
- int64_t FOURS = 0x0404040404040404ull;
- int64_t ONES = 0x0101010101010101ull;
- int64_t Min_Vals = 0x0000000000000000ull;
- int64_t Max_Vals = 0x0000000000000000ull;
- int64_t ShiftMask = 0xfefffefffefffeffull;
-
- long oldbx;
-
- // pretend it's indented -->>
- __asm__ __volatile__
- (
- // Loop general reg usage
- //
- // XAX - pBobP, then pDest
- // XBX - pBob
- // XCX - src_pitch2
- // XDX - current offset
- // XDI - prev weave pixels, 1 line up
- // XSI - next weave pixels, 1 line up
-
- // Save "XBX" (-fPIC)
- MOVX" %%"XBX", "_oldbx"\n\t"
-
- // simple bob first 8 bytes
- MOVX" "_pBob", %%"XBX"\n\t"
- MOVX" "_src_pitch2", %%"XCX"\n\t"
-
-#ifdef USE_VERTICAL_FILTER
- "movq (%%"XBX"), %%mm0\n\t"
- "movq (%%"XBX", %%"XCX"), %%mm1\n\t" //, qword ptr["XBX"+"XCX"]
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // halfway between
- V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask) // 1/4 way
- V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask) // 3/4 way
- MOVX" "_pDest", %%"XDI"\n\t"
- MOVX" "_dst_pitchw", %%"XAX"\n\t"
- V_MOVNTQ ("(%%"XDI")", "%%mm0")
- V_MOVNTQ ("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1
-
- // simple bob last 8 bytes
- MOVX" "_Last8", %%"XDX"\n\t"
- LEAX" (%%"XBX", %%"XDX"), %%"XSI"\n\t" // ["XBX"+"XDX"]
- "movq (%%"XSI"), %%mm0\n\t"
- "movq (%%"XSI", %%"XCX"), %%mm1\n\t" // qword ptr["XSI"+"XCX"]
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // halfway between
- V_PAVGB ("%%mm0", "%%mm2", "%%mm3", _ShiftMask) // 1/4 way
- V_PAVGB ("%%mm1", "%%mm2", "%%mm3", _ShiftMask) // 3/4 way
- ADDX" %%"XDX", %%"XDI"\n\t" // last 8 bytes of dest
- V_MOVNTQ ("%%"XDI"", "%%mm0")
- V_MOVNTQ ("(%%"XDI", %%"XAX")", "%%mm1") // qword ptr["XDI"+"XAX"], mm1)
-
-#else
- "movq (%%"XBX"), %%mm0\n\t"
- // pavgb mm0, qword ptr["XBX"+"XCX"]
- V_PAVGB ("%%mm0", "(%%"XBX", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XBX"+"XCX"], mm2, ShiftMask)
- MOVX" "_pDest", %%"XDI"\n\t"
- V_MOVNTQ ("(%%"XDI")", "%%mm0")
-
- // simple bob last 8 bytes
- MOVX" "_Last8", %%"XDX"\n\t"
- LEAX" (%%"XBX", %%"XDX"), %%"XSI"\n\t" //"XSI", ["XBX"+"XDX"]
- "movq (%%"XSI"), %%mm0\n\t"
- // pavgb mm0, qword ptr["XSI"+"XCX"]
- V_PAVGB ("%%mm0", "(%%"XSI", %%"XCX")", "%%mm2", _ShiftMask) // qword ptr["XSI"+"XCX"], mm2, ShiftMask)
- V_MOVNTQ ("(%%"XDI", %%"XDX")", "%%mm0") // qword ptr["XDI"+"XDX"], mm0)
-#endif
- // now loop and get the middle qwords
- MOVX" "_pSrc", %%"XSI"\n\t"
- MOVX" "_pSrcP", %%"XDI"\n\t"
- MOVX" $8, %%"XDX"\n\t" // curr offset longo all lines
-
- "1:\n\t"
- MOVX" "_pBobP", %%"XAX"\n\t"
- ADDX" $8, %%"XDI"\n\t"
- ADDX" $8, %%"XSI"\n\t"
- ADDX" $8, %%"XBX"\n\t"
- ADDX" %%"XDX", %%"XAX"\n\t"
-
-#ifdef USE_STRANGE_BOB
-#include "StrangeBob.inc"
-#else
-#include "WierdBob.inc"
-#endif
-
- // For non-SSE2:
- // through out most of the rest of this loop we will maintain
- // mm4 our min bob value
- // mm5 best weave pixels so far
- // mm6 our max Bob value
- // mm7 best weighted pixel ratings so far
-
- // We will keep a slight bias to using the weave pixels
- // from the current location, by rating them by the min distance
- // from the Bob value instead of the avg distance from that value.
- // our best and only rating so far
- "pcmpeqb %%mm7, %%mm7\n\t" // ffff, say we didn't find anything good yet
-
-#else
- Last8 = (rowsize - 4);
-
- for (y=1; y < FldHeight-1; y++)
- {
- #ifdef USE_STRANGE_BOB
- long DiffThres = 0x0f;
- #endif
-
- #ifndef SKIP_SEARCH
- long weave[2], MaxVals[2], MinVals[2];
- #endif
-
- long diff[2], best[2], avg[2], diff2[2], out[2], x;
-
-#ifdef USE_VERTICAL_FILTER
- pDest[0] = (3 * pBob[0] + pBob[src_pitch2]) / 4;
- pDest[1] = (3 * pBob[1] + pBob[src_pitch2 + 1]) / 4;
- pDest[2] = (3 * pBob[2] + pBob[src_pitch2 + 2]) / 4;
- pDest[3] = (3 * pBob[3] + pBob[src_pitch2 + 3]) / 4;
- pDest[dst_pitchw] = (pBob[0] + 3 * pBob[src_pitch2]) / 4;
- pDest[dst_pitchw + 1] = (pBob[1] + 3 * pBob[src_pitch2 + 1]) / 4;
- pDest[dst_pitchw + 2] = (pBob[2] + 3 * pBob[src_pitch2 + 2]) / 4;
- pDest[dst_pitchw + 3] = (pBob[3] + 3 * pBob[src_pitch2 + 3]) / 4;
-
- // simple bob last byte
- pDest[Last8] = (3 * pBob[Last8] + pBob[Last8 + src_pitch2]) / 4;
- pDest[Last8 + 1] = (3 * pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 4;
- pDest[Last8 + 2] = (3 * pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 4;
- pDest[Last8 + 3] = (3 * pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 4;
- pDest[Last8 + src_pitch2] = (pBob[Last8] + 3 * pBob[Last8 + src_pitch2]) / 4;
- pDest[Last8 + src_pitch2 + 1] = (pBob[Last8 + 1] + 3 * pBob[Last8 + src_pitch2 + 1]) / 4;
- pDest[Last8 + src_pitch2 + 2] = (pBob[Last8 + 2] + 3 * pBob[Last8 + src_pitch2 + 2]) / 4;
- pDest[Last8 + src_pitch2 + 3] = (pBob[Last8 + 3] + 3 * pBob[Last8 + src_pitch2 + 3]) / 4;
-#else
- pDest[0] = (pBob[0] + pBob[src_pitch2 + 1]) / 2;
- pDest[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2;
- pDest[2] = (pBob[2] + pBob[src_pitch2 + 2]) / 2;
- pDest[3] = (pBob[3] + pBob[src_pitch2 + 3]) / 2;
-
- // simple bob last byte
- pDest[Last8] = (pBob[Last8] + pBob[Last8 + src_pitch2]) / 2;
- pDest[Last8 + 1] = (pBob[Last8 + 1] + pBob[Last8 + src_pitch2 + 1]) / 2;
- pDest[Last8 + 2] = (pBob[Last8 + 2] + pBob[Last8 + src_pitch2 + 2]) / 2;
- pDest[Last8 + 3] = (pBob[Last8 + 3] + pBob[Last8 + src_pitch2 + 3]) / 2;
-#endif
-
- pBob += 4;
- pBobP += 4;
- pSrc += 4;
- pSrcP += 4;
-
- for (x=4; x < Last8; x += 2) {
-
-#ifdef USE_STRANGE_BOB
-#include "StrangeBob.inc"
-#else
-#include "WierdBob.inc"
-#endif
-
- // We will keep a slight bias to using the weave pixels
- // from the current location, by rating them by the min distance
- // from the Bob value instead of the avg distance from that value.
- // our best and only rating so far
- diff[0] = diff[1] = 255;
-
-
-#endif
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc
deleted file mode 100644
index 3e3d19b5..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVA.inc
+++ /dev/null
@@ -1,6 +0,0 @@
-// -*- c++ -*-
-
-// Searches the center vertical line above center and below, in both the old
-// and new fields, but takes averages. These are even pixel addresses.
- MERGE4PIXavg("(%%"XDI", %%"XCX", 2)", "(%%"XSI")") // down, up
- MERGE4PIXavg("(%%"XDI")", "(%%"XSI", %%"XCX", 2)") // up, down
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc b/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc
deleted file mode 100644
index 33155bc1..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/SearchLoopVAH.inc
+++ /dev/null
@@ -1,6 +0,0 @@
-// -*- c++ -*-
-
-// Searches the center vertical line above center and below, in both the old
-// and new fields, but takes averages. These are even pixel addresses.
- MERGE4PIXavgH("(%%"XDI", %%"XCX", 2)", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI")") // down, up
- MERGE4PIXavgH("(%%"XDI")", "(%%"XDI", %%"XCX")", "(%%"XSI", %%"XCX")", "(%%"XSI", %%"XCX", 2)") // up, down
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc b/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc
deleted file mode 100644
index 45b4c865..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/StrangeBob.inc
+++ /dev/null
@@ -1,435 +0,0 @@
-// -*- c++ -*-
-
- // First, get and save our possible Bob values
- // Assume our pixels are layed out as follows with x the calc'd bob value
- // and the other pixels are from the current field
- //
- // j a b c k current field
- // x calculated line
- // m d e f n current field
- //
- // we calc the bob value luma value as:
- // if |j - n| < Thres && |a - m| > Thres
- // avg(j,n)
- // end if
- // if |k - m| < Thres && |c - n| > Thres
- // avg(k,m)
- // end if
- // if |c - d| < Thres && |b - f| > Thres
- // avg(c,d)
- // end if
- // if |a - f| < Thres && |b - d| > Thres
- // avg(a,f)
- // end if
- // if |b - e| < Thres
- // avg(b,e)
- // end if
- // pickup any thing not yet set with avg(b,e)
-
-#ifndef IS_C
-
- // j, n
- "pxor %%mm5, %%mm5\n\t"
- "pxor %%mm6, %%mm6\n\t"
- "pxor %%mm7, %%mm7\n\t"
-
- "movq -2(%%"XBX"), %%mm0\n\t" // value a from top left
- "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value m from bottom right
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(a,m)
-
- "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(a,m) > Thres else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(a,m) < Thres, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(a,m) > Thres, else 00
-
-
- "movq -4(%%"XBX"), %%mm0\n\t" // value j
- "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(j,n)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm0\n\t"
- "psubusb %%mm3, %%mm1\n\t"
- "por %%mm1, %%mm0\n\t" // abs(j,n)
-
- "movq %%mm0, %%mm1\n\t"
- "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(j,n) > Thres else 0
- "pxor %%mm3, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(j,n) < Thres, else 00
-
- "pand %%mm4, %%mm1\n\t"
- "pand %%mm1, %%mm2\n\t"
- "pand %%mm1, %%mm0\n\t"
-
- "movq %%mm1, %%mm3\n\t"
- "pxor %%mm5, %%mm3\n\t"
- "pand %%mm3, %%mm6\n\t"
- "pand %%mm3, %%mm7\n\t"
- "pand %%mm3, %%mm5\n\t"
-
- "por %%mm1, %%mm5\n\t"
- "por %%mm2, %%mm6\n\t"
- "por %%mm0, %%mm7\n\t"
-
- // k & m
- "movq 2(%%"XBX"), %%mm0\n\t" // value c from top left
- "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom right
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(c,n)
-
- "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(c,n) > Thres else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(c,n) < Thres, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(c,n) > Thres, else 00
-
-
- "movq 4(%%"XBX"), %%mm0\n\t" // value k
- "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value m
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(k,m)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm0\n\t"
- "psubusb %%mm3, %%mm1\n\t"
- "por %%mm1, %%mm0\n\t" // abs(k,m)
-
- "movq %%mm0, %%mm1\n\t"
- "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(k,m) > Thres else 0
- "pxor %%mm3, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(k,m) < Thres, else 00
-
- "pand %%mm4, %%mm1\n\t"
-
- "pand %%mm1, %%mm2\n\t"
- "pand %%mm1, %%mm0\n\t"
-
- "movq %%mm1, %%mm3\n\t"
- "pxor %%mm5, %%mm3\n\t"
- "pand %%mm3, %%mm6\n\t"
- "pand %%mm3, %%mm7\n\t"
- "pand %%mm3, %%mm5\n\t"
-
- "por %%mm1, %%mm5\n\t"
- "por %%mm2, %%mm6\n\t"
- "por %%mm0, %%mm7\n\t"
-
-
- // c & d
- "movq (%%"XBX"), %%mm0\n\t" // value b from top left
- "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(b,f)
-
- "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(b,f) > Thres else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(b,f) < Thres, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(b,f) > Thres, else 00
-
- "movq 2(%%"XBX"), %%mm0\n\t" // value c
- "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value d
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(c,d)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm0\n\t"
- "psubusb %%mm3, %%mm1\n\t"
- "por %%mm1, %%mm0\n\t" // abs(c,d)
-
- "movq %%mm0, %%mm1\n\t"
- "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(c,d) > Thres else 0
- "pxor %%mm3, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(c,d) < Thres, else 00
-
- "pand %%mm4, %%mm1\n\t"
-
- "pand %%mm1, %%mm2\n\t"
- "pand %%mm1, %%mm0\n\t"
-
- "movq %%mm1, %%mm3\n\t"
- "pxor %%mm5, %%mm3\n\t"
- "pand %%mm3, %%mm6\n\t"
- "pand %%mm3, %%mm7\n\t"
- "pand %%mm3, %%mm5\n\t"
-
- "por %%mm1, %%mm5\n\t"
- "por %%mm2, %%mm6\n\t"
- "por %%mm0, %%mm7\n\t"
-
- // a & f
- "movq (%%"XBX"), %%mm0\n\t" // value b from top left
- "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value d from bottom right
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(b,d)
-
- "psubusb "_DiffThres", %%mm3\n\t" // nonzero where abs(b,d) > Thres else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where abs(b,d) < Thres, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where abs(b,d) > Thres, else 00
-
- "movq -2(%%"XBX"), %%mm0\n\t" // value a
- "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(a,f)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm0\n\t"
- "psubusb %%mm3, %%mm1\n\t"
- "por %%mm1, %%mm0\n\t" // abs(a,f)
-
- "movq %%mm0, %%mm1\n\t"
- "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(a,f) > Thres else 0
- "pxor %%mm3, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(a,f) < Thres, else 00
-
- "pand %%mm4, %%mm1\n\t"
-
- "pand %%mm1, %%mm2\n\t"
- "pand %%mm1, %%mm0\n\t"
-
- "movq %%mm1, %%mm3\n\t"
- "pxor %%mm5, %%mm3\n\t"
- "pand %%mm3, %%mm6\n\t"
- "pand %%mm3, %%mm7\n\t"
- "pand %%mm3, %%mm5\n\t"
-
- "por %%mm1, %%mm5\n\t"
- "por %%mm2, %%mm6\n\t"
- "por %%mm0, %%mm7\n\t"
-
- "pand "_YMask", %%mm5\n\t" // mask out chroma from here
- "pand "_YMask", %%mm6\n\t" // mask out chroma from here
- "pand "_YMask", %%mm7\n\t" // mask out chroma from here
-
- // b,e
- "movq (%%"XBX"), %%mm0\n\t" // value b from top
- "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom
- "movq %%mm0, %%mm2\n\t"
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm0\n\t"
- "psubusb %%mm3, %%mm1\n\t"
- "por %%mm1, %%mm0\n\t" // abs(b,e)
-
- "movq %%mm0, %%mm1\n\t"
- "psubusb "_DiffThres", %%mm1\n\t" // nonzero where abs(b,e) > Thres else 0
- "pxor %%mm3, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm1\n\t" // now ff where abs(b,e) < Thres, else 00
-
- "pand %%mm1, %%mm2\n\t"
- "pand %%mm1, %%mm0\n\t"
-
- "movq %%mm1, %%mm3\n\t"
- "pxor %%mm5, %%mm3\n\t"
- "pand %%mm3, %%mm6\n\t"
- "pand %%mm3, %%mm7\n\t"
- "pand %%mm3, %%mm5\n\t"
-
- "por %%mm1, %%mm5\n\t"
- "por %%mm2, %%mm6\n\t"
- "por %%mm0, %%mm7\n\t"
-
- // bob in any leftovers
- "movq (%%"XBX"), %%mm0\n\t" // value b from top
- "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom
-
-
-// We will also calc here the max/min values to later limit comb
-// so the max excursion will not exceed the Max_Comb constant
-
-#ifdef SKIP_SEARCH
- "movq %%mm0, %%mm2\n\t"
-// pminub %%mm2, %%mm1
- V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
-
-// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this
- V_PMAXUB ("%%mm6", "%%mm2")
- "movq %%mm0, %%mm2\n\t"
- V_PMAXUB ("%%mm2", "%%mm1")
-// pminub %%mm6, %%mm2 // clip our current results so far to be below this
- V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
-
-#else
- "movq %%mm0, %%mm2\n\t"
- "movq (%%"XAX"), %%mm4\n\t"
- "psubusb %%mm4, %%mm2\n\t"
- "psubusb %%mm0, %%mm4\n\t"
- "por %%mm2, %%mm4\n\t" // abs diff
-
- "movq %%mm1, %%mm2\n\t"
- "movq (%%"XAX", %%"XCX"), %%mm3\n\t"
- "psubusb %%mm3, %%mm2\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "por %%mm2, %%mm3\n\t" // abs diff
-// pmaxub %%mm3, %%mm4 // top or bottom pixel moved most
- V_PMAXUB ("%%mm3", "%%mm4") // top or bottom pixel moved most
- "psubusb "_DiffThres", %%mm3\n\t" // moved more than allowed? or goes to 0?
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where low motion, else high motion
-
- "movq %%mm0, %%mm2\n\t"
-// pminub %%mm2, %%mm1
- V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
-
-// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this
- V_PMAXUB ("%%mm6", "%%mm2")
-
- "psubusb %%mm3, %%mm2\n\t" // maybe decrease it to 0000.. if no surround motion
- "movq %%mm2, "_Min_Vals"\n\t"
-
- "movq %%mm0, %%mm2\n\t"
- V_PMAXUB ("%%mm2", "%%mm1")
-// pminub %%mm6, %%mm2 // clip our current results so far to be below this
- V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
- "paddusb %%mm3, %%mm2\n\t" // maybe increase it to ffffff if no surround motion
- "movq %%mm2, "_Max_Vals"\n\t"
-#endif
-
- "movq %%mm0, %%mm2\n\t"
-// pavgb %%mm2, %%mm1 // avg(b,e)
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e)
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(b,e)
- "movq %%mm3, %%mm1\n\t" // keep copy of diffs
-
- "pxor %%mm4, %%mm4\n\t"
- "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00
- "pcmpeqb %%mm0, %%mm0\n\t"
- "pandn %%mm0, %%mm5\n\t"
- "por %%mm5, %%mm3\n\t"
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00
-
- "pand %%mm3, %%mm1\n\t"
- "pand %%mm3, %%mm2\n\t"
-
- "pand %%mm4, %%mm6\n\t"
- "pand %%mm4, %%mm7\n\t"
-
- "por %%mm2, %%mm6\n\t" // our x2 value
- "por %%mm1, %%mm7\n\t" // our x2 diffs
- "movq %%mm7, %%mm4\n\t" // save as bob uncertainty indicator
-
-#else
-
- diff[0] = -1;
- diff[1] = -1;
- best[0] = 0;
- best[1] = 0;
- // j, n
- if (ABS (pBob[-2] - pBob[src_pitch2 - 4]) < DiffThres &&
- ABS (pBob[-4] - pBob[src_pitch2 + 4]) > DiffThres) {
- best[0] = (pBob[-2] + pBob[src_pitch2 - 4]) / 2;
- diff[0] = ABS (pBob[-2] - pBob[src_pitch2 - 4]);
- }
- if (ABS (pBob[-1] - pBob[src_pitch2 - 3]) < DiffThres &&
- ABS (pBob[-3] - pBob[src_pitch2 + 5]) > DiffThres) {
- best[1] = (pBob[-1] + pBob[src_pitch2 - 3]) / 2;
- diff[1] = ABS (pBob[-1] - pBob[src_pitch2 - 3]);
- }
-
- // k & m
- if (ABS (pBob[2] - pBob[src_pitch2 + 4]) < DiffThres &&
- ABS (pBob[4] - pBob[src_pitch2 - 4]) > DiffThres) {
- best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
- diff[0] = ABS (pBob[4] - pBob[src_pitch2 - 4]);
- }
-
- if (ABS (pBob[3] - pBob[src_pitch2 + 5]) < DiffThres &&
- ABS (pBob[5] - pBob[src_pitch2 - 3]) > DiffThres) {
- best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
- diff[1] = ABS (pBob[5] - pBob[src_pitch2 - 3]);
- }
-
- // c & d
- if (ABS (pBob[0] - pBob[src_pitch2 + 2]) < DiffThres &&
- ABS (pBob[2] - pBob[src_pitch2 - 2]) > DiffThres) {
- best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2;
- diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]);
- }
-
- if (ABS (pBob[1] - pBob[src_pitch2 + 3]) < DiffThres &&
- ABS (pBob[3] - pBob[src_pitch2 - 1]) > DiffThres) {
- best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2;
- diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]);
- }
-
- // a & f
- if (ABS (pBob[0] - pBob[src_pitch2 - 2]) < DiffThres &&
- ABS (pBob[-2] - pBob[src_pitch2 + 2]) > DiffThres) {
- best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2;
- diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]);
- }
-
- if (ABS (pBob[1] - pBob[src_pitch2 - 1]) < DiffThres &&
- ABS (pBob[-1] - pBob[src_pitch2 + 3]) > DiffThres) {
- best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2;
- diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]);
- }
-
- // b,e
- if (ABS (pBob[0] - pBob[src_pitch2]) < DiffThres) {
- best[0] = (pBob[0] + pBob[src_pitch2]) / 2;
- diff[0] = ABS (pBob[0] - pBob[src_pitch2]);
- }
-
- if (ABS (pBob[1] - pBob[src_pitch2 + 1]) < DiffThres) {
- best[1] = (pBob[1] + pBob[src_pitch2 + 1]) / 2;
- diff[1] = ABS (pBob[1] - pBob[src_pitch2 + 1]);
- }
-
-
-// We will also calc here the max/min values to later limit comb
-// so the max excursion will not exceed the Max_Comb constant
-
-#ifdef SKIP_SEARCH
- best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
- best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
-#else
- mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2]));
- mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1]));
-
- MinVals[0] = 0;
- MinVals[1] = 0;
- MaxVals[0] = 255;
- MaxVals[1] = 255;
- if (mov[0] > DiffThres) {
- MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]);
- MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]);
- }
-
- if (mov[1] > DiffThres) {
- MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2+1]), best[1]);
- MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2+1]), best[1]);
- }
-
- best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
- best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
-#endif
- avg[0] = (pBob[src_pitch2] + pBob[0]) / 2;
- avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2;
- diff2[0] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
- diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
-
- if (diff[0] == -1 || diff2[0] < diff[0]) {
- best[0] = avg[0];
- diff[0] = diff2[0];
- }
-
- if (diff[1] == -1 || diff2[1] < diff[1]) {
- best[1] = avg[1];
- diff[1] = diff2[1];
- }
-#endif
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc b/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc
deleted file mode 100644
index 89ed39e4..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll.inc
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * GStreamer
- * Copyright (c) 2002 Tom Barry All rights reserved.
- *
- * 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.
- */
-
-/*
- * Relicensed for GStreamer from GPL to LGPL with permit from Tom Barry.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-
-#ifndef TopFirst
-#define TopFirst IsOdd
-#endif
-
-#ifdef SEFUNC
-#undef SEFUNC
-#endif
-
-#if defined(IS_MMXEXT)
-#define SEFUNC(x) Search_Effort_MMXEXT_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
-#elif defined(IS_3DNOW)
-#define SEFUNC(x) Search_Effort_3DNOW_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
-#elif defined(IS_MMX)
-#define SEFUNC(x) Search_Effort_MMX_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
-#else
-#define SEFUNC(x) Search_Effort_C_##x(int src_pitch, int dst_pitch, int rowsize, const unsigned char *pWeaveSrc, const unsigned char *pWeaveSrcP, unsigned char *pWeaveDest, int IsOdd, const unsigned char *pCopySrc, const unsigned char *pCopySrcP, int FldHeight)
-#endif
-
-#include "TomsMoCompAll2.inc"
-
-#define USE_STRANGE_BOB
-
-#include "TomsMoCompAll2.inc"
-
-#undef USE_STRANGE_BOB
-
-#undef SEFUNC
-#if defined(IS_MMXEXT)
-#define SEFUNC(x) Search_Effort_MMXEXT_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
-#elif defined(IS_3DNOW)
-#define SEFUNC(x) Search_Effort_3DNOW_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
-#elif defined(IS_MMX)
-#define SEFUNC(x) Search_Effort_MMX_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
-#else
-#define SEFUNC(x) Search_Effort_C_##x(src_pitch, dst_pitch, rowsize, pWeaveSrc, pWeaveSrcP, pWeaveDest, IsOdd, pCopySrc, pCopySrcP, FldHeight)
-#endif
-
-void FUNCT_NAME(GstDeinterlaceMethod *d_method, GstDeinterlace2* object, GstBuffer *outbuf)
-{
- GstDeinterlaceMethodTomsMoComp *self = GST_DEINTERLACE_METHOD_TOMSMOCOMP (d_method);
- long SearchEffort = self->search_effort;
- int UseStrangeBob = self->strange_bob;
- int IsOdd;
- const unsigned char *pWeaveSrc;
- const unsigned char *pWeaveSrcP;
- unsigned char *pWeaveDest;
- const unsigned char *pCopySrc;
- const unsigned char *pCopySrcP;
- unsigned char *pCopyDest;
- int src_pitch;
- int dst_pitch;
- int rowsize;
- int FldHeight;
-
- /* double stride do address just every odd/even scanline */
- src_pitch = object->field_stride;
- dst_pitch = object->row_stride;
- rowsize = object->row_stride;
- FldHeight = object->field_height;
-
- pCopySrc = GST_BUFFER_DATA(object->field_history[object->history_count-1].buf);
- pCopySrcP = GST_BUFFER_DATA(object->field_history[object->history_count-3].buf);
- pWeaveSrc = GST_BUFFER_DATA(object->field_history[object->history_count-2].buf);
- pWeaveSrcP = GST_BUFFER_DATA(object->field_history[object->history_count-4].buf);
-
- /* use bottom field and interlace top field */
- if (object->field_history[object->history_count-2].flags == PICTURE_INTERLACED_BOTTOM) {
- IsOdd = 1;
-
- // if we have an odd field we copy an even field and weave an odd field
- pCopyDest = GST_BUFFER_DATA(outbuf);
- pWeaveDest = pCopyDest + dst_pitch;
- }
- /* do it vice verca */
- else {
-
- IsOdd = 0;
- // if we have an even field we copy an odd field and weave an even field
- pCopyDest = GST_BUFFER_DATA(outbuf) + dst_pitch;
- pWeaveDest = GST_BUFFER_DATA(outbuf);
- }
-
-
- // copy 1st and last weave lines
- Fieldcopy(pWeaveDest, pCopySrc, rowsize,
- 1, dst_pitch*2, src_pitch);
- Fieldcopy(pWeaveDest+(FldHeight-1)*dst_pitch*2,
- pCopySrc+(FldHeight-1)*src_pitch, rowsize,
- 1, dst_pitch*2, src_pitch);
-
-#ifdef USE_VERTICAL_FILTER
- // Vertical Filter currently not implemented for DScaler !!
- // copy 1st and last lines the copy field
- Fieldcopy(pCopyDest, pCopySrc, rowsize,
- 1, dst_pitch*2, src_pitch);
- Fieldcopy(pCopyDest+(FldHeight-1)*dst_pitch*2,
- pCopySrc+(FldHeight-1)*src_pitch, rowsize,
- 1, dst_pitch*2, src_pitch);
-#else
-
- // copy all of the copy field
- Fieldcopy(pCopyDest, pCopySrc, rowsize,
- FldHeight, dst_pitch*2, src_pitch);
-#endif
- // then go fill in the hard part, being variously lazy depending upon
- // SearchEffort
-
- if(!UseStrangeBob) {
- if (SearchEffort == 0)
- {
- SEFUNC(0);
- }
- else if (SearchEffort <= 1)
- {
- SEFUNC(1);
- }
- /* else if (SearchEffort <= 2)
- {
- SEFUNC(2);
- }
- */
- else if (SearchEffort <= 3)
- {
- SEFUNC(3);
- }
- else if (SearchEffort <= 5)
- {
- SEFUNC(5);
- }
- else if (SearchEffort <= 9)
- {
- SEFUNC(9);
- }
- else if (SearchEffort <= 11)
- {
- SEFUNC(11);
- }
- else if (SearchEffort <= 13)
- {
- SEFUNC(13);
- }
- else if (SearchEffort <= 15)
- {
- SEFUNC(15);
- }
- else if (SearchEffort <= 19)
- {
- SEFUNC(19);
- }
- else if (SearchEffort <= 21)
- {
- SEFUNC(21);
- }
- else
- {
- SEFUNC(Max);
- }
- }
- else
- {
- if (SearchEffort == 0)
- {
- SEFUNC(0SB);
- }
- else if (SearchEffort <= 1)
- {
- SEFUNC(1SB);
- }
- /* else if (SearchEffort <= 2)
- {
- SEFUNC(2SB);
- }
- */
- else if (SearchEffort <= 3)
- {
- SEFUNC(3SB);
- }
- else if (SearchEffort <= 5)
- {
- SEFUNC(5SB);
- }
- else if (SearchEffort <= 9)
- {
- SEFUNC(9SB);
- }
- else if (SearchEffort <= 11)
- {
- SEFUNC(11SB);
- }
- else if (SearchEffort <= 13)
- {
- SEFUNC(13SB);
- }
- else if (SearchEffort <= 15)
- {
- SEFUNC(15SB);
- }
- else if (SearchEffort <= 19)
- {
- SEFUNC(19SB);
- }
- else if (SearchEffort <= 21)
- {
- SEFUNC(21SB);
- }
- else
- {
- SEFUNC(MaxSB);
- }
- }
-
-#if defined(BUILD_X86_ASM) && !defined(IS_C)
- __asm__ __volatile__("emms");
-#endif
-}
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc b/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc
deleted file mode 100644
index f6344eab..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/TomsMoCompAll2.inc
+++ /dev/null
@@ -1,243 +0,0 @@
-// -*- c++ -*-
-
-#ifdef SEARCH_EFFORT_FUNC
-#undef SEARCH_EFFORT_FUNC
-#endif
-
-#ifdef USE_STRANGE_BOB
-#define SEARCH_EFFORT_FUNC(n) SEFUNC(n##SB)
-#else
-#define SEARCH_EFFORT_FUNC(n) SEFUNC(n)
-#endif
-
-static inline int SEARCH_EFFORT_FUNC(0) // we don't try at all ;-)
-{
- //see Search_Effort_Max() for comments
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-}
-
-static inline int SEARCH_EFFORT_FUNC(1)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see Search_Effort_Max() for comments
-#include "SearchLoopTop.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-static inline int SEARCH_EFFORT_FUNC(3)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see Search_Effort_Max() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA2.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-static inline int SEARCH_EFFORT_FUNC(5)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see Search_Effort_Max() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA2.inc"
-#include "SearchLoopOddAH2.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// 3x3 search
-static inline int SEARCH_EFFORT_FUNC(9)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchEffortMax() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoopVA.inc"
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// Search 9 with 2 H-half pels added
-static inline int SEARCH_EFFORT_FUNC(11)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchEffortMax() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA.inc"
-#include "SearchLoopOddAH2.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoopVA.inc"
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// Search 11 with 2 V-half pels added
-static inline int SEARCH_EFFORT_FUNC(13)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchEffortMax() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA.inc"
-#include "SearchLoopOddAH2.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoopVAH.inc"
-#include "SearchLoopVA.inc"
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// 5x3
-static inline int SEARCH_EFFORT_FUNC(15)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchEffortMax() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoopEdgeA.inc"
-#include "SearchLoopVA.inc"
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// 5x3 + 4 half pels
-static inline int SEARCH_EFFORT_FUNC(19)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchEffortMax() for comments
-#include "SearchLoopTop.inc"
-#include "SearchLoopOddA.inc"
-#include "SearchLoopOddAH2.inc"
- RESET_CHROMA // pretend chroma diffs was 255 each
-#include "SearchLoopEdgeA.inc"
-#include "SearchLoopVAH.inc"
-#include "SearchLoopVA.inc"
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// Handle one 4x1 block of pixels
-// Search a 7x3 area, no half pels
-
-static inline int SEARCH_EFFORT_FUNC(21)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchLoopTop.inc for comments
-#include "SearchLoopTop.inc"
-
- // odd addresses -- the pixels at odd address wouldn't generate
- // good luma values but we will mask those off
-
-#include "SearchLoopOddA6.inc" // 4 odd v half pels, 3 to left & right
-#include "SearchLoopOddA.inc" // 6 odd pels, 1 to left & right
-
- RESET_CHROMA // pretend chroma diffs was 255 each
-
- // even addresses -- use both luma and chroma from these
- // search averages of 2 pixels left and right
-#include "SearchLoopEdgeA.inc"
- // search vertical line and averages, -1,0,+1
-#include "SearchLoopVA.inc"
- // blend our results and loop
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-// Handle one 4x1 block of pixels
-// Search a 9x3 area, no half pels
-static inline int SEARCH_EFFORT_FUNC(Max)
-{
-#ifdef IS_C
-#define SKIP_SEARCH
-#include "SearchLoopTop.inc"
-#include "SearchLoopBottom.inc"
-#undef SKIP_SEARCH
-#else
- //see SearchLoopTop.inc for comments
-#include "SearchLoopTop.inc"
-
- // odd addresses -- the pixels at odd address wouldn't generate
- // good luma values but we will mask those off
-
-#include "SearchLoopOddA6.inc" // 4 odd v half pels, 3 to left & right
-#include "SearchLoopOddA.inc" // 6 odd pels, 1 to left & right
-
- RESET_CHROMA // pretend chroma diffs was 255 each
-
- // even addresses -- use both luma and chroma from these
- // search averages of 4 pixels left and right
-#include "SearchLoopEdgeA8.inc"
- // search averages of 2 pixels left and right
-#include "SearchLoopEdgeA.inc"
- // search vertical line and averages, -1,0,+1
-#include "SearchLoopVA.inc"
- // blend our results and loop
-#include "SearchLoop0A.inc"
-#include "SearchLoopBottom.inc"
-#endif
-}
-
-#undef SEARCH_EFFORT_FUNC
-
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc b/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc
deleted file mode 100644
index f4bbb830..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/WierdBob.inc
+++ /dev/null
@@ -1,286 +0,0 @@
-// -*- c++ -*-
-
- // First, get and save our possible Bob values
- // Assume our pixels are layed out as follows with x the calc'd bob value
- // and the other pixels are from the current field
- //
- // j a b c k current field
- // x calculated line
- // m d e f n current field
- //
- // we calc the bob value as:
- // x2 = either avg(a,f), avg(c,d), avg(b,e), avg(j,n), or avg(k,m)
-
- // selected for the smallest of abs(a,f), abs(c,d), or abs(b,e), etc.
-
-#ifndef IS_C
- // a,f
- "movq -2(%%"XBX"), %%mm0\n\t" // value a from top left
- "movq 2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right
- "movq %%mm0, %%mm6\n\t"
-// pavgb %%mm6, %%mm1 // avg(a,f), also best so far
- V_PAVGB ("%%mm6", "%%mm1", "%%mm7", _ShiftMask) // avg(a,f), also best so far
- "movq %%mm0, %%mm7\n\t"
- "psubusb %%mm1, %%mm7\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm7\n\t" // abs diff, also best so far
-
- // c,d
- "movq 2(%%"XBX"), %%mm0\n\t" // value a from top left
- "movq -2(%%"XBX", %%"XCX"), %%mm1\n\t" // value f from bottom right
- "movq %%mm0, %%mm2\n\t"
-// pavgb %%mm2, %%mm1 // avg(c,d)
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(c,d)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(c,d)
- "movq %%mm3, %%mm1\n\t" // keep copy
-
- "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00
-
- "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs
- "pand %%mm3, %%mm2\n\t"
-
- "pand %%mm4, %%mm6\n\t"
- "pand %%mm4, %%mm7\n\t"
-
- "por %%mm2, %%mm6\n\t" // and merge new & old vals keeping best
- "por %%mm1, %%mm7\n\t"
- "por "_UVMask", %%mm7\n\t" // but we know chroma is worthless so far
- "pand "_YMask", %%mm5\n\t" // mask out chroma from here also
-
- // j,n
- "movq -4(%%"XBX"), %%mm0\n\t" // value j from top left
- "movq 4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom right
- "movq %%mm0, %%mm2\n\t"
-// pavgb %%mm2, %%mm1 // avg(j,n)
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(j,n)
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(j-n)
- "movq %%mm3, %%mm1\n\t" // keep copy
-
- "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00
-
- "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs
- "pand %%mm2, %%mm3\n\t"
-
- "pand %%mm4, %%mm6\n\t"
- "pand %%mm4, %%mm7\n\t"
-
- "por %%mm3, %%mm6\n\t" // and merge new & old vals keeping best
- "por %%mm1, %%mm7\n\t" // "
-
- // k, m
- "movq 4(%%"XBX"), %%mm0\n\t" // value k from top right
- "movq -4(%%"XBX", %%"XCX"), %%mm1\n\t" // value n from bottom left
- "movq %%mm0, %%mm4\n\t"
-// pavgb %%mm4, %%mm1 // avg(k,m)
- V_PAVGB ("%%mm4", "%%mm1", "%%mm3", _ShiftMask) // avg(k,m)
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(k,m)
- "movq %%mm3, %%mm1\n\t" // keep copy
-
- "movq %%mm4, %%mm2\n\t" // avg(k,m)
-
- "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00
-
- "pand %%mm3, %%mm1\n\t" // keep only better new avg and abs
- "pand %%mm2, %%mm3\n\t"
-
- "pand %%mm4, %%mm6\n\t"
- "pand %%mm4, %%mm7\n\t"
-
- "por %%mm3, %%mm6\n\t" // and merge new & old vals keeping best
- "por %%mm1, %%mm7\n\t" // "
-
- // b,e
- "movq (%%"XBX"), %%mm0\n\t" // value b from top
- "movq (%%"XBX", %%"XCX"), %%mm1\n\t" // value e from bottom
-
-// We will also calc here the max/min values to later limit comb
-// so the max excursion will not exceed the Max_Comb constant
-
-#ifdef SKIP_SEARCH
- "movq %%mm0, %%mm2\n\t"
-// pminub %%mm2, %%mm1
- V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
-
-// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this
- V_PMAXUB ("%%mm6", "%%mm2")
- "movq %%mm0, %%mm2\n\t"
- V_PMAXUB ("%%mm2", "%%mm1")
-// pminub %%mm6, %%mm2 // clip our current results so far to be below this
- V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
-
-#else
- "movq %%mm0, %%mm2\n\t"
- "movq (%%"XAX"), %%mm4\n\t"
- "psubusb %%mm4, %%mm2\n\t"
- "psubusb %%mm0, %%mm4\n\t"
- "por %%mm2, %%mm4\n\t" // abs diff
-
- "movq %%mm1, %%mm2\n\t"
- "movq (%%"XAX", %%"XCX"), %%mm3\n\t"
- "psubusb %%mm3, %%mm2\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "por %%mm2, %%mm3\n\t" // abs diff
-// pmaxub %%mm3, %%mm4 // top or bottom pixel moved most
- V_PMAXUB ("%%mm3", "%%mm4") // top or bottom pixel moved most
- "psubusb "_Max_Mov", %%mm3\n\t" // moved more than allowed? or goes to 0?
- "pxor %%mm4, %%mm4\n\t"
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where low motion, else high motion
-
- "movq %%mm0, %%mm2\n\t"
-// pminub %%mm2, %%mm1
- V_PMINUB ("%%mm2", "%%mm1", "%%mm4")
-
-// pmaxub %%mm6, %%mm2 // clip our current results so far to be above this
- V_PMAXUB ("%%mm6", "%%mm2")
-
- "psubusb %%mm3, %%mm2\n\t" // maybe decrease it to 0000.. if no surround motion
- "movq %%mm2, "_Min_Vals"\n\t"
-
- "movq %%mm0, %%mm2\n\t"
- V_PMAXUB ("%%mm2", "%%mm1")
-// pminub %%mm6, %%mm2 // clip our current results so far to be below this
- V_PMINUB ("%%mm6", "%%mm2", "%%mm4")
- "paddusb %%mm3, %%mm2\n\t" // maybe increase it to ffffff if no surround motion
- "movq %%mm2, "_Max_Vals"\n\t"
-#endif
-
- "movq %%mm0, %%mm2\n\t"
-// pavgb %%mm2, %%mm1 // avg(b,e)
- V_PAVGB ("%%mm2", "%%mm1", "%%mm3", _ShiftMask) // avg(b,e)
-
- "movq %%mm0, %%mm3\n\t"
- "psubusb %%mm1, %%mm3\n\t"
- "psubusb %%mm0, %%mm1\n\t"
- "por %%mm1, %%mm3\n\t" // abs(c,d)
- "movq %%mm3, %%mm1\n\t" // keep copy of diffs
-
- "pxor %%mm4, %%mm4\n\t"
- "psubusb %%mm7, %%mm3\n\t" // nonzero where new weights bigger, else 0
- "pcmpeqb %%mm4, %%mm3\n\t" // now ff where new better, else 00
-
- "pcmpeqb %%mm3, %%mm4\n\t" // here ff where old better, else 00
-
- "pand %%mm3, %%mm1\n\t"
- "pand %%mm3, %%mm2\n\t"
-
- "pand %%mm4, %%mm6\n\t"
- "pand %%mm4, %%mm7\n\t"
-
- "por %%mm2, %%mm6\n\t" // our x2 value
- "por %%mm1, %%mm7\n\t" // our x2 diffs
- "movq %%mm7, %%mm4\n\t" // save as bob uncertainty indicator
-
-#else
-
- // a,f
- best[0] = (pBob[-2] + pBob[src_pitch2 + 2]) / 2;
- diff[0] = ABS (pBob[-2] - pBob[src_pitch2 + 2]);
- best[1] = (pBob[-1] + pBob[src_pitch2 + 3]) / 2;
- diff[1] = ABS (pBob[-1] - pBob[src_pitch2 + 3]);
-
- // c,d
- if (ABS (pBob[2] - pBob[src_pitch2 - 2]) < diff[0]) {
- best[0] = (pBob[2] + pBob[src_pitch2 - 2]) / 2;
- diff[0] = ABS (pBob[2] - pBob[src_pitch2 - 2]);
- }
-
- if (ABS (pBob[3] - pBob[src_pitch2 - 1]) < diff[1]) {
- best[1] = (pBob[3] + pBob[src_pitch2 - 1]) / 2;
- diff[1] = ABS (pBob[3] - pBob[src_pitch2 - 1]);
- }
-
- // j,n
- if (ABS (pBob[-4] - pBob[src_pitch2 + 4]) < diff[0]) {
- best[0] = (pBob[-4] + pBob[src_pitch2 + 4]) / 2;
- diff[0] = ABS (pBob[-4] - pBob[src_pitch2 + 4]);
- }
-
- if (ABS (pBob[-3] - pBob[src_pitch2 + 5]) < diff[1]) {
- best[1] = (pBob[-3] + pBob[src_pitch2 + 5]) / 2;
- diff[1] = ABS (pBob[-3] - pBob[src_pitch2 + 5]);
- }
-
- // k,m
- if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) {
- best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
- diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]);
- }
-
- if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) {
- best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
- diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]);
- }
- // k,m
- if (ABS (pBob[4] - pBob[src_pitch2 - 4]) < diff[0]) {
- best[0] = (pBob[4] + pBob[src_pitch2 - 4]) / 2;
- diff[0] = ABS (pBob[-4] - pBob[src_pitch2 - 4]);
- }
-
- if (ABS (pBob[5] - pBob[src_pitch2 - 3]) < diff[1]) {
- best[1] = (pBob[5] + pBob[src_pitch2 - 3]) / 2;
- diff[1] = ABS (pBob[-3] - pBob[src_pitch2 - 3]);
- }
-
-// We will also calc here the max/min values to later limit comb
-// so the max excursion will not exceed the Max_Comb constant
-
-#ifdef SKIP_SEARCH
- best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
- best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
-#else
- mov[0] = MAX (ABS (pBob[0] - pBobP[0]), ABS (pBob[src_pitch2] - pBobP[src_pitch2]));
- mov[1] = MAX (ABS (pBob[1] - pBobP[1]), ABS (pBob[src_pitch2 + 1] - pBobP[src_pitch2 + 1]));
-
- MinVals[0] = 0;
- MinVals[1] = 0;
- MaxVals[0] = 255;
- MaxVals[1] = 255;
-
- if (mov[0] > Max_Mov[0]) {
- MinVals[0] = MAX (MIN (pBob[0], pBob[src_pitch2]), best[0]);
- MaxVals[0] = MIN (MAX (pBob[0], pBob[src_pitch2]), best[0]);
- }
-
- if (mov[1] > Max_Mov[1]) {
- MinVals[1] = MAX (MIN (pBob[1], pBob[src_pitch2 + 1]), best[1]);
- MaxVals[1] = MIN (MAX (pBob[1], pBob[src_pitch2 + 1]), best[1]);
- }
-
- best[0] = CLAMP (best[0], MIN (pBob[src_pitch2], pBob[0]), MAX (pBob[src_pitch2], pBob[0]));
- best[1] = CLAMP (best[1], MIN (pBob[src_pitch2 + 1], pBob[1]), MAX (pBob[src_pitch2 + 1], pBob[1]));
-#endif
-
- avg[0] = (pBob[src_pitch2] + pBob[0]) / 2;
- avg[1] = (pBob[src_pitch2 + 1] + pBob[1]) / 2;
- diff2[0] = ABS (pBob[src_pitch2] - pBob[0]);
- diff2[1] = ABS (pBob[src_pitch2 + 1] - pBob[1]);
-
- if (diff2[0] < diff[0]) {
- best[0] = avg[0];
- diff[0] = diff2[0];
- }
-
- if (diff2[1] < diff[1]) {
- best[1] = avg[1];
- diff[1] = diff2[1];
- }
-#endif
diff --git a/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h b/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h
deleted file mode 100644
index 7e8147ec..00000000
--- a/gst/deinterlace2/tvtime/tomsmocomp/tomsmocompmacros.h
+++ /dev/null
@@ -1,164 +0,0 @@
-#include <string.h>
-#include <math.h>
-
-// Define a few macros for CPU dependent instructions.
-// I suspect I don't really understand how the C macro preprocessor works but
-// this seems to get the job done. // TRB 7/01
-
-// BEFORE USING THESE YOU MUST SET:
-
-// #define SIMD_TYPE MMXEXT (or MMX or 3DNOW)
-
-// some macros for pavgb instruction
-// V_PAVGB(mmr1, mmr2, mmr work register, smask) mmr2 may = mmrw if you can trash it
-
-#define V_PAVGB_MMX(mmr1, mmr2, mmrw, smask) \
- "movq "mmr2", "mmrw"\n\t" \
- "pand "smask", "mmrw"\n\t" \
- "psrlw $1, "mmrw"\n\t" \
- "pand "smask", "mmr1"\n\t" \
- "psrlw $1, "mmr1"\n\t" \
- "paddusb "mmrw", "mmr1"\n\t"
-#define V_PAVGB_MMXEXT(mmr1, mmr2, mmrw, smask) "pavgb "mmr2", "mmr1"\n\t"
-#define V_PAVGB_3DNOW(mmr1, mmr2, mmrw, smask) "pavgusb "mmr2", "mmr1"\n\t"
-#define V_PAVGB(mmr1, mmr2, mmrw, smask) V_PAVGB2(mmr1, mmr2, mmrw, smask, SIMD_TYPE)
-#define V_PAVGB2(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type)
-#define V_PAVGB3(mmr1, mmr2, mmrw, smask, simd_type) V_PAVGB_##simd_type(mmr1, mmr2, mmrw, smask)
-
-// some macros for pmaxub instruction
-#define V_PMAXUB_MMX(mmr1, mmr2) \
- "psubusb "mmr2", "mmr1"\n\t" \
- "paddusb "mmr2", "mmr1"\n\t"
-#define V_PMAXUB_MMXEXT(mmr1, mmr2) "pmaxub "mmr2", "mmr1"\n\t"
-#define V_PMAXUB_3DNOW(mmr1, mmr2) V_PMAXUB_MMX(mmr1, mmr2) // use MMX version
-#define V_PMAXUB(mmr1, mmr2) V_PMAXUB2(mmr1, mmr2, SIMD_TYPE)
-#define V_PMAXUB2(mmr1, mmr2, simd_type) V_PMAXUB3(mmr1, mmr2, simd_type)
-#define V_PMAXUB3(mmr1, mmr2, simd_type) V_PMAXUB_##simd_type(mmr1, mmr2)
-
-// some macros for pminub instruction
-// V_PMINUB(mmr1, mmr2, mmr work register) mmr2 may NOT = mmrw
-#define V_PMINUB_MMX(mmr1, mmr2, mmrw) \
- "pcmpeqb "mmrw", "mmrw"\n\t" \
- "psubusb "mmr2", "mmrw"\n\t" \
- "paddusb "mmrw", "mmr1"\n\t" \
- "psubusb "mmrw", "mmr1"\n\t"
-#define V_PMINUB_MMXEXT(mmr1, mmr2, mmrw) "pminub "mmr2", "mmr1"\n\t"
-#define V_PMINUB_3DNOW(mmr1, mmr2, mmrw) V_PMINUB_MMX(mmr1, mmr2, mmrw) // use MMX version
-#define V_PMINUB(mmr1, mmr2, mmrw) V_PMINUB2(mmr1, mmr2, mmrw, SIMD_TYPE)
-#define V_PMINUB2(mmr1, mmr2, mmrw, simd_type) V_PMINUB3(mmr1, mmr2, mmrw, simd_type)
-#define V_PMINUB3(mmr1, mmr2, mmrw, simd_type) V_PMINUB_##simd_type(mmr1, mmr2, mmrw)
-
-// some macros for movntq instruction
-// V_MOVNTQ(mmr1, mmr2)
-#define V_MOVNTQ_MMX(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ_3DNOW(mmr1, mmr2) "movq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ_MMXEXT(mmr1, mmr2) "movntq "mmr2", "mmr1"\n\t"
-#define V_MOVNTQ(mmr1, mmr2) V_MOVNTQ2(mmr1, mmr2, SIMD_TYPE)
-#define V_MOVNTQ2(mmr1, mmr2, simd_type) V_MOVNTQ3(mmr1, mmr2, simd_type)
-#define V_MOVNTQ3(mmr1, mmr2, simd_type) V_MOVNTQ_##simd_type(mmr1, mmr2)
-
-// end of macros
-
-#ifdef IS_SSE2
-
-#define MERGE4PIXavg(PADDR1, PADDR2) \
- "movdqu "PADDR1", %%xmm0\n\t" /* our 4 pixels */ \
- "movdqu "PADDR2", %%xmm1\n\t" /* our pixel2 value */ \
- "movdqa %%xmm0, %%xmm2\n\t" /* another copy of our pixel1 value */ \
- "movdqa %%xmm1, %%xmm3\n\t" /* another copy of our pixel1 value */ \
- "psubusb %%xmm1, %%xmm2\n\t" \
- "psubusb %%xmm0, %%xmm3\n\t" \
- "por %%xmm3, %%xmm2\n\t" \
- "pavgb %%xmm1, %%xmm0\n\t" /* avg of 2 pixels */ \
- "movdqa %%xmm2, %%xmm3\n\t" /* another copy of our our weights */ \
- "pxor %%xmm1, %%xmm1\n\t" \
- "psubusb %%xmm7, %%xmm3\n\t" /* nonzero where old weights lower, else 0 */ \
- "pcmpeqb %%xmm1, %%xmm3\n\t" /* now ff where new better, else 00 */ \
- "pcmpeqb %%xmm3, %%xmm1\n\t" /* here ff where old better, else 00 */ \
- "pand %%xmm3, %%xmm0\n\t" /* keep only better new pixels */ \
- "pand %%xmm3, %%xmm2\n\t" /* and weights */ \
- "pand %%xmm1, %%xmm5\n\t" /* keep only better old pixels */ \
- "pand %%xmm1, %%xmm7\n\t" \
- "por %%xmm0, %%xmm5\n\t" /* and merge new & old vals */ \
- "por %%xmm2, %%xmm7\n\t"
-
-#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B) \
- "movdqu "PADDR1A", %%xmm0\n\t" /* our 4 pixels */ \
- "movdqu "PADDR2A", %%xmm1\n\t" /* our pixel2 value */ \
- "movdqu "PADDR1B", %%xmm2\n\t" /* our 4 pixels */ \
- "movdqu "PADDR2B", %%xmm3\n\t" /* our pixel2 value */ \
- "pavgb %%xmm2, %%xmm0\n\t" \
- "pavgb %%xmm3, %%xmm1\n\t" \
- "movdqa %%xmm0, %%xmm2\n\t" /* another copy of our pixel1 value */ \
- "movdqa %%xmm1, %%xmm3\n\t" /* another copy of our pixel1 value */ \
- "psubusb %%xmm1, %%xmm2\n\t" \
- "psubusb %%xmm0, %%xmm3\n\t" \
- "por %%xmm3, %%xmm2\n\t" \
- "pavgb %%xmm1, %%xmm0\n\t" /* avg of 2 pixels */ \
- "movdqa %%xmm2, %%xmm3\n\t" /* another copy of our our weights */ \
- "pxor %%xmm1, %%xmm1\n\t" \
- "psubusb %%xmm7, %%xmm3\n\t" /* nonzero where old weights lower, else 0 */ \
- "pcmpeqb %%xmm1, %%xmm3\n\t" /* now ff where new better, else 00 */ \
- "pcmpeqb %%xmm3, %%xmm1\n\t" /* here ff where old better, else 00 */ \
- "pand %%xmm3, %%xmm0\n\t" /* keep only better new pixels */ \
- "pand %%xmm3, %%xmm2\n\t" /* and weights */ \
- "pand %%xmm1, %%xmm5\n\t" /* keep only better old pixels */ \
- "pand %%xmm1, %%xmm7\n\t" \
- "por %%xmm0, %%xmm5\n\t" /* and merge new & old vals */ \
- "por %%xmm2, %%xmm7\n\t"
-
-#define RESET_CHROMA "por "_UVMask", %%xmm7\n\t"
-
-#else // ifdef IS_SSE2
-
-#define MERGE4PIXavg(PADDR1, PADDR2) \
- "movq "PADDR1", %%mm0\n\t" /* our 4 pixels */ \
- "movq "PADDR2", %%mm1\n\t" /* our pixel2 value */ \
- "movq %%mm0, %%mm2\n\t" /* another copy of our pixel1 value */ \
- "movq %%mm1, %%mm3\n\t" /* another copy of our pixel1 value */ \
- "psubusb %%mm1, %%mm2\n\t" \
- "psubusb %%mm0, %%mm3\n\t" \
- "por %%mm3, %%mm2\n\t" \
- V_PAVGB ("%%mm0", "%%mm1", "%%mm3", _ShiftMask) /* avg of 2 pixels */ \
- "movq %%mm2, %%mm3\n\t" /* another copy of our our weights */ \
- "pxor %%mm1, %%mm1\n\t" \
- "psubusb %%mm7, %%mm3\n\t" /* nonzero where old weights lower, else 0 */ \
- "pcmpeqb %%mm1, %%mm3\n\t" /* now ff where new better, else 00 */ \
- "pcmpeqb %%mm3, %%mm1\n\t" /* here ff where old better, else 00 */ \
- "pand %%mm3, %%mm0\n\t" /* keep only better new pixels */ \
- "pand %%mm3, %%mm2\n\t" /* and weights */ \
- "pand %%mm1, %%mm5\n\t" /* keep only better old pixels */ \
- "pand %%mm1, %%mm7\n\t" \
- "por %%mm0, %%mm5\n\t" /* and merge new & old vals */ \
- "por %%mm2, %%mm7\n\t"
-
-#define MERGE4PIXavgH(PADDR1A, PADDR1B, PADDR2A, PADDR2B) \
- "movq "PADDR1A", %%mm0\n\t" /* our 4 pixels */ \
- "movq "PADDR2A", %%mm1\n\t" /* our pixel2 value */ \
- "movq "PADDR1B", %%mm2\n\t" /* our 4 pixels */ \
- "movq "PADDR2B", %%mm3\n\t" /* our pixel2 value */ \
- V_PAVGB("%%mm0", "%%mm2", "%%mm2", _ShiftMask) \
- V_PAVGB("%%mm1", "%%mm3", "%%mm3", _ShiftMask) \
- "movq %%mm0, %%mm2\n\t" /* another copy of our pixel1 value */ \
- "movq %%mm1, %%mm3\n\t" /* another copy of our pixel1 value */ \
- "psubusb %%mm1, %%mm2\n\t" \
- "psubusb %%mm0, %%mm3\n\t" \
- "por %%mm3, %%mm2\n\t" \
- V_PAVGB("%%mm0", "%%mm1", "%%mm3", _ShiftMask) /* avg of 2 pixels */ \
- "movq %%mm2, %%mm3\n\t" /* another copy of our our weights */ \
- "pxor %%mm1, %%mm1\n\t" \
- "psubusb %%mm7, %%mm3\n\t" /* nonzero where old weights lower, else 0 */ \
- "pcmpeqb %%mm1, %%mm3\n\t" /* now ff where new better, else 00 */ \
- "pcmpeqb %%mm3, %%mm1\n\t" /* here ff where old better, else 00 */ \
- "pand %%mm3, %%mm0\n\t" /* keep only better new pixels */ \
- "pand %%mm3, %%mm2\n\t" /* and weights */ \
- "pand %%mm1, %%mm5\n\t" /* keep only better old pixels */ \
- "pand %%mm1, %%mm7\n\t" \
- "por %%mm0, %%mm5\n\t" /* and merge new & old vals */ \
- "por %%mm2, %%mm7\n\t"
-
-#define RESET_CHROMA "por "_UVMask", %%mm7\n\t"
-
-#endif
-
-
diff --git a/gst/deinterlace2/tvtime/vfir.c b/gst/deinterlace2/tvtime/vfir.c
deleted file mode 100644
index 56950459..00000000
--- a/gst/deinterlace2/tvtime/vfir.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (C) 2004 Billy Biggs <vektor@dumbterm.net>
- * Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
- * Copyright (C) 2008 Sebastian Dröge <slomo@collabora.co.uk>
- *
- * 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.
- */
-
-/*
- * This file contains code from ffmpeg, see http://ffmpeg.org/ (LGPL)
- * and modifications by Billy Biggs.
- *
- * Relicensed for GStreamer from GPL to LGPL with permit from Billy Biggs.
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_VFIR (gst_deinterlace_method_vfir_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_VFIR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR))
-#define GST_IS_DEINTERLACE_METHOD_VFIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR))
-#define GST_DEINTERLACE_METHOD_VFIR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass))
-#define GST_DEINTERLACE_METHOD_VFIR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIR))
-#define GST_DEINTERLACE_METHOD_VFIR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_VFIR, GstDeinterlaceMethodVFIRClass))
-#define GST_DEINTERLACE_METHOD_VFIR_CAST(obj) ((GstDeinterlaceMethodVFIR*)(obj))
-
-GType gst_deinterlace_method_vfir_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodVFIR;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodVFIRClass;
-
-/*
- * The MPEG2 spec uses a slightly harsher filter, they specify
- * [-1 8 2 8 -1]. ffmpeg uses a similar filter but with more of
- * a tendancy to blur than to use the local information. The
- * filter taps here are: [-1 4 2 4 -1].
- */
-
-/**
- * C implementation.
- */
-static inline void
-deinterlace_line_c (GstDeinterlaceMethod * self, GstDeinterlace2 * parent,
- guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width)
-{
- gint sum;
- guint8 *lum_m4 = scanlines->tt1;
- guint8 *lum_m3 = scanlines->t0;
- guint8 *lum_m2 = scanlines->m1;
- guint8 *lum_m1 = scanlines->b0;
- guint8 *lum = scanlines->bb1;
- gint size = width * 2;
-
- for (; size >= 0; size--) {
- sum = -lum_m4[0];
- sum += lum_m3[0] << 2;
- sum += lum_m2[0] << 1;
- sum += lum_m1[0] << 2;
- sum += -lum[0];
- dst[0] = (sum + 4) >> 3; // This needs to be clipped at 0 and 255: cm[(sum + 4) >> 3];
- lum_m4++;
- lum_m3++;
- lum_m2++;
- lum_m1++;
- lum++;
- dst++;
- }
-}
-
-#ifdef BUILD_X86_ASM
-#include "mmx.h"
-static void
-deinterlace_line_mmx (GstDeinterlaceMethod * self, GstDeinterlace2 * parent,
- guint8 * dst, GstDeinterlaceScanlineData * scanlines, gint width)
-{
- mmx_t rounder;
- guint8 *lum_m4 = scanlines->tt1;
- guint8 *lum_m3 = scanlines->t0;
- guint8 *lum_m2 = scanlines->m1;
- guint8 *lum_m1 = scanlines->b0;
- guint8 *lum = scanlines->bb1;
-
- rounder.uw[0] = 4;
- rounder.uw[1] = 4;
- rounder.uw[2] = 4;
- rounder.uw[3] = 4;
- pxor_r2r (mm7, mm7);
- movq_m2r (rounder, mm6);
-
- for (; width > 1; width -= 2) {
- movd_m2r (*lum_m4, mm0);
- movd_m2r (*lum_m3, mm1);
- movd_m2r (*lum_m2, mm2);
- movd_m2r (*lum_m1, mm3);
- movd_m2r (*lum, mm4);
- punpcklbw_r2r (mm7, mm0);
- punpcklbw_r2r (mm7, mm1);
- punpcklbw_r2r (mm7, mm2);
- punpcklbw_r2r (mm7, mm3);
- punpcklbw_r2r (mm7, mm4);
- paddw_r2r (mm3, mm1);
- psllw_i2r (1, mm2);
- paddw_r2r (mm4, mm0);
- psllw_i2r (2, mm1); // 2
- paddw_r2r (mm6, mm2);
- paddw_r2r (mm2, mm1);
- psubusw_r2r (mm0, mm1);
- psrlw_i2r (3, mm1); // 3
- packuswb_r2r (mm7, mm1);
- movd_r2m (mm1, *dst);
- lum_m4 += 4;
- lum_m3 += 4;
- lum_m2 += 4;
- lum_m1 += 4;
- lum += 4;
- dst += 4;
- }
- emms ();
-
- /* Handle odd widths */
- if (width > 0) {
- scanlines->tt1 = lum_m4;
- scanlines->t0 = lum_m3;
- scanlines->m1 = lum_m2;
- scanlines->b0 = lum_m1;
- scanlines->bb1 = lum;
-
- deinterlace_line_c (self, parent, dst, scanlines, width);
- }
-}
-#endif
-
-G_DEFINE_TYPE (GstDeinterlaceMethodVFIR, gst_deinterlace_method_vfir,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_vfir_class_init (GstDeinterlaceMethodVFIRClass * klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-#ifdef BUILD_X86_ASM
- guint cpu_flags = oil_cpu_get_flags ();
-#endif
-
- dim_class->fields_required = 2;
- dim_class->name = "Blur Vertical";
- dim_class->nick = "vfir";
- dim_class->latency = 0;
-
-#ifdef BUILD_X86_ASM
- if (cpu_flags & OIL_IMPL_FLAG_MMX) {
- dism_class->interpolate_scanline = deinterlace_line_mmx;
- } else {
- dism_class->interpolate_scanline = deinterlace_line_c;
- }
-#else
- dism_class->interpolate_scanline = deinterlace_line_c;
-#endif
-}
-
-static void
-gst_deinterlace_method_vfir_init (GstDeinterlaceMethodVFIR * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/weave.c b/gst/deinterlace2/tvtime/weave.c
deleted file mode 100644
index 09732a3a..00000000
--- a/gst/deinterlace2/tvtime/weave.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Weave frames
- * Copyright (C) 2002 Billy Biggs <vektor@dumbterm.net>.
- * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_WEAVE (gst_deinterlace_method_weave_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_WEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE))
-#define GST_IS_DEINTERLACE_METHOD_WEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE))
-#define GST_DEINTERLACE_METHOD_WEAVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass))
-#define GST_DEINTERLACE_METHOD_WEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeave))
-#define GST_DEINTERLACE_METHOD_WEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE, GstDeinterlaceMethodWeaveClass))
-#define GST_DEINTERLACE_METHOD_WEAVE_CAST(obj) ((GstDeinterlaceMethodWeave*)(obj))
-
-GType gst_deinterlace_method_weave_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeave;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveClass;
-
-
-static void
-deinterlace_scanline_weave (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m1, parent->row_stride);
-}
-
-static void
-copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent,
- guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m0, parent->row_stride);
-}
-
-G_DEFINE_TYPE (GstDeinterlaceMethodWeave, gst_deinterlace_method_weave,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_weave_class_init (GstDeinterlaceMethodWeaveClass * klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-
- dim_class->fields_required = 2;
- dim_class->name = "Weave";
- dim_class->nick = "weave";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_weave;
- dism_class->copy_scanline = copy_scanline;
-}
-
-static void
-gst_deinterlace_method_weave_init (GstDeinterlaceMethodWeave * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/weavebff.c b/gst/deinterlace2/tvtime/weavebff.c
deleted file mode 100644
index 4ddf5a51..00000000
--- a/gst/deinterlace2/tvtime/weavebff.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Weave frames, bottom-field-first.
- * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
- * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF (gst_deinterlace_method_weave_bff_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF))
-#define GST_IS_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF))
-#define GST_DEINTERLACE_METHOD_WEAVE_BFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass))
-#define GST_DEINTERLACE_METHOD_WEAVE_BFF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFF))
-#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_BFF, GstDeinterlaceMethodWeaveBFFClass))
-#define GST_DEINTERLACE_METHOD_WEAVE_BFF_CAST(obj) ((GstDeinterlaceMethodWeaveBFF*)(obj))
-
-GType gst_deinterlace_method_weave_bff_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveBFF;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveBFFClass;
-
-
-static void
-deinterlace_scanline_weave (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m1, parent->row_stride);
-}
-
-static void
-copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent,
- guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width)
-{
- /* FIXME: original code used m2 and m0 but this looks really bad */
- if (scanlines->bottom_field) {
- oil_memcpy (out, scanlines->bb2, parent->row_stride);
- } else {
- oil_memcpy (out, scanlines->bb0, parent->row_stride);
- }
-}
-
-G_DEFINE_TYPE (GstDeinterlaceMethodWeaveBFF, gst_deinterlace_method_weave_bff,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_weave_bff_class_init (GstDeinterlaceMethodWeaveBFFClass *
- klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-
- dim_class->fields_required = 3;
- dim_class->name = "Progressive: Bottom Field First";
- dim_class->nick = "weavebff";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_weave;
- dism_class->copy_scanline = copy_scanline;
-}
-
-static void
-gst_deinterlace_method_weave_bff_init (GstDeinterlaceMethodWeaveBFF * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/weavetff.c b/gst/deinterlace2/tvtime/weavetff.c
deleted file mode 100644
index 9411f51b..00000000
--- a/gst/deinterlace2/tvtime/weavetff.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Weave frames, top-field-first.
- * Copyright (C) 2003 Billy Biggs <vektor@dumbterm.net>.
- * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 "config.h"
-#endif
-
-#include "_stdint.h"
-#include "gstdeinterlace2.h"
-#include <string.h>
-
-#define GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF (gst_deinterlace_method_weave_tff_get_type ())
-#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF))
-#define GST_IS_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF))
-#define GST_DEINTERLACE_METHOD_WEAVE_TFF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass))
-#define GST_DEINTERLACE_METHOD_WEAVE_TFF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFF))
-#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DEINTERLACE_METHOD_WEAVE_TFF, GstDeinterlaceMethodWeaveTFFClass))
-#define GST_DEINTERLACE_METHOD_WEAVE_TFF_CAST(obj) ((GstDeinterlaceMethodWeaveTFF*)(obj))
-
-GType gst_deinterlace_method_weave_tff_get_type (void);
-
-typedef GstDeinterlaceSimpleMethod GstDeinterlaceMethodWeaveTFF;
-
-typedef GstDeinterlaceSimpleMethodClass GstDeinterlaceMethodWeaveTFFClass;
-
-
-static void
-deinterlace_scanline_weave (GstDeinterlaceMethod * self,
- GstDeinterlace2 * parent, guint8 * out,
- GstDeinterlaceScanlineData * scanlines, gint width)
-{
- oil_memcpy (out, scanlines->m1, parent->row_stride);
-}
-
-static void
-copy_scanline (GstDeinterlaceMethod * self, GstDeinterlace2 * parent,
- guint8 * out, GstDeinterlaceScanlineData * scanlines, gint width)
-{
- /* FIXME: original code used m2 and m0 but this looks really bad */
- if (scanlines->bottom_field) {
- oil_memcpy (out, scanlines->bb0, parent->row_stride);
- } else {
- oil_memcpy (out, scanlines->bb2, parent->row_stride);
- }
-}
-
-G_DEFINE_TYPE (GstDeinterlaceMethodWeaveTFF, gst_deinterlace_method_weave_tff,
- GST_TYPE_DEINTERLACE_SIMPLE_METHOD);
-
-static void
-gst_deinterlace_method_weave_tff_class_init (GstDeinterlaceMethodWeaveTFFClass *
- klass)
-{
- GstDeinterlaceMethodClass *dim_class = (GstDeinterlaceMethodClass *) klass;
- GstDeinterlaceSimpleMethodClass *dism_class =
- (GstDeinterlaceSimpleMethodClass *) klass;
-
- dim_class->fields_required = 3;
- dim_class->name = "Progressive: Top Field First";
- dim_class->nick = "weavetff";
- dim_class->latency = 0;
-
- dism_class->interpolate_scanline = deinterlace_scanline_weave;
- dism_class->copy_scanline = copy_scanline;
-}
-
-static void
-gst_deinterlace_method_weave_tff_init (GstDeinterlaceMethodWeaveTFF * self)
-{
-}
diff --git a/gst/deinterlace2/tvtime/x86-64_macros.inc b/gst/deinterlace2/tvtime/x86-64_macros.inc
deleted file mode 100644
index 2e9df758..00000000
--- a/gst/deinterlace2/tvtime/x86-64_macros.inc
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *
- * GStreamer
- * Copyright (C) 2004 Dirk Ziegelmeier <dziegel@gmx.de>
- *
- * 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.
- */
-
-/*
- *
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=163578
- */
-
-/*
- * This file is copied from TVTIME's sources.
- * Original author: Achim Schneider <batchall@mordor.ch>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef XAX
-
-#if defined (HAVE_CPU_I386) && !defined(HAVE_CPU_X86_64)
-
-#define XAX "eax"
-#define XBX "ebx"
-#define XCX "ecx"
-#define XDX "edx"
-#define XSI "esi"
-#define XDI "edi"
-#define XSP "esp"
-#define MOVX "movl"
-#define LEAX "leal"
-#define DECX "decl"
-#define PUSHX "pushl"
-#define POPX "popl"
-#define CMPX "cmpl"
-#define ADDX "addl"
-#define SHLX "shll"
-#define SHRX "shrl"
-#define SUBX "subl"
-
-#elif defined (HAVE_CPU_X86_64)
-
-#define XAX "rax"
-#define XBX "rbx"
-#define XCX "rcx"
-#define XDX "rdx"
-#define XSI "rsi"
-#define XDI "rdi"
-#define XSP "rsp"
-#define MOVX "movq"
-#define LEAX "leaq"
-#define DECX "decq"
-#define PUSHX "pushq"
-#define POPX "popq"
-#define CMPX "cmpq"
-#define ADDX "addq"
-#define SHLX "shlq"
-#define SHRX "shrq"
-#define SUBX "subq"
-
-#else
-#error Undefined architecture. Define either ARCH_X86 or ARCH_X86_64.
-#endif
-
-#endif
diff --git a/gst/dvdspu/Makefile.am b/gst/dvdspu/Makefile.am
index 4d75f76c..07a66357 100644
--- a/gst/dvdspu/Makefile.am
+++ b/gst/dvdspu/Makefile.am
@@ -1,13 +1,13 @@
plugin_LTLIBRARIES = libgstdvdspu.la
-libgstdvdspu_la_SOURCES = gstdvdspu.c gstdvdspu-render.c
+libgstdvdspu_la_SOURCES = gstdvdspu.c gstdvdspu-render.c gstspu-vobsub.c gstspu-vobsub-render.c gstspu-pgs.c
libgstdvdspu_la_CFLAGS = $(GST_CFLAGS)
libgstdvdspu_la_LIBADD = $(GST_LIBS)
libgstdvdspu_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdvdspu_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = gstdvdspu.h
+noinst_HEADERS = gstdvdspu.h gstspu-pgs.h gstspu-vobsub.h
EXTRA_DIST = Notes.txt
diff --git a/gst/dvdspu/gstdvdspu-render.c b/gst/dvdspu/gstdvdspu-render.c
index e3bae8b6..7731aed4 100644
--- a/gst/dvdspu/gstdvdspu-render.c
+++ b/gst/dvdspu/gstdvdspu-render.c
@@ -1,5 +1,6 @@
/* GStreamer DVD Sub-Picture Unit
* Copyright (C) 2007 Fluendo S.A. <info@fluendo.com>
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,338 +30,38 @@
GST_DEBUG_CATEGORY_EXTERN (dvdspu_debug);
#define GST_CAT_DEFAULT dvdspu_debug
-static void
-dvdspu_recalc_palette (GstDVDSpu * dvdspu,
- SpuColour * dest, guint8 * idx, guint8 * alpha)
-{
- SpuState *state = &dvdspu->spu_state;
- gint i;
-
- for (i = 0; i < 4; i++, dest++) {
- guint32 col = state->current_clut[idx[i]];
-
- dest->Y = (guint16) ((col >> 16) & 0xff) * alpha[i];
- /* U/V are stored as V/U in the clut words, so switch them */
- dest->U = (guint16) (col & 0xff) * alpha[i];
- dest->V = (guint16) ((col >> 8) & 0xff) * alpha[i];
- dest->A = alpha[i];
- }
-}
-
-/* Recalculate the main, HL & ChgCol palettes */
-static void
-dvdspu_update_palettes (GstDVDSpu * dvdspu, SpuState * state)
-{
- gint16 l, c;
- guint8 index[4]; /* Indices for the palette */
- guint8 alpha[4]; /* Alpha values the palette */
-
- if (state->main_pal_dirty) {
- dvdspu_recalc_palette (dvdspu, state->main_pal, state->main_idx,
- state->main_alpha);
-
- /* Need to refresh the hl_ctrl info copies of the main palette too */
- memcpy (state->hl_ctrl_i.pix_ctrl_i[0].pal_cache, state->main_pal,
- 4 * sizeof (SpuColour));
- memcpy (state->hl_ctrl_i.pix_ctrl_i[2].pal_cache, state->main_pal,
- 4 * sizeof (SpuColour));
-
- state->main_pal_dirty = FALSE;
- }
-
- if (state->hl_pal_dirty) {
- dvdspu_recalc_palette (dvdspu, state->hl_ctrl_i.pix_ctrl_i[1].pal_cache,
- state->hl_idx, state->hl_alpha);
- state->hl_pal_dirty = FALSE;
- }
-
- /* Update the offset positions for the highlight region */
- if (state->hl_rect.top != -1) {
- state->hl_ctrl_i.top = state->hl_rect.top;
- state->hl_ctrl_i.bottom = state->hl_rect.bottom;
- state->hl_ctrl_i.n_changes = 3;
- state->hl_ctrl_i.pix_ctrl_i[0].left = 0;
- state->hl_ctrl_i.pix_ctrl_i[1].left = state->hl_rect.left;
- state->hl_ctrl_i.pix_ctrl_i[2].left = state->hl_rect.right + 1;
- }
-
- if (state->line_ctrl_i_pal_dirty) {
- GST_LOG_OBJECT (dvdspu, "Updating chg-col-con palettes");
- for (l = 0; l < state->n_line_ctrl_i; l++) {
- SpuLineCtrlI *cur_line_ctrl = state->line_ctrl_i + l;
-
- for (c = 0; c < cur_line_ctrl->n_changes; c++) {
- SpuPixCtrlI *cur = cur_line_ctrl->pix_ctrl_i + c;
-
- index[3] = (cur->palette >> 28) & 0x0f;
- index[2] = (cur->palette >> 24) & 0x0f;
- index[1] = (cur->palette >> 20) & 0x0f;
- index[0] = (cur->palette >> 16) & 0x0f;
-
- alpha[3] = (cur->palette >> 12) & 0x0f;
- alpha[2] = (cur->palette >> 8) & 0x0f;
- alpha[1] = (cur->palette >> 4) & 0x0f;
- alpha[0] = (cur->palette) & 0x0f;
- dvdspu_recalc_palette (dvdspu, cur->pal_cache, index, alpha);
- }
- }
- state->line_ctrl_i_pal_dirty = FALSE;
- }
-}
-
-static void
-dvdspu_clear_comp_buffers (SpuState * state)
+void
+gstspu_clear_comp_buffers (SpuState * state)
{
- /* The area to clear is the line inside the disp_rect, each entry 2 bytes,
+ /* The area to clear is the line inside the disp_rect, each entry 4 bytes,
* of the sub-sampled UV planes. */
- gint16 left = state->disp_rect.left / 2;
- gint16 right = state->disp_rect.right / 2;
- gint16 uv_width = 2 * (right - left + 1);
+ gint16 left = state->comp_left / 2;
+ gint16 right = state->comp_right / 2;
+ gint16 uv_width = sizeof (guint32) * (right - left + 1);
memset (state->comp_bufs[0] + left, 0, uv_width);
memset (state->comp_bufs[1] + left, 0, uv_width);
memset (state->comp_bufs[2] + left, 0, uv_width);
-
- state->comp_last_x[0] = -1;
- state->comp_last_x[1] = -1;
-}
-
-static inline guint8
-dvdspu_get_nibble (SpuState * state, guint16 * rle_offset)
-{
- guint8 ret;
-
- if (G_UNLIKELY (*rle_offset >= state->max_offset))
- return 0; /* Overran the buffer */
-
- ret = GST_BUFFER_DATA (state->pix_buf)[(*rle_offset) / 2];
-
- /* If the offset is even, we shift the answer down 4 bits, otherwise not */
- if (*rle_offset & 0x01)
- ret &= 0x0f;
- else
- ret = ret >> 4;
-
- (*rle_offset)++;
- return ret;
}
-static guint16
-dvdspu_get_rle_code (SpuState * state, guint16 * rle_offset)
-{
- guint16 code;
-
- code = dvdspu_get_nibble (state, rle_offset);
- if (code < 0x4) { /* 4 .. f */
- code = (code << 4) | dvdspu_get_nibble (state, rle_offset);
- if (code < 0x10) { /* 1x .. 3x */
- code = (code << 4) | dvdspu_get_nibble (state, rle_offset);
- if (code < 0x40) { /* 04x .. 0fx */
- code = (code << 4) | dvdspu_get_nibble (state, rle_offset);
- }
- }
- }
- return code;
-}
-
-static inline void
-dvdspu_draw_rle_run (SpuState * state, gint16 x, gint16 end, SpuColour * colour)
-{
-#if 0
- GST_LOG ("Y: %d x: %d end %d col %d %d %d %d",
- state->cur_Y, x, end, colour->Y, colour->U, colour->V, colour->A);
-#endif
-
- if (colour->A != 0) {
- guint8 inv_A = 0xf - colour->A;
-
- /* FIXME: This could be more efficient */
- while (x < end) {
- state->out_Y[x] = (inv_A * state->out_Y[x] + colour->Y) / 0xf;
- state->out_U[x / 2] += colour->U;
- state->out_V[x / 2] += colour->V;
- state->out_A[x / 2] += colour->A;
- x++;
- }
- /* Update the compositing buffer so we know how much to blend later */
- *(state->comp_last_x_ptr) = end;
- }
-}
-
-static inline gint16
-rle_end_x (guint16 rle_code, gint16 x, gint16 end)
-{
- /* run length = rle_code >> 2 */
- if (G_UNLIKELY (((rle_code >> 2) == 0)))
- return end;
- else
- return MIN (end, x + (rle_code >> 2));
-}
-
-static void dvdspu_render_line_with_chgcol (SpuState * state,
- guint8 * planes[3], guint16 * rle_offset);
-static gboolean dvdspu_update_chgcol (SpuState * state);
-
-static void
-dvdspu_render_line (SpuState * state, guint8 * planes[3], guint16 * rle_offset)
-{
- gint16 x, next_x, end, rle_code;
- SpuColour *colour;
-
- /* Check for special case of chg_col info to use (either highlight or
- * ChgCol command */
- if (state->cur_chg_col != NULL) {
- if (dvdspu_update_chgcol (state)) {
- /* Check the top & bottom, because we might not be within the region yet */
- if (state->cur_Y >= state->cur_chg_col->top &&
- state->cur_Y <= state->cur_chg_col->bottom) {
- dvdspu_render_line_with_chgcol (state, planes, rle_offset);
- return;
- }
- }
- }
-
- /* No special case. Render as normal */
-
- /* Set up our output pointers */
- state->out_Y = planes[0];
- state->out_U = state->comp_bufs[0];
- state->out_V = state->comp_bufs[1];
- state->out_A = state->comp_bufs[2];
- /* We always need to start our RLE decoding byte_aligned */
- *rle_offset = GST_ROUND_UP_2 (*rle_offset);
-
- x = state->disp_rect.left;
- end = state->disp_rect.right + 1;
- while (x < end) {
- rle_code = dvdspu_get_rle_code (state, rle_offset);
- colour = &state->main_pal[rle_code & 3];
- next_x = rle_end_x (rle_code, x, end);
- /* Now draw the run between [x,next_x) */
- dvdspu_draw_rle_run (state, x, next_x, colour);
- x = next_x;
- }
-}
-
-static gboolean
-dvdspu_update_chgcol (SpuState * state)
-{
- if (state->cur_chg_col == NULL)
- return FALSE;
-
- if (state->cur_Y <= state->cur_chg_col->bottom)
- return TRUE;
-
- while (state->cur_chg_col < state->cur_chg_col_end) {
- if (state->cur_Y >= state->cur_chg_col->top &&
- state->cur_Y <= state->cur_chg_col->bottom) {
-#if 0
- g_print ("Stopped @ entry %d with top %d bottom %d, cur_y %d",
- (gint16) (state->cur_chg_col - state->line_ctrl_i),
- state->cur_chg_col->top, state->cur_chg_col->bottom, y);
-#endif
- return TRUE;
- }
- state->cur_chg_col++;
- }
-
- /* Finished all our cur_chg_col entries. Use the main palette from here on */
- state->cur_chg_col = NULL;
- return FALSE;
-}
-
-static void
-dvdspu_render_line_with_chgcol (SpuState * state, guint8 * planes[3],
- guint16 * rle_offset)
-{
- SpuLineCtrlI *chg_col = state->cur_chg_col;
-
- gint16 x, next_x, disp_end, rle_code, run_end;
- SpuColour *colour;
- SpuPixCtrlI *cur_pix_ctrl;
- SpuPixCtrlI *next_pix_ctrl;
- SpuPixCtrlI *end_pix_ctrl;
- SpuPixCtrlI dummy_pix_ctrl;
- gint16 cur_reg_end;
- gint i;
-
- state->out_Y = planes[0];
- state->out_U = state->comp_bufs[0];
- state->out_V = state->comp_bufs[1];
- state->out_A = state->comp_bufs[2];
-
- /* We always need to start our RLE decoding byte_aligned */
- *rle_offset = GST_ROUND_UP_2 (*rle_offset);
-
- /* Our run will cover the display rect */
- x = state->disp_rect.left;
- disp_end = state->disp_rect.right + 1;
-
- /* Work out the first pixel control info, which may point to the dummy entry if
- * the global palette/alpha need using initally */
- cur_pix_ctrl = chg_col->pix_ctrl_i;
- end_pix_ctrl = chg_col->pix_ctrl_i + chg_col->n_changes;
-
- if (cur_pix_ctrl->left != 0) {
- next_pix_ctrl = cur_pix_ctrl;
- cur_pix_ctrl = &dummy_pix_ctrl;
- for (i = 0; i < 4; i++) /* Copy the main palette to our dummy entry */
- dummy_pix_ctrl.pal_cache[i] = state->main_pal[i];
- } else {
- next_pix_ctrl = cur_pix_ctrl + 1;
- }
- if (next_pix_ctrl < end_pix_ctrl)
- cur_reg_end = next_pix_ctrl->left;
- else
- cur_reg_end = disp_end;
-
- /* Render stuff */
- while (x < disp_end) {
- rle_code = dvdspu_get_rle_code (state, rle_offset);
- next_x = rle_end_x (rle_code, x, disp_end);
-
- /* Now draw the run between [x,next_x), crossing palette regions as needed */
- while (x < next_x) {
- run_end = MIN (next_x, cur_reg_end);
-
- if (G_LIKELY (x < run_end)) {
- colour = &cur_pix_ctrl->pal_cache[rle_code & 3];
- dvdspu_draw_rle_run (state, x, run_end, colour);
- x = run_end;
- }
-
- if (x >= cur_reg_end) {
- /* Advance to next region */
- cur_pix_ctrl = next_pix_ctrl;
- next_pix_ctrl++;
-
- if (next_pix_ctrl < end_pix_ctrl)
- cur_reg_end = next_pix_ctrl->left;
- else
- cur_reg_end = disp_end;
- }
- }
- }
-}
-
-static void
-dvdspu_blend_comp_buffers (SpuState * state, guint8 * planes[3])
+void
+gstspu_blend_comp_buffers (SpuState * state, guint8 * planes[3])
{
gint16 uv_end;
gint16 left, x;
guint8 *out_U;
guint8 *out_V;
- guint16 *in_U;
- guint16 *in_V;
- guint16 *in_A;
- gint16 comp_last_x = MAX (state->comp_last_x[0], state->comp_last_x[1]);
+ guint32 *in_U;
+ guint32 *in_V;
+ guint32 *in_A;
+ gint16 comp_last_x = state->comp_right;
- if (comp_last_x < state->disp_rect.left)
+ if (comp_last_x < state->comp_left)
return; /* Didn't draw in the comp buffers, nothing to do... */
#if 0
- GST_LOG ("Blending comp buffers from disp_rect.left %d to x=%d",
- state->disp_rect.left, comp_last_x);
+ GST_LOG ("Blending comp buffers from x=%d to x=%d",
+ state->comp_left, state->comp_right);
#endif
/* Set up the output pointers */
@@ -376,186 +77,18 @@ dvdspu_blend_comp_buffers (SpuState * state, guint8 * planes[3])
* drawn in the render_line function, divided by 2 (rounding up) to account
* for UV sub-sampling */
uv_end = (comp_last_x + 1) / 2;
- left = state->disp_rect.left / 2;
+ left = state->comp_left / 2;
for (x = left; x < uv_end; x++) {
- guint16 tmp;
- guint16 inv_A = (4 * 0xf) - in_A[x];
-
+ guint32 tmp;
/* Each entry in the compositing buffer is 4 summed pixels, so the
- * inverse alpha is (4 * 0x0f) - in_A[x] */
+ * inverse alpha is (4 * 0xff) - in_A[x] */
+ guint16 inv_A = (4 * 0xff) - in_A[x];
+
tmp = in_U[x] + inv_A * out_U[x];
- out_U[x] = (guint8) (tmp / (4 * 0xf));
+ out_U[x] = (guint8) (tmp / (4 * 0xff));
tmp = in_V[x] + inv_A * out_V[x];
- out_V[x] = (guint8) (tmp / (4 * 0xf));
- }
-}
-
-void
-gst_dvd_spu_render_spu (GstDVDSpu * dvdspu, GstBuffer * buf)
-{
- SpuState *state = &dvdspu->spu_state;
- guint8 *planes[3]; /* YUV frame pointers */
- gint y, last_y;
-
- /* Set up our initial state */
-
- /* Store the start of each plane */
- planes[0] = GST_BUFFER_DATA (buf);
- planes[1] = planes[0] + (state->Y_height * state->Y_stride);
- planes[2] = planes[1] + (state->UV_height * state->UV_stride);
-
- /* Sanity check */
- g_return_if_fail (planes[2] + (state->UV_height * state->UV_stride) <=
- GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf));
-
- GST_DEBUG ("Rendering SPU. disp_rect %d,%d to %d,%d. hl_rect %d,%d to %d,%d",
- state->disp_rect.left, state->disp_rect.top,
- state->disp_rect.right, state->disp_rect.bottom,
- state->hl_rect.left, state->hl_rect.top,
- state->hl_rect.right, state->hl_rect.bottom);
-
- GST_DEBUG ("vid_disp %d,%d", state->vid_width, state->vid_height);
-
- /* When reading RLE data, we track the offset in nibbles... */
- state->cur_offsets[0] = state->pix_data[0] * 2;
- state->cur_offsets[1] = state->pix_data[1] * 2;
- state->max_offset = GST_BUFFER_SIZE (state->pix_buf) * 2;
-
- /* Update all the palette caches */
- dvdspu_update_palettes (dvdspu, state);
-
- /* Set up HL or Change Color & Contrast rect tracking */
- if (state->hl_rect.top != -1) {
- state->cur_chg_col = &state->hl_ctrl_i;
- state->cur_chg_col_end = state->cur_chg_col + 1;
- } else if (state->n_line_ctrl_i > 0) {
- state->cur_chg_col = state->line_ctrl_i;
- state->cur_chg_col_end = state->cur_chg_col + state->n_line_ctrl_i;
- } else
- state->cur_chg_col = NULL;
-
- /* We start rendering from the first line of the display rect */
- y = state->disp_rect.top;
- /* start_y is always an even number and we render lines in pairs from there,
- * accumulating 2 lines of chroma then blending it. We might need to render a
- * single line at the end if the display rect ends on an even line too. */
- last_y = (state->disp_rect.bottom - 1) & ~(0x01);
-
- /* center the image when display rectangle exceeds the video width */
- if (state->vid_width < state->disp_rect.right) {
- gint diff, disp_width;
-
- disp_width = state->disp_rect.left - state->disp_rect.right;
- diff = (disp_width - state->vid_width) / 2;
-
- /* fixme, this is not used yet */
- state->clip_rect.left = state->disp_rect.left + diff;
- state->clip_rect.right = state->disp_rect.right - diff;
-
- GST_DEBUG ("clipping width to %d,%d", state->clip_rect.left,
- state->clip_rect.right);
- } else {
- state->clip_rect.left = state->disp_rect.left;
- state->clip_rect.right = state->disp_rect.right;
- }
-
- /* for the height, chop off the bottom bits of the diplay rectangle because we
- * assume the picture is in the lower part. We should better check where it
- * is and do something more clever. */
- state->clip_rect.bottom = state->disp_rect.bottom;
- if (state->vid_height < state->disp_rect.bottom) {
- state->clip_rect.top = state->disp_rect.bottom - state->vid_height;
- GST_DEBUG ("clipping height to %d,%d", state->clip_rect.top,
- state->clip_rect.bottom);
- } else {
- state->clip_rect.top = state->disp_rect.top;
- /* Update our plane references to the first line of the disp_rect */
- planes[0] += state->Y_stride * y;
- planes[1] += state->UV_stride * (y / 2);
- planes[2] += state->UV_stride * (y / 2);
- }
-
- for (state->cur_Y = y; state->cur_Y <= last_y; state->cur_Y++) {
- gboolean clip;
-
- clip = (state->cur_Y < state->clip_rect.top
- || state->cur_Y > state->clip_rect.bottom);
-
- /* Reset the compositing buffer */
- dvdspu_clear_comp_buffers (state);
- /* Render even line */
- state->comp_last_x_ptr = state->comp_last_x;
- dvdspu_render_line (state, planes, &state->cur_offsets[0]);
- if (!clip) {
- /* Advance the luminance output pointer */
- planes[0] += state->Y_stride;
- }
- state->cur_Y++;
-
- /* Render odd line */
- state->comp_last_x_ptr = state->comp_last_x + 1;
- dvdspu_render_line (state, planes, &state->cur_offsets[1]);
- /* Blend the accumulated UV compositing buffers onto the output */
- dvdspu_blend_comp_buffers (state, planes);
-
- if (!clip) {
- /* Update all the output pointers */
- planes[0] += state->Y_stride;
- planes[1] += state->UV_stride;
- planes[2] += state->UV_stride;
- }
- }
- if (state->cur_Y == state->disp_rect.bottom) {
- g_assert ((state->disp_rect.bottom & 0x01) == 0);
-
- /* Render a remaining lone last even line. y already has the correct value
- * after the above loop exited. */
- dvdspu_clear_comp_buffers (state);
- state->comp_last_x_ptr = state->comp_last_x;
- dvdspu_render_line (state, planes, &state->cur_offsets[0]);
- dvdspu_blend_comp_buffers (state, planes);
+ out_V[x] = (guint8) (tmp / (4 * 0xff));
}
-
- /* for debugging purposes, draw a faint rectangle at the edges of the disp_rect */
-#if 0
- do {
- guint8 *cur;
- gint16 pos;
-
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->disp_rect.top;
- for (pos = state->disp_rect.left + 1; pos < state->disp_rect.right; pos++)
- cur[pos] = (cur[pos] / 2) + 0x8;
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->disp_rect.bottom;
- for (pos = state->disp_rect.left + 1; pos < state->disp_rect.right; pos++)
- cur[pos] = (cur[pos] / 2) + 0x8;
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->disp_rect.top;
- for (pos = state->disp_rect.top; pos <= state->disp_rect.bottom; pos++) {
- cur[state->disp_rect.left] = (cur[state->disp_rect.left] / 2) + 0x8;
- cur[state->disp_rect.right] = (cur[state->disp_rect.right] / 2) + 0x8;
- cur += state->Y_stride;
- }
- } while (0);
-#endif
- /* For debugging purposes, draw a faint rectangle around the highlight rect */
-#if 0
- if (state->hl_rect.top != -1) {
- guint8 *cur;
- gint16 pos;
-
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.top;
- for (pos = state->hl_rect.left + 1; pos < state->hl_rect.right; pos++)
- cur[pos] = (cur[pos] / 2) + 0x8;
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.bottom;
- for (pos = state->hl_rect.left + 1; pos < state->hl_rect.right; pos++)
- cur[pos] = (cur[pos] / 2) + 0x8;
- cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.top;
- for (pos = state->hl_rect.top; pos <= state->hl_rect.bottom; pos++) {
- cur[state->hl_rect.left] = (cur[state->hl_rect.left] / 2) + 0x8;
- cur[state->hl_rect.right] = (cur[state->hl_rect.right] / 2) + 0x8;
- cur += state->Y_stride;
- }
- }
-#endif
}
diff --git a/gst/dvdspu/gstdvdspu.c b/gst/dvdspu/gstdvdspu.c
index 3b4c1a0c..f5fce4bc 100644
--- a/gst/dvdspu/gstdvdspu.c
+++ b/gst/dvdspu/gstdvdspu.c
@@ -32,22 +32,17 @@
# include <config.h>
#endif
+#include <gst/gst-i18n-plugin.h>
+
#include <string.h>
#include <gst/gst.h>
#include "gstdvdspu.h"
-#define DUMP_DCSQ 0
-
-extern void gst_dvd_spu_render_spu (GstDVDSpu * dvdspu, GstBuffer * buf);
-
GST_DEBUG_CATEGORY (dvdspu_debug);
#define GST_CAT_DEFAULT dvdspu_debug
-/* Convert an STM offset in the SPU sequence to a GStreamer timestamp */
-#define STM_TO_GST(stm) ((GST_MSECOND * 1024 * (stm)) / 90)
-
/* Filter signals and args */
enum
{
@@ -73,12 +68,19 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
);
static GstStaticPadTemplate subpic_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("subpicture",
+ GST_STATIC_PAD_TEMPLATE ("subpicture",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-dvd-subpicture")
+ GST_STATIC_CAPS ("video/x-dvd-subpicture; subpicture/x-pgs")
);
+static const guint32 default_clut[16] = {
+ 0xb48080, 0x248080, 0x628080, 0xd78080,
+ 0x808080, 0x808080, 0x808080, 0x808080,
+ 0x808080, 0x808080, 0x808080, 0x808080,
+ 0x808080, 0x808080, 0x808080, 0x808080
+};
+
GST_BOILERPLATE (GstDVDSpu, gst_dvd_spu, GstElement, GST_TYPE_ELEMENT);
static void gst_dvd_spu_dispose (GObject * object);
@@ -94,27 +96,31 @@ static GstFlowReturn gst_dvd_spu_video_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_dvd_spu_video_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_dvd_spu_buffer_alloc (GstPad * sinkpad, guint64 offset,
guint size, GstCaps * caps, GstBuffer ** buf);
-static void gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu);
+static void gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu, gboolean force);
static void gst_dvd_spu_check_still_updates (GstDVDSpu * dvdspu);
static GstFlowReturn gst_dvd_spu_subpic_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_dvd_spu_subpic_event (GstPad * pad, GstEvent * event);
+static gboolean gst_dvd_spu_subpic_set_caps (GstPad * pad, GstCaps * caps);
static void gst_dvd_spu_clear (GstDVDSpu * dvdspu);
-static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu);
+static void gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu,
+ gboolean process_events);
static void gst_dvd_spu_advance_spu (GstDVDSpu * dvdspu, GstClockTime new_ts);
+static void gstspu_render (GstDVDSpu * dvdspu, GstBuffer * buf);
static GstFlowReturn
dvdspu_handle_vid_buffer (GstDVDSpu * dvdspu, GstBuffer * buf);
+static void gst_dvd_spu_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event);
static void
gst_dvd_spu_base_init (gpointer gclass)
{
static GstElementDetails element_details =
- GST_ELEMENT_DETAILS ("Fluendo DVD Player Sub-picture Overlay",
- "Mixer/Video/Overlay/DVD",
- "Parses the DVD Sub-Picture command stream and renders the SPU overlay "
+ GST_ELEMENT_DETAILS ("GStreamer Sub-picture Overlay",
+ "Mixer/Video/Overlay/DVD/Bluray",
+ "Parses Sub-Picture command streams and renders the SPU overlay "
"onto the video as it passes through",
- "Jan Schmidt <jan@fluendo.com>");
+ "Jan Schmidt <thaytan@noraisin.net>");
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_add_pad_template (element_class,
@@ -164,7 +170,8 @@ gst_dvd_spu_init (GstDVDSpu * dvdspu, GstDVDSpuClass * gclass)
gst_pad_new_from_static_template (&subpic_sink_factory, "subpicture");
gst_pad_set_chain_function (dvdspu->subpic_sinkpad, gst_dvd_spu_subpic_chain);
gst_pad_set_event_function (dvdspu->subpic_sinkpad, gst_dvd_spu_subpic_event);
- gst_pad_use_fixed_caps (dvdspu->subpic_sinkpad);
+ gst_pad_set_setcaps_function (dvdspu->subpic_sinkpad,
+ gst_dvd_spu_subpic_set_caps);
gst_element_add_pad (GST_ELEMENT (dvdspu), dvdspu->videosinkpad);
gst_element_add_pad (GST_ELEMENT (dvdspu), dvdspu->subpic_sinkpad);
@@ -179,7 +186,10 @@ gst_dvd_spu_init (GstDVDSpu * dvdspu, GstDVDSpuClass * gclass)
static void
gst_dvd_spu_clear (GstDVDSpu * dvdspu)
{
- gst_dvd_spu_flush_spu_info (dvdspu);
+ gst_dvd_spu_flush_spu_info (dvdspu, FALSE);
+ gst_segment_init (&dvdspu->subp_seg, GST_FORMAT_UNDEFINED);
+
+ dvdspu->spu_input_type = SPU_INPUT_TYPE_NONE;
gst_buffer_replace (&dvdspu->ref_frame, NULL);
gst_buffer_replace (&dvdspu->pending_frame, NULL);
@@ -223,15 +233,14 @@ gst_dvd_spu_finalize (GObject * object)
/* With SPU lock held, clear the queue of SPU packets */
static void
-gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu)
+gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu, gboolean keep_events)
{
SpuPacket *packet;
SpuState *state = &dvdspu->spu_state;
+ GQueue tmp_q = G_QUEUE_INIT;
GST_INFO_OBJECT (dvdspu, "Flushing SPU information");
- gst_segment_init (&dvdspu->subp_seg, GST_FORMAT_UNDEFINED);
-
if (dvdspu->partial_spu) {
gst_buffer_unref (dvdspu->partial_spu);
dvdspu->partial_spu = NULL;
@@ -239,38 +248,37 @@ gst_dvd_spu_flush_spu_info (GstDVDSpu * dvdspu)
packet = (SpuPacket *) g_queue_pop_head (dvdspu->pending_spus);
while (packet != NULL) {
- if (packet->buf)
+ if (packet->buf) {
gst_buffer_unref (packet->buf);
- if (packet->event)
- gst_event_unref (packet->event);
- g_free (packet);
+ g_assert (packet->event == NULL);
+ g_free (packet);
+ } else if (packet->event) {
+ if (keep_events) {
+ g_queue_push_tail (&tmp_q, packet);
+ } else {
+ gst_event_unref (packet->event);
+ g_free (packet);
+ }
+ }
packet = (SpuPacket *) g_queue_pop_head (dvdspu->pending_spus);
}
+ /* Push anything we decided to keep back onto the pending_spus list */
+ for (packet = g_queue_pop_head (&tmp_q); packet != NULL;
+ packet = g_queue_pop_head (&tmp_q))
+ g_queue_push_tail (dvdspu->pending_spus, packet);
- if (state->buf) {
- gst_buffer_unref (state->buf);
- state->buf = NULL;
- }
- if (state->pix_buf) {
- gst_buffer_unref (state->pix_buf);
- state->pix_buf = NULL;
- }
-
- state->base_ts = state->next_ts = GST_CLOCK_TIME_NONE;
state->flags &= ~(SPU_STATE_FLAGS_MASK);
- state->pix_data[0] = 0;
- state->pix_data[1] = 0;
+ state->next_ts = GST_CLOCK_TIME_NONE;
- state->hl_rect.top = -1;
- state->hl_rect.bottom = -1;
-
- state->disp_rect.top = -1;
- state->disp_rect.bottom = -1;
-
- state->n_line_ctrl_i = 0;
- if (state->line_ctrl_i != NULL) {
- g_free (state->line_ctrl_i);
- state->line_ctrl_i = NULL;
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ gstspu_vobsub_flush (dvdspu);
+ break;
+ case SPU_INPUT_TYPE_PGS:
+ gstspu_pgs_flush (dvdspu);
+ break;
+ default:
+ break;
}
}
@@ -342,7 +350,7 @@ gst_dvd_spu_video_set_caps (GstPad * pad, GstCaps * caps)
state->UV_stride = GST_ROUND_UP_4 (state->Y_stride / 2);
for (i = 0; i < 3; i++) {
state->comp_bufs[i] = g_realloc (state->comp_bufs[i],
- sizeof (guint16) * state->UV_stride);
+ sizeof (guint32) * state->UV_stride);
}
}
DVD_SPU_UNLOCK (dvdspu);
@@ -413,13 +421,16 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event)
break;
}
- GST_DEBUG_OBJECT (dvdspu,
- "DVD event of type %s on video pad", event_type);
-
if (strcmp (event_type, "dvd-still") == 0) {
gboolean in_still;
if (gst_structure_get_boolean (structure, "still-state", &in_still)) {
+ GstBuffer *to_push = NULL;
+
+ GST_DEBUG_OBJECT (dvdspu,
+ "DVD event of type %s on video pad: in-still = %d", event_type,
+ in_still);
+
DVD_SPU_LOCK (dvdspu);
if (in_still) {
state->flags |= SPU_STATE_STILL_FRAME;
@@ -429,15 +440,24 @@ gst_dvd_spu_video_event (GstPad * pad, GstEvent * event)
/* And re-draw the still frame to make sure it appears on
* screen, otherwise the last frame might have been discarded
* by QoS */
- gst_dvd_spu_redraw_still (dvdspu);
- } else
+ gst_dvd_spu_redraw_still (dvdspu, TRUE);
+ to_push = dvdspu->pending_frame;
+ dvdspu->pending_frame = NULL;
+
+ } else {
state->flags &= ~(SPU_STATE_STILL_FRAME);
+ }
DVD_SPU_UNLOCK (dvdspu);
+ if (to_push)
+ gst_pad_push (dvdspu->srcpad, to_push);
}
gst_event_unref (event);
res = TRUE;
- } else
+ } else {
+ GST_DEBUG_OBJECT (dvdspu,
+ "DVD event of type %s on video pad", event_type);
res = gst_pad_event_default (pad, event);
+ }
break;
}
case GST_EVENT_NEWSEGMENT:
@@ -602,7 +622,7 @@ dvdspu_handle_vid_buffer (GstDVDSpu * dvdspu, GstBuffer * buf)
/* Render the SPU overlay onto the buffer */
buf = gst_buffer_make_writable (buf);
- gst_dvd_spu_render_spu (dvdspu, buf);
+ gstspu_render (dvdspu, buf);
} else {
if (using_ref == FALSE) {
/* Not going to draw anything on this frame, just store a reference
@@ -631,17 +651,35 @@ no_ref_frame:
return GST_FLOW_OK;
}
+
+static void
+gstspu_render (GstDVDSpu * dvdspu, GstBuffer * buf)
+{
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ gstspu_vobsub_render (dvdspu, buf);
+ break;
+ case SPU_INPUT_TYPE_PGS:
+ gstspu_pgs_render (dvdspu, buf);
+ break;
+ default:
+ break;
+ }
+}
+
/* With SPU LOCK */
static void
-gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu)
+gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu, gboolean force)
{
/* If we have an active SPU command set and a reference frame, copy the
* frame, redraw the SPU and store it as the pending frame for output */
if (dvdspu->ref_frame) {
- if ((dvdspu->spu_state.flags & SPU_STATE_FORCED_DSP) ||
- ((dvdspu->spu_state.flags & SPU_STATE_FORCED_ONLY) == 0 &&
- (dvdspu->spu_state.flags & SPU_STATE_DISPLAY))) {
- GstBuffer *buf = gst_buffer_copy (dvdspu->ref_frame);
+ gboolean redraw = (dvdspu->spu_state.flags & SPU_STATE_FORCED_DSP);
+ redraw |= (dvdspu->spu_state.flags & SPU_STATE_FORCED_ONLY) == 0 &&
+ (dvdspu->spu_state.flags & SPU_STATE_DISPLAY);
+
+ if (redraw) {
+ GstBuffer *buf = gst_buffer_ref (dvdspu->ref_frame);
buf = gst_buffer_make_writable (buf);
@@ -652,11 +690,23 @@ gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu)
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
/* Render the SPU overlay onto the buffer */
- gst_dvd_spu_render_spu (dvdspu, buf);
+ gstspu_render (dvdspu, buf);
gst_buffer_replace (&dvdspu->pending_frame, buf);
+ gst_buffer_unref (buf);
+ } else if (force) {
+ /* Simply output the reference frame */
+ GstBuffer *buf = gst_buffer_ref (dvdspu->ref_frame);
+ buf = gst_buffer_make_metadata_writable (buf);
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+ GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
+
+ GST_DEBUG_OBJECT (dvdspu, "Pushing reference frame at start of still");
+
+ gst_buffer_replace (&dvdspu->pending_frame, buf);
+ gst_buffer_unref (buf);
} else {
- GST_LOG_OBJECT (dvdspu,
- "Redraw due to Still Frame skipped - no SPU to draw");
+ GST_LOG_OBJECT (dvdspu, "Redraw due to Still Frame skipped");
}
} else {
GST_LOG_OBJECT (dvdspu, "Not redrawing still frame - no ref frame");
@@ -664,392 +714,47 @@ gst_dvd_spu_redraw_still (GstDVDSpu * dvdspu)
}
static void
-gst_dvd_spu_parse_chg_colcon (GstDVDSpu * dvdspu, guint8 * data, guint8 * end)
-{
- SpuState *state = &dvdspu->spu_state;
- guint8 *cur;
- gint16 n_entries;
- gint16 i;
-
- /* Clear any existing chg colcon info */
- state->n_line_ctrl_i = 0;
- if (state->line_ctrl_i != NULL) {
- g_free (state->line_ctrl_i);
- state->line_ctrl_i = NULL;
- }
- GST_DEBUG_OBJECT (dvdspu, "Change Color & Contrast. Pixel data = %d bytes",
- (gint16) (end - data));
-
- /* Count the number of entries we'll need */
- n_entries = 0;
- for (cur = data; cur < end;) {
- guint8 n_changes;
- guint32 code;
-
- if (cur + 4 > end)
- break;
-
- code = GST_READ_UINT32_BE (cur);
- if (code == 0x0fffffff)
- break; /* Termination code */
-
- n_changes = CLAMP ((cur[2] >> 4), 1, 8);
- cur += 4 + (6 * n_changes);
-
- if (cur > end)
- break; /* Invalid entry overrunning buffer */
-
- n_entries++;
- }
-
- state->n_line_ctrl_i = n_entries;
- state->line_ctrl_i = g_new (SpuLineCtrlI, n_entries);
-
- cur = data;
- for (i = 0; i < n_entries; i++) {
- SpuLineCtrlI *cur_line_ctrl = state->line_ctrl_i + i;
- guint8 n_changes = CLAMP ((cur[2] >> 4), 1, 8);
- guint8 c;
-
- cur_line_ctrl->n_changes = n_changes;
- cur_line_ctrl->top = ((cur[0] << 8) & 0x300) | cur[1];
- cur_line_ctrl->bottom = ((cur[2] << 8) & 0x300) | cur[3];
-
- GST_LOG_OBJECT (dvdspu, "ChgColcon Entry %d Top: %d Bottom: %d Changes: %d",
- i, cur_line_ctrl->top, cur_line_ctrl->bottom, n_changes);
- cur += 4;
-
- for (c = 0; c < n_changes; c++) {
- SpuPixCtrlI *cur_pix_ctrl = cur_line_ctrl->pix_ctrl_i + c;
-
- cur_pix_ctrl->left = ((cur[0] << 8) & 0x300) | cur[1];
- cur_pix_ctrl->palette = GST_READ_UINT32_BE (cur + 2);
- GST_LOG_OBJECT (dvdspu, " %d: left: %d palette 0x%x", c,
- cur_pix_ctrl->left, cur_pix_ctrl->palette);
- cur += 6;
- }
- }
-}
-
-static void
-gst_dvd_spu_exec_cmd_blk (GstDVDSpu * dvdspu, guint8 * data, guint8 * end)
-{
- SpuState *state = &dvdspu->spu_state;
-
- while (data < end) {
- guint8 cmd;
-
- cmd = data[0];
-
- switch (cmd) {
- case SPU_CMD_FSTA_DSP:
- GST_DEBUG_OBJECT (dvdspu, " Forced Display");
- state->flags |= SPU_STATE_FORCED_DSP;
- data += 1;
- break;
- case SPU_CMD_DSP:
- GST_DEBUG_OBJECT (dvdspu, " Display On");
- state->flags |= SPU_STATE_DISPLAY;
- data += 1;
- break;
- case SPU_CMD_STP_DSP:
- GST_DEBUG_OBJECT (dvdspu, " Display Off");
- state->flags &= ~(SPU_STATE_FORCED_DSP | SPU_STATE_DISPLAY);
- data += 1;
- break;
- case SPU_CMD_SET_COLOR:{
- if (G_UNLIKELY (data + 3 >= end))
- return; /* Invalid SET_COLOR cmd at the end of the blk */
-
- state->main_idx[3] = data[1] >> 4;
- state->main_idx[2] = data[1] & 0x0f;
- state->main_idx[1] = data[2] >> 4;
- state->main_idx[0] = data[2] & 0x0f;
-
- state->main_pal_dirty = TRUE;
-
- GST_DEBUG_OBJECT (dvdspu,
- " Set Color bg %u pattern %u emph-1 %u emph-2 %u",
- state->main_idx[0], state->main_idx[1], state->main_idx[2],
- state->main_idx[3]);
- data += 3;
- break;
- }
- case SPU_CMD_SET_ALPHA:{
- if (G_UNLIKELY (data + 3 >= end))
- return; /* Invalid SET_ALPHA cmd at the end of the blk */
-
- state->main_alpha[3] = data[1] >> 4;
- state->main_alpha[2] = data[1] & 0x0f;
- state->main_alpha[1] = data[2] >> 4;
- state->main_alpha[0] = data[2] & 0x0f;
-
- state->main_pal_dirty = TRUE;
-
- GST_DEBUG_OBJECT (dvdspu,
- " Set Alpha bg %u pattern %u emph-1 %u emph-2 %u",
- state->main_alpha[0], state->main_alpha[1], state->main_alpha[2],
- state->main_alpha[3]);
- data += 3;
- break;
- }
- case SPU_CMD_SET_DAREA:{
- SpuRect *r = &state->disp_rect;
-
- if (G_UNLIKELY (data + 7 >= end))
- return; /* Invalid SET_DAREA cmd at the end of the blk */
-
- r->top = ((data[4] & 0x3f) << 4) | ((data[5] & 0xe0) >> 4);
- r->left = ((data[1] & 0x3f) << 4) | ((data[2] & 0xf0) >> 4);
- r->right = ((data[2] & 0x03) << 8) | data[3];
- r->bottom = ((data[5] & 0x03) << 8) | data[6];
-
- GST_DEBUG_OBJECT (dvdspu,
- " Set Display Area top %u left %u bottom %u right %u", r->top,
- r->left, r->bottom, r->right);
-
- data += 7;
- break;
- }
- case SPU_CMD_DSPXA:{
- if (G_UNLIKELY (data + 5 >= end))
- return; /* Invalid SET_DSPXE cmd at the end of the blk */
-
- state->pix_data[0] = GST_READ_UINT16_BE (data + 1);
- state->pix_data[1] = GST_READ_UINT16_BE (data + 3);
- /* Store a reference to the current command buffer, as that's where
- * we'll need to take our pixel data from */
- gst_buffer_replace (&state->pix_buf, state->buf);
-
- GST_DEBUG_OBJECT (dvdspu, " Set Pixel Data Offsets top: %u bot: %u",
- state->pix_data[0], state->pix_data[1]);
-
- data += 5;
- break;
- }
- case SPU_CMD_CHG_COLCON:{
- guint16 field_size;
-
- GST_DEBUG_OBJECT (dvdspu, " Set Color & Contrast Change");
- if (G_UNLIKELY (data + 3 >= end))
- return; /* Invalid CHG_COLCON cmd at the end of the blk */
-
- data++;
- field_size = GST_READ_UINT16_BE (data);
-
- if (G_UNLIKELY (data + field_size >= end))
- return; /* Invalid CHG_COLCON cmd at the end of the blk */
-
- gst_dvd_spu_parse_chg_colcon (dvdspu, data + 2, data + field_size);
- state->line_ctrl_i_pal_dirty = TRUE;
- data += field_size;
- break;
- }
- case SPU_CMD_END:
- default:
- GST_DEBUG_OBJECT (dvdspu, " END");
- data = end;
- break;
- }
- }
-}
-
-static void
-gst_dvd_spu_finish_spu_buf (GstDVDSpu * dvdspu)
-{
- SpuState *state = &dvdspu->spu_state;
-
- state->next_ts = state->base_ts = GST_CLOCK_TIME_NONE;
- gst_buffer_replace (&state->buf, NULL);
-
- GST_DEBUG_OBJECT (dvdspu, "Finished SPU buffer");
-}
-
-static gboolean
-gst_dvd_spu_setup_cmd_blk (GstDVDSpu * dvdspu, guint16 cmd_blk_offset,
- guint8 * start, guint8 * end)
-{
- SpuState *state = &dvdspu->spu_state;
- guint16 delay;
- guint8 *cmd_blk = start + cmd_blk_offset;
-
- if (G_UNLIKELY (cmd_blk + 5 >= end))
- return FALSE; /* No valid command block to read */
-
- delay = GST_READ_UINT16_BE (cmd_blk);
- state->next_ts = state->base_ts + STM_TO_GST (delay);
- state->cur_cmd_blk = cmd_blk_offset;
-
- GST_DEBUG_OBJECT (dvdspu, "Setup CMD Block @ %u with TS %" GST_TIME_FORMAT,
- state->cur_cmd_blk, GST_TIME_ARGS (state->next_ts));
- return TRUE;
-}
-
-static void
-gst_dvd_spu_handle_new_spu_buf (GstDVDSpu * dvdspu, SpuPacket * packet)
-{
- guint8 *start, *end;
- SpuState *state = &dvdspu->spu_state;
-
- if (G_UNLIKELY (GST_BUFFER_SIZE (packet->buf) < 4))
- goto invalid;
-
- if (state->buf != NULL) {
- gst_buffer_unref (state->buf);
- state->buf = NULL;
- }
- state->buf = packet->buf;
- state->base_ts = packet->event_ts;
-
- start = GST_BUFFER_DATA (state->buf);
- end = start + GST_BUFFER_SIZE (state->buf);
-
- /* Configure the first command block in this buffer as our initial blk */
- state->cur_cmd_blk = GST_READ_UINT16_BE (start + 2);
- gst_dvd_spu_setup_cmd_blk (dvdspu, state->cur_cmd_blk, start, end);
- /* Clear existing chg-colcon info */
- state->n_line_ctrl_i = 0;
- if (state->line_ctrl_i != NULL) {
- g_free (state->line_ctrl_i);
- state->line_ctrl_i = NULL;
- }
- return;
-
-invalid:
- /* Invalid buffer */
- gst_dvd_spu_finish_spu_buf (dvdspu);
-}
-
-static void
gst_dvd_spu_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
{
- const gchar *event_type;
const GstStructure *structure = gst_event_get_structure (event);
- SpuState *state = &dvdspu->spu_state;
+ const gchar *event_type = gst_structure_get_string (structure, "event");
gboolean hl_change = FALSE;
- event_type = gst_structure_get_string (structure, "event");
GST_INFO_OBJECT (dvdspu, "DVD event of type %s on subp pad OOB=%d",
event_type, (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB));
- if (strcmp (event_type, "dvd-spu-clut-change") == 0) {
- gchar prop_name[32];
- gint i;
- gint entry;
-
- for (i = 0; i < 16; i++) {
- g_snprintf (prop_name, 32, "clut%02d", i);
- if (!gst_structure_get_int (structure, prop_name, &entry))
- entry = 0;
- state->current_clut[i] = (guint32) entry;
- }
-
- state->main_pal_dirty = TRUE;
- state->hl_pal_dirty = TRUE;
- state->line_ctrl_i_pal_dirty = TRUE;
- hl_change = TRUE;
- } else if (strcmp (event_type, "dvd-spu-highlight") == 0) {
- gint val;
-
- if (gst_structure_get_int (structure, "palette", &val)) {
- state->hl_idx[3] = ((guint32) (val) >> 28) & 0x0f;
- state->hl_idx[2] = ((guint32) (val) >> 24) & 0x0f;
- state->hl_idx[1] = ((guint32) (val) >> 20) & 0x0f;
- state->hl_idx[0] = ((guint32) (val) >> 16) & 0x0f;
-
- state->hl_alpha[3] = ((guint32) (val) >> 12) & 0x0f;
- state->hl_alpha[2] = ((guint32) (val) >> 8) & 0x0f;
- state->hl_alpha[1] = ((guint32) (val) >> 4) & 0x0f;
- state->hl_alpha[0] = ((guint32) (val) >> 0) & 0x0f;
-
- state->hl_pal_dirty = TRUE;
- }
- if (gst_structure_get_int (structure, "sx", &val))
- state->hl_rect.left = (gint16) val;
- if (gst_structure_get_int (structure, "sy", &val))
- state->hl_rect.top = (gint16) val;
- if (gst_structure_get_int (structure, "ex", &val))
- state->hl_rect.right = (gint16) val;
- if (gst_structure_get_int (structure, "ey", &val))
- state->hl_rect.bottom = (gint16) val;
-
- GST_INFO_OBJECT (dvdspu, "Highlight rect is now (%d,%d) to (%d,%d)",
- state->hl_rect.left, state->hl_rect.top,
- state->hl_rect.right, state->hl_rect.bottom);
- hl_change = TRUE;
- } else if (strcmp (event_type, "dvd-spu-reset-highlight") == 0) {
- if (state->hl_rect.top != -1 || state->hl_rect.bottom != -1)
- hl_change = TRUE;
- state->hl_rect.top = -1;
- state->hl_rect.bottom = -1;
- GST_INFO_OBJECT (dvdspu, "Highlight off");
- } else if (strcmp (event_type, "dvd-set-subpicture-track") == 0) {
- gboolean forced_only;
-
- if (gst_structure_get_boolean (structure, "forced-only", &forced_only)) {
- gboolean was_forced = (state->flags & SPU_STATE_FORCED_ONLY);
-
- if (forced_only)
- state->flags |= SPU_STATE_FORCED_ONLY;
- else
- state->flags &= ~(SPU_STATE_FORCED_ONLY);
-
- if ((was_forced && !forced_only) || (!was_forced && forced_only))
- hl_change = TRUE;
- }
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ hl_change = gstspu_vobsub_handle_dvd_event (dvdspu, event);
+ break;
+ case SPU_INPUT_TYPE_PGS:
+ hl_change = gstspu_pgs_handle_dvd_event (dvdspu, event);
+ break;
+ default:
+ break;
}
- if (hl_change && (state->flags & SPU_STATE_STILL_FRAME)) {
- gst_dvd_spu_redraw_still (dvdspu);
+ if (hl_change && (dvdspu->spu_state.flags & SPU_STATE_STILL_FRAME)) {
+ gst_dvd_spu_redraw_still (dvdspu, FALSE);
}
-
- gst_event_unref (event);
}
-#if DUMP_DCSQ
-static void
-gst_dvd_spu_dump_dcsq (GstDVDSpu * dvdspu,
- GstClockTime start_ts, GstBuffer * spu_buf)
+static gboolean
+gstspu_execute_event (GstDVDSpu * dvdspu)
{
- guint16 cmd_blk_offset;
- guint16 next_blk;
- guint8 *start, *end;
-
- start = GST_BUFFER_DATA (spu_buf);
- end = start + GST_BUFFER_SIZE (spu_buf);
-
- g_return_if_fail (start != NULL);
-
- /* First command */
- next_blk = GST_READ_UINT16_BE (start + 2);
- cmd_blk_offset = 0;
-
- /* Loop through all commands */
- g_print ("SPU begins @ %" GST_TIME_FORMAT " offset %u\n",
- GST_TIME_ARGS (start_ts), next_blk);
-
- while (cmd_blk_offset != next_blk) {
- guint8 *data;
- GstClockTime cmd_blk_ts;
-
- cmd_blk_offset = next_blk;
-
- if (G_UNLIKELY (start + cmd_blk_offset + 5 >= end))
- break; /* No valid command to read */
-
- data = start + cmd_blk_offset;
-
- cmd_blk_ts = start_ts + STM_TO_GST (GST_READ_UINT16_BE (data));
- next_blk = GST_READ_UINT16_BE (data + 2);
-
- g_print ("Cmd Blk @ offset %u next %u ts %" GST_TIME_FORMAT "\n",
- cmd_blk_offset, next_blk, GST_TIME_ARGS (cmd_blk_ts));
-
- data += 4;
- gst_dvd_spu_exec_cmd_blk (dvdspu, data, end);
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ return gstspu_vobsub_execute_event (dvdspu);
+ break;
+ case SPU_INPUT_TYPE_PGS:
+ return gstspu_pgs_execute_event (dvdspu);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
+ return FALSE;
}
-#endif
/* Advance the SPU packet/command queue to a time. new_ts is in running time */
static void
@@ -1057,11 +762,15 @@ gst_dvd_spu_advance_spu (GstDVDSpu * dvdspu, GstClockTime new_ts)
{
SpuState *state = &dvdspu->spu_state;
+ if (G_UNLIKELY (dvdspu->spu_input_type == SPU_INPUT_TYPE_NONE))
+ return;
+
while (state->next_ts == GST_CLOCK_TIME_NONE || state->next_ts <= new_ts) {
- guint8 *start, *cmd_blk, *end;
- guint16 next_blk;
+ GST_DEBUG_OBJECT (dvdspu,
+ "Advancing SPU from TS %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (state->next_ts), GST_TIME_ARGS (new_ts));
- if (state->buf == NULL) {
+ if (!gstspu_execute_event (dvdspu)) {
GstClockTime vid_run_ts;
/* No current command buffer, try and get one */
@@ -1082,51 +791,25 @@ gst_dvd_spu_advance_spu (GstDVDSpu * dvdspu, GstClockTime new_ts)
packet->buf ? "buffer" : "event");
if (packet->buf) {
-#if DUMP_DCSQ
- gst_dvd_spu_dump_dcsq (dvdspu, packet->event_ts, packet->buf);
-#endif
- gst_dvd_spu_handle_new_spu_buf (dvdspu, packet);
- }
- if (packet->event)
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ gstspu_vobsub_handle_new_buf (dvdspu, packet->event_ts,
+ packet->buf);
+ break;
+ case SPU_INPUT_TYPE_PGS:
+ gstspu_pgs_handle_new_buf (dvdspu, packet->event_ts, packet->buf);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ g_assert (packet->event == NULL);
+ } else if (packet->event)
gst_dvd_spu_handle_dvd_event (dvdspu, packet->event);
g_free (packet);
continue;
}
-
- GST_DEBUG_OBJECT (dvdspu,
- "Advancing SPU from TS %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (state->next_ts), GST_TIME_ARGS (new_ts));
-
- /* If we get here, we have an SPU buffer, and it's time to process the
- * next cmd */
- g_assert (state->buf != NULL);
-
- GST_DEBUG_OBJECT (dvdspu, "Executing cmd blk with TS %" GST_TIME_FORMAT
- " @ offset %u", GST_TIME_ARGS (state->next_ts), state->cur_cmd_blk);
-
- start = GST_BUFFER_DATA (state->buf);
- end = start + GST_BUFFER_SIZE (state->buf);
-
- cmd_blk = start + state->cur_cmd_blk;
-
- if (G_UNLIKELY (cmd_blk + 5 >= end)) {
- /* Invalid. Finish the buffer and loop again */
- gst_dvd_spu_finish_spu_buf (dvdspu);
- continue;
- }
-
- gst_dvd_spu_exec_cmd_blk (dvdspu, cmd_blk + 4, end);
-
- next_blk = GST_READ_UINT16_BE (cmd_blk + 2);
- if (next_blk != state->cur_cmd_blk) {
- /* Advance to the next block of commands */
- gst_dvd_spu_setup_cmd_blk (dvdspu, next_blk, start, end);
- } else {
- /* Next Block points to the current block, so we're finished with this
- * SPU buffer */
- gst_dvd_spu_finish_spu_buf (dvdspu);
- }
}
}
@@ -1152,10 +835,66 @@ gst_dvd_spu_check_still_updates (GstDVDSpu * dvdspu)
}
}
+static void
+submit_new_spu_packet (GstDVDSpu * dvdspu, GstBuffer * buf)
+{
+ SpuPacket *spu_packet;
+ GstClockTime ts;
+ GstClockTime run_ts = GST_CLOCK_TIME_NONE;
+
+ GST_DEBUG_OBJECT (dvdspu,
+ "Complete subpicture buffer of %u bytes with TS %" GST_TIME_FORMAT,
+ GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ /* Decide whether to pass this buffer through to the rendering code */
+ ts = GST_BUFFER_TIMESTAMP (buf);
+ if (GST_CLOCK_TIME_IS_VALID (ts)) {
+ if (ts < (GstClockTime) dvdspu->subp_seg.start) {
+ GstClockTimeDiff diff = dvdspu->subp_seg.start - ts;
+
+ /* Buffer starts before segment, see if we can calculate a running time */
+ run_ts =
+ gst_segment_to_running_time (&dvdspu->subp_seg, GST_FORMAT_TIME,
+ dvdspu->subp_seg.start);
+ if (run_ts >= (GstClockTime) diff)
+ run_ts -= diff;
+ else
+ run_ts = GST_CLOCK_TIME_NONE; /* No running time possible for this subpic */
+ } else {
+ /* TS within segment, convert to running time */
+ run_ts =
+ gst_segment_to_running_time (&dvdspu->subp_seg, GST_FORMAT_TIME, ts);
+ }
+ }
+
+ if (GST_CLOCK_TIME_IS_VALID (run_ts)) {
+ /* Complete SPU packet, push it onto the queue for processing when
+ * video packets come past */
+ spu_packet = g_new0 (SpuPacket, 1);
+ spu_packet->buf = buf;
+
+ /* Store the activation time of this buffer in running time */
+ spu_packet->event_ts = run_ts;
+ GST_INFO_OBJECT (dvdspu,
+ "Pushing SPU buf with TS %" GST_TIME_FORMAT " running time %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (ts),
+ GST_TIME_ARGS (spu_packet->event_ts));
+
+ g_queue_push_tail (dvdspu->pending_spus, spu_packet);
+
+ /* In a still frame condition, advance the SPU to make sure the state is
+ * up to date */
+ gst_dvd_spu_check_still_updates (dvdspu);
+ } else {
+ gst_buffer_unref (buf);
+ }
+}
+
static GstFlowReturn
gst_dvd_spu_subpic_chain (GstPad * pad, GstBuffer * buf)
{
GstDVDSpu *dvdspu = (GstDVDSpu *) (gst_object_get_parent (GST_OBJECT (pad)));
+ GstFlowReturn ret = GST_FLOW_OK;
g_return_val_if_fail (dvdspu != NULL, GST_FLOW_ERROR);
@@ -1170,7 +909,15 @@ gst_dvd_spu_subpic_chain (GstPad * pad, GstBuffer * buf)
GST_BUFFER_TIMESTAMP (buf));
}
+ if (GST_BUFFER_IS_DISCONT (buf) && dvdspu->partial_spu) {
+ gst_buffer_unref (dvdspu->partial_spu);
+ dvdspu->partial_spu = NULL;
+ }
+
if (dvdspu->partial_spu != NULL) {
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
+ GST_WARNING_OBJECT (dvdspu,
+ "Joining subpicture buffer with timestamp to previous");
dvdspu->partial_spu = gst_buffer_join (dvdspu->partial_spu, buf);
} else {
/* If we don't yet have a buffer, wait for one with a timestamp,
@@ -1181,85 +928,88 @@ gst_dvd_spu_subpic_chain (GstPad * pad, GstBuffer * buf)
gst_buffer_unref (buf);
}
- if (dvdspu->partial_spu != NULL && GST_BUFFER_SIZE (dvdspu->partial_spu) > 4) {
- guint16 packet_size;
- guint8 *data;
-
- data = GST_BUFFER_DATA (dvdspu->partial_spu);
- packet_size = GST_READ_UINT16_BE (data);
-
- if (packet_size == GST_BUFFER_SIZE (dvdspu->partial_spu)) {
- SpuPacket *spu_packet;
- GstClockTime ts;
- GstClockTime run_ts = GST_CLOCK_TIME_NONE;
-
- GST_DEBUG_OBJECT (dvdspu,
- "Complete subpicture buffer of %u bytes with TS %" GST_TIME_FORMAT,
- GST_BUFFER_SIZE (dvdspu->partial_spu),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (dvdspu->partial_spu)));
-
- /* Decide whether to pass this buffer through to the rendering code */
- ts = GST_BUFFER_TIMESTAMP (dvdspu->partial_spu);
- if (GST_CLOCK_TIME_IS_VALID (ts)) {
- if (ts < (GstClockTime) dvdspu->subp_seg.start) {
- GstClockTimeDiff diff = dvdspu->subp_seg.start - ts;
-
- /* Buffer starts before segment, see if we can calculate a running time */
- run_ts =
- gst_segment_to_running_time (&dvdspu->subp_seg, GST_FORMAT_TIME,
- dvdspu->subp_seg.start);
- if (run_ts >= (GstClockTime) diff)
- run_ts -= diff;
- else
- run_ts = GST_CLOCK_TIME_NONE; /* No running time possible for this subpic */
+ if (dvdspu->partial_spu == NULL)
+ goto done;
+
+ switch (dvdspu->spu_input_type) {
+ case SPU_INPUT_TYPE_VOBSUB:
+ if (GST_BUFFER_SIZE (dvdspu->partial_spu) > 4) {
+ guint16 packet_size;
+ guint8 *data;
+
+ data = GST_BUFFER_DATA (dvdspu->partial_spu);
+ packet_size = GST_READ_UINT16_BE (data);
+
+ if (packet_size == GST_BUFFER_SIZE (dvdspu->partial_spu)) {
+ submit_new_spu_packet (dvdspu, dvdspu->partial_spu);
+ dvdspu->partial_spu = NULL;
+ } else if (packet_size < GST_BUFFER_SIZE (dvdspu->partial_spu)) {
+ /* Somehow we collected too much - something is wrong. Drop the
+ * packet entirely and wait for a new one */
+ GST_DEBUG_OBJECT (dvdspu, "Discarding invalid SPU buffer of size %u",
+ GST_BUFFER_SIZE (dvdspu->partial_spu));
+
+ gst_buffer_unref (dvdspu->partial_spu);
+ dvdspu->partial_spu = NULL;
} else {
- /* TS within segment, convert to running time */
- run_ts =
- gst_segment_to_running_time (&dvdspu->subp_seg, GST_FORMAT_TIME,
- ts);
+ GST_LOG_OBJECT (dvdspu,
+ "SPU buffer claims to be of size %u. Collected %u so far.",
+ packet_size, GST_BUFFER_SIZE (dvdspu->partial_spu));
+ }
+ }
+ break;
+ case SPU_INPUT_TYPE_PGS:{
+ /* Collect until we have a command buffer that ends exactly at the size
+ * we've collected */
+ guint8 packet_type;
+ guint16 packet_size;
+ guint8 *data = GST_BUFFER_DATA (dvdspu->partial_spu);
+ guint8 *end = data + GST_BUFFER_SIZE (dvdspu->partial_spu);
+
+ /* FIXME: There's no need to walk the command set each time. We can set a
+ * marker and resume where we left off next time */
+ /* FIXME: Move the packet parsing and sanity checking into the format-specific modules */
+ while (data != end) {
+ if (data + 3 > end)
+ break;
+ packet_type = *data++;
+ packet_size = GST_READ_UINT16_BE (data);
+ data += 2;
+ if (data + packet_size > end)
+ break;
+ data += packet_size;
+ /* 0x80 is the END command for PGS packets */
+ if (packet_type == 0x80 && data != end) {
+ /* Extra cruft on the end of the packet -> assume invalid */
+ gst_buffer_unref (dvdspu->partial_spu);
+ dvdspu->partial_spu = NULL;
+ break;
}
}
- if (GST_CLOCK_TIME_IS_VALID (run_ts)) {
- /* Complete SPU packet, push it onto the queue for processing when
- * video packets come past */
- spu_packet = g_new0 (SpuPacket, 1);
- spu_packet->buf = dvdspu->partial_spu;
-
- /* Store the activation time of this buffer in running time */
- spu_packet->event_ts =
- gst_segment_to_running_time (&dvdspu->subp_seg, GST_FORMAT_TIME,
- ts);
- GST_INFO_OBJECT (dvdspu,
- "Pushing SPU buf with TS %" GST_TIME_FORMAT " running time %"
- GST_TIME_FORMAT, GST_TIME_ARGS (ts),
- GST_TIME_ARGS (spu_packet->event_ts));
-
- g_queue_push_tail (dvdspu->pending_spus, spu_packet);
- dvdspu->partial_spu = NULL;
-
- /* In a still frame condition, advance the SPU to make sure the state is
- * up to date */
- gst_dvd_spu_check_still_updates (dvdspu);
- } else {
- gst_buffer_unref (dvdspu->partial_spu);
+ if (dvdspu->partial_spu && data == end) {
+ GST_DEBUG_OBJECT (dvdspu,
+ "Have complete PGS packet of size %u. Enqueueing.",
+ GST_BUFFER_SIZE (dvdspu->partial_spu));
+ submit_new_spu_packet (dvdspu, dvdspu->partial_spu);
dvdspu->partial_spu = NULL;
}
- } else if (packet_size < GST_BUFFER_SIZE (dvdspu->partial_spu)) {
- /* Somehow we collected too much - something is wrong. Drop the
- * packet entirely and wait for a new one */
- GST_DEBUG_OBJECT (dvdspu, "Discarding invalid SPU buffer of size %u",
- GST_BUFFER_SIZE (dvdspu->partial_spu));
-
- gst_buffer_unref (dvdspu->partial_spu);
- dvdspu->partial_spu = NULL;
+ break;
}
+ default:
+ GST_ERROR_OBJECT (dvdspu, "Input type not configured before SPU passing");
+ goto caps_not_set;
}
+done:
DVD_SPU_UNLOCK (dvdspu);
-
gst_object_unref (dvdspu);
- return GST_FLOW_OK;
+ return ret;
+caps_not_set:
+ GST_ELEMENT_ERROR (dvdspu, RESOURCE, NO_SPACE_LEFT,
+ (_("Subpicture format was not configured before data flow")), (NULL));
+ ret = GST_FLOW_ERROR;
+ goto done;
}
static gboolean
@@ -1287,7 +1037,8 @@ gst_dvd_spu_subpic_event (GstPad * pad, GstEvent * event)
DVD_SPU_LOCK (dvdspu);
if (GST_EVENT_IS_SERIALIZED (event)) {
SpuPacket *spu_packet = g_new0 (SpuPacket, 1);
-
+ GST_DEBUG_OBJECT (dvdspu,
+ "Enqueueing DVD event on subpicture pad for later");
spu_packet->event = event;
g_queue_push_tail (dvdspu->pending_spus, spu_packet);
} else {
@@ -1348,8 +1099,11 @@ gst_dvd_spu_subpic_event (GstPad * pad, GstEvent * event)
GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
DVD_SPU_LOCK (dvdspu);
+
gst_segment_set_newsegment_full (&dvdspu->subp_seg, update, rate, arate,
format, start, stop, time);
+ GST_LOG_OBJECT (dvdspu, "Subpicture segment now: %" GST_SEGMENT_FORMAT,
+ &dvdspu->subp_seg);
DVD_SPU_UNLOCK (dvdspu);
gst_event_unref (event);
@@ -1359,8 +1113,10 @@ gst_dvd_spu_subpic_event (GstPad * pad, GstEvent * event)
gst_event_unref (event);
goto done;
case GST_EVENT_FLUSH_STOP:
+ GST_DEBUG_OBJECT (dvdspu, "Have flush-stop event on SPU pad");
DVD_SPU_LOCK (dvdspu);
- gst_dvd_spu_flush_spu_info (dvdspu);
+ gst_segment_init (&dvdspu->subp_seg, GST_FORMAT_UNDEFINED);
+ gst_dvd_spu_flush_spu_info (dvdspu, TRUE);
DVD_SPU_UNLOCK (dvdspu);
/* We don't forward flushes on the spu pad */
@@ -1383,6 +1139,39 @@ done:
return res;
}
+static gboolean
+gst_dvd_spu_subpic_set_caps (GstPad * pad, GstCaps * caps)
+{
+ GstDVDSpu *dvdspu = GST_DVD_SPU (gst_pad_get_parent (pad));
+ gboolean res = FALSE;
+ GstStructure *s;
+ SpuInputType input_type;
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (gst_structure_has_name (s, "video/x-dvd-subpicture")) {
+ input_type = SPU_INPUT_TYPE_VOBSUB;
+ } else if (gst_structure_has_name (s, "subpicture/x-pgs")) {
+ input_type = SPU_INPUT_TYPE_PGS;
+ } else {
+ goto done;
+ }
+
+ DVD_SPU_LOCK (dvdspu);
+ if (dvdspu->spu_input_type != input_type) {
+ GST_INFO_OBJECT (dvdspu, "Incoming SPU packet type changed to %u",
+ input_type);
+ dvdspu->spu_input_type = input_type;
+ gst_dvd_spu_flush_spu_info (dvdspu, TRUE);
+ }
+
+ DVD_SPU_UNLOCK (dvdspu);
+ res = TRUE;
+done:
+ gst_object_unref (dvdspu);
+ return res;
+}
+
static GstStateChangeReturn
gst_dvd_spu_change_state (GstElement * element, GstStateChange transition)
{
@@ -1407,8 +1196,8 @@ gst_dvd_spu_change_state (GstElement * element, GstStateChange transition)
gboolean
gst_dvd_spu_plugin_init (GstPlugin * plugin)
{
- GST_DEBUG_CATEGORY_INIT (dvdspu_debug, "gstdvdspu",
- 0, "DVD Sub-picture Overlay decoder/renderer");
+ GST_DEBUG_CATEGORY_INIT (dvdspu_debug, "gstspu",
+ 0, "Sub-picture Overlay decoder/renderer");
return gst_element_register (plugin, "dvdspu",
GST_RANK_NONE, GST_TYPE_DVD_SPU);
diff --git a/gst/dvdspu/gstdvdspu.h b/gst/dvdspu/gstdvdspu.h
index dfc51f9e..22b48d1d 100644
--- a/gst/dvdspu/gstdvdspu.h
+++ b/gst/dvdspu/gstdvdspu.h
@@ -16,11 +16,15 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
-#ifndef __DVD_SPU_H__
-#define __DVD_SPU_H__
+#ifndef __GST_DVD_SPU_H__
+#define __GST_DVD_SPU_H__
#include <gst/gst.h>
+#include "gstspu-common.h"
+#include "gstspu-vobsub.h"
+#include "gstspu-pgs.h"
+
G_BEGIN_DECLS
#define GST_TYPE_DVD_SPU \
@@ -37,63 +41,16 @@ G_BEGIN_DECLS
#define DVD_SPU_LOCK(s) g_mutex_lock ((s)->spu_lock);
#define DVD_SPU_UNLOCK(s) g_mutex_unlock ((s)->spu_lock);
-typedef struct _GstDVDSpu GstDVDSpu;
typedef struct _GstDVDSpuClass GstDVDSpuClass;
-typedef struct SpuRect SpuRect;
-typedef struct SpuPixCtrlI SpuPixCtrlI;
-typedef struct SpuLineCtrlI SpuLineCtrlI;
-typedef struct SpuColour SpuColour;
typedef enum SpuStateFlags SpuStateFlags;
-typedef struct SpuState SpuState;
+typedef enum SpuInputType SpuInputType;
typedef struct SpuPacket SpuPacket;
-typedef enum SpuCmd SpuCmd;
-
-/* Describe the limits of a rectangle */
-struct SpuRect {
- gint16 left;
- gint16 top;
- gint16 right;
- gint16 bottom;
-};
-
-/* Store a pre-multiplied colour value. The YUV fields hold the YUV values
- * multiplied by the 8-bit alpha, to save computing it while rendering */
-struct SpuColour {
- guint16 Y;
- guint16 U;
- guint16 V;
- guint8 A;
-};
-
-/* Pixel Control Info from a Change Color Contrast command */
-struct SpuPixCtrlI {
- gint16 left;
- guint32 palette;
-
- /* Pre-multiplied palette values, updated as
- * needed */
- SpuColour pal_cache[4];
-};
-
-struct SpuLineCtrlI {
- guint8 n_changes; /* 1 to 8 */
- SpuPixCtrlI pix_ctrl_i[8];
-
- gint16 top;
- gint16 bottom;
-};
-enum SpuCmd {
- SPU_CMD_FSTA_DSP = 0x00, /* Forced Display */
- SPU_CMD_DSP = 0x01, /* Display Start */
- SPU_CMD_STP_DSP = 0x02, /* Display Off */
- SPU_CMD_SET_COLOR = 0x03, /* Set the color indexes for the palette */
- SPU_CMD_SET_ALPHA = 0x04, /* Set the alpha indexes for the palette */
- SPU_CMD_SET_DAREA = 0x05, /* Set the display area for the SPU */
- SPU_CMD_DSPXA = 0x06, /* Pixel data addresses */
- SPU_CMD_CHG_COLCON = 0x07, /* Change Color & Contrast */
- SPU_CMD_END = 0xff
+enum SpuInputType {
+ SPU_INPUT_TYPE_NONE = 0x00,
+ SPU_INPUT_TYPE_VOBSUB = 0x01,
+ SPU_INPUT_TYPE_PGS = 0x02
};
enum SpuStateFlags {
@@ -110,69 +67,19 @@ enum SpuStateFlags {
struct SpuState {
GstClockTime next_ts; /* Next event TS in running time */
-
- GstClockTime base_ts; /* base TS for cmd blk delays in running time */
- GstBuffer *buf; /* Current SPU packet we're executing commands from */
- guint16 cur_cmd_blk; /* Offset into the buf for the current cmd block */
-
SpuStateFlags flags;
-
- /* Top + Bottom field offsets in the buffer. 0 = not set */
- guint16 pix_data[2];
- GstBuffer *pix_buf; /* Current SPU packet the pix_data references */
-
- SpuRect disp_rect;
- SpuRect clip_rect;
- SpuRect hl_rect;
-
- guint32 current_clut[16]; /* Colour lookup table from incoming events */
-
- guint8 main_idx[4]; /* Indices for current main palette */
- guint8 main_alpha[4]; /* Alpha values for main palette */
-
- guint8 hl_idx[4]; /* Indices for current highlight palette */
- guint8 hl_alpha[4]; /* Alpha values for highlight palette */
-
- /* Pre-multiplied colour palette for the main palette */
- SpuColour main_pal[4];
- gboolean main_pal_dirty;
-
- /* Line control info for rendering the highlight palette */
- SpuLineCtrlI hl_ctrl_i;
- gboolean hl_pal_dirty; /* Indicates that the HL palette info needs refreshing */
-
- /* LineCtrlI Info from a Change Color & Contrast command */
- SpuLineCtrlI *line_ctrl_i;
- gint16 n_line_ctrl_i;
- gboolean line_ctrl_i_pal_dirty; /* Indicates that the palettes for the line_ctrl_i
- * need recalculating */
-
- /* Rendering state vars below */
- guint16 *comp_bufs[3]; /* Compositing buffers for U+V & A */
- gint16 comp_last_x[2]; /* Maximum X values we rendered into the comp buffer (odd & even) */
- gint16 *comp_last_x_ptr; /* Ptr to the current comp_last_x value to be updated by the render */
+
+ gint fps_n, fps_d;
gint16 vid_width, vid_height;
gint16 Y_stride, UV_stride;
gint16 Y_height, UV_height;
- gint fps_n, fps_d;
-
- /* Current Y Position */
- gint16 cur_Y;
-
- /* Current offset in nibbles into the pix_data */
- guint16 cur_offsets[2];
- guint16 max_offset;
-
- /* current ChgColCon Line Info */
- SpuLineCtrlI *cur_chg_col;
- SpuLineCtrlI *cur_chg_col_end;
+ guint32 *comp_bufs[3]; /* Compositing buffers for U+V & A */
+ guint16 comp_left;
+ guint16 comp_right;
- /* Output position tracking */
- guint8 *out_Y;
- guint16 *out_U;
- guint16 *out_V;
- guint16 *out_A;
+ SpuVobsubState vobsub;
+ SpuPgsState pgs;
};
/* Structure used to store the queue of pending SPU packets. The start_ts is
@@ -198,6 +105,7 @@ struct _GstDVDSpu {
GstSegment subp_seg;
SpuState spu_state;
+ SpuInputType spu_input_type;
/* GQueue of SpuBuf structures */
GQueue *pending_spus;
@@ -221,4 +129,4 @@ GType gst_dvd_spu_get_type (void);
G_END_DECLS
-#endif /* __DVD_SPU_H__ */
+#endif /* __GST_DVD_SPU_H__ */
diff --git a/gst/dvdspu/gstspu-common.h b/gst/dvdspu/gstspu-common.h
new file mode 100644
index 00000000..206e8820
--- /dev/null
+++ b/gst/dvdspu/gstspu-common.h
@@ -0,0 +1,56 @@
+/* GStreamer DVD Sub-Picture Unit
+ * Copyright (C) 2007 Fluendo S.A. <info@fluendo.com>
+ *
+ * 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 __GSTSPU_COMMON_H__
+#define __GSTSPU_COMMON_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* FIXME: Move this back to gstdvdspu.h when the renderers no longer use it: */
+typedef struct _GstDVDSpu GstDVDSpu;
+
+typedef struct SpuState SpuState;
+typedef struct SpuColour SpuColour;
+typedef struct SpuRect SpuRect;
+
+/* Describe the limits of a rectangle */
+struct SpuRect {
+ gint16 left;
+ gint16 top;
+ gint16 right;
+ gint16 bottom;
+};
+
+/* Store a pre-multiplied colour value. The YUV fields hold the YUV values
+ * multiplied by the 8-bit alpha, to save computing it while rendering */
+struct SpuColour {
+ guint16 Y;
+ guint16 U;
+ guint16 V;
+ guint8 A;
+};
+
+void gstspu_clear_comp_buffers (SpuState * state);
+void gstspu_blend_comp_buffers (SpuState * state, guint8 * planes[3]);
+
+
+G_END_DECLS
+
+#endif /* __GSTSPU_COMMON_H__ */
diff --git a/gst/dvdspu/gstspu-pgs.c b/gst/dvdspu/gstspu-pgs.c
new file mode 100644
index 00000000..d1d4de18
--- /dev/null
+++ b/gst/dvdspu/gstspu-pgs.c
@@ -0,0 +1,762 @@
+/* GStreamer Sub-Picture Unit - PGS handling
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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 <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstdvdspu.h"
+#include "gstspu-pgs.h"
+
+const struct PgsFrameRateEntry
+{
+ guint8 id;
+ guint fps_n;
+ guint fps_d;
+} PgsFrameRates[] = {
+ {
+ 64, 30000, 1001} /* 29.97 FPS */
+};
+
+typedef enum PgsCommandType PgsCommandType;
+
+enum PgsCommandType
+{
+ PGS_COMMAND_SET_PALETTE = 0x14,
+ PGS_COMMAND_SET_OBJECT_DATA = 0x15,
+ PGS_COMMAND_PRESENTATION_SEGMENT = 0x16,
+ PGS_COMMAND_SET_WINDOW = 0x17,
+ PGS_COMMAND_INTERACTIVE_SEGMENT = 0x18,
+
+ PGS_COMMAND_END_DISPLAY = 0x80,
+
+ PGS_COMMAND_INVALID = 0xFFFF
+};
+
+static gint gstspu_exec_pgs_buffer (GstDVDSpu * dvdspu, GstBuffer * buf);
+
+#define DUMP_CMDS 0
+#define DUMP_FULL_IMAGE 0
+#define DUMP_FULL_PALETTE 0
+
+#if DUMP_CMDS
+#define PGS_DUMP(...) g_print(__VA_ARGS__)
+#else
+#define PGS_DUMP(...)
+#endif
+
+static void
+dump_bytes (guint8 * data, guint16 len)
+{
+ gint i;
+
+ /* Dump the numbers */
+ for (i = 0; i < len; i++) {
+ PGS_DUMP ("0x%02x ", data[i]);
+ if (!((i + 1) % 16))
+ PGS_DUMP ("\n");
+ }
+ if (len > 0 && (i % 16))
+ PGS_DUMP ("\n");
+}
+
+static void
+dump_rle_data (GstDVDSpu * dvdspu, guint8 * data, guint32 len)
+{
+ guint8 *end = data + len;
+ guint16 obj_w, obj_h;
+ guint x = 0;
+
+ if (data + 4 > end)
+ return;
+
+ /* RLE data: */
+ obj_w = GST_READ_UINT16_BE (data);
+ obj_h = GST_READ_UINT16_BE (data + 2);
+ data += 4;
+ PGS_DUMP ("RLE image is %ux%u\n", obj_w, obj_h);
+
+ while (data < end) {
+ guint8 pal_id;
+ guint16 run_len;
+
+ pal_id = *data++;
+ if (pal_id != 0) {
+ // PGS_DUMP ("data 0x%02x\n", data[0]);
+ run_len = 1;
+ } else {
+ if (data + 1 > end)
+ return;
+ switch (data[0] & 0xC0) {
+ case 0x00:
+ //PGS_DUMP ("data 0x%02x\n", data[0]);
+ run_len = (data[0] & 0x3f);
+ data++;
+ break;
+ case 0x40:
+ if (data + 2 > end)
+ return;
+ //PGS_DUMP ("data 0x%02x 0x%02x\n", data[0], data[1]);
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ data += 2;
+ break;
+ case 0x80:
+ if (data + 2 > end)
+ return;
+ //PGS_DUMP ("data 0x%02x 0x%02x\n", data[0], data[1]);
+ run_len = (data[0] & 0x3f);
+ pal_id = data[1];
+ data += 2;
+ break;
+ case 0xC0:
+ if (data + 3 > end)
+ return;
+ //PGS_DUMP ("data 0x%02x 0x%02x 0x%02x\n", data[0], data[1], data[2]);
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ pal_id = data[2];
+ data += 3;
+ break;
+ }
+ }
+
+#if DUMP_FULL_IMAGE
+ {
+ gint i;
+#if 1
+ if (dvdspu->spu_state.pgs.palette[pal_id].A) {
+ guint8 val = dvdspu->spu_state.pgs.palette[pal_id].A;
+ for (i = 0; i < run_len; i++)
+ PGS_DUMP ("%02x ", val);
+ } else {
+ for (i = 0; i < run_len; i++)
+ PGS_DUMP (" ");
+ }
+ if (!run_len || (x + run_len) > obj_w)
+ PGS_DUMP ("\n");
+#else
+ PGS_DUMP ("Run x: %d pix: %d col: %d\n", x, run_len, pal_id);
+#endif
+ }
+#endif
+
+ x += run_len;
+ if (!run_len || x > obj_w)
+ x = 0;
+ };
+
+ PGS_DUMP ("\n");
+}
+
+static void
+pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
+ GstBuffer * dest_buf)
+{
+ SpuColour *colour;
+ guint8 *planes[3]; /* YUV frame pointers */
+ guint8 *data, *end;
+ guint16 obj_w, obj_h;
+ guint x, y, i, max_x;
+
+ if (G_UNLIKELY (obj->rle_data == NULL || obj->rle_data_size == 0
+ || obj->rle_data_used != obj->rle_data_size))
+ return;
+
+ data = obj->rle_data;
+ end = data + obj->rle_data_used;
+
+ if (data + 4 > end)
+ return;
+
+ /* FIXME: Calculate and use the cropping window for the output, as the
+ * intersection of the crop rectangle for this object (if any) and the
+ * window specified by the object's window_id */
+
+ /* Store the start of each plane */
+ planes[0] = GST_BUFFER_DATA (dest_buf);
+ planes[1] = planes[0] + (state->Y_height * state->Y_stride);
+ planes[2] = planes[1] + (state->UV_height * state->UV_stride);
+
+ /* Sanity check */
+ g_return_if_fail (planes[2] + (state->UV_height * state->UV_stride) <=
+ GST_BUFFER_DATA (dest_buf) + GST_BUFFER_SIZE (dest_buf));
+
+ x = obj->x;
+ y = obj->y;
+
+ planes[0] += state->Y_stride * y;
+ planes[1] += state->UV_stride * (y / 2);
+ planes[2] += state->UV_stride * (y / 2);
+
+ /* RLE data: */
+ obj_w = GST_READ_UINT16_BE (data);
+ obj_h = GST_READ_UINT16_BE (data + 2);
+ data += 4;
+
+ max_x = x + obj_w;
+
+ state->comp_left = x;
+ state->comp_right = max_x;
+
+ gstspu_clear_comp_buffers (state);
+
+ while (data < end) {
+ guint8 pal_id;
+ guint16 run_len;
+
+ pal_id = *data++;
+ if (pal_id != 0) {
+ run_len = 1;
+ } else {
+ if (data + 1 > end)
+ return;
+ switch (data[0] & 0xC0) {
+ case 0x00:
+ run_len = (data[0] & 0x3f);
+ data++;
+ break;
+ case 0x40:
+ if (data + 2 > end)
+ return;
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ data += 2;
+ break;
+ case 0x80:
+ if (data + 2 > end)
+ return;
+ run_len = (data[0] & 0x3f);
+ pal_id = data[1];
+ data += 2;
+ break;
+ case 0xC0:
+ if (data + 3 > end)
+ return;
+ run_len = ((data[0] << 8) | data[1]) & 0x3fff;
+ pal_id = data[2];
+ data += 3;
+ break;
+ }
+ }
+
+ colour = &state->pgs.palette[pal_id];
+ if (colour->A) {
+ guint32 inv_A = 0xff - colour->A;
+
+ for (i = 0; i < run_len; i++) {
+ planes[0][x] = (inv_A * planes[0][x] + colour->Y) / 0xff;
+
+ state->comp_bufs[0][x / 2] += colour->U;
+ state->comp_bufs[1][x / 2] += colour->V;
+ state->comp_bufs[2][x / 2] += colour->A;
+ x++;
+ }
+ } else {
+ x += run_len;
+ }
+
+ if (!run_len || x > max_x) {
+ x = state->pgs.win_x;
+ planes[0] += state->Y_stride;
+
+ if (y % 2) {
+ gstspu_blend_comp_buffers (state, planes);
+ gstspu_clear_comp_buffers (state);
+
+ planes[1] += state->UV_stride;
+ planes[2] += state->UV_stride;
+ }
+ y++;
+ }
+ }
+
+ if (y % 2)
+ gstspu_blend_comp_buffers (state, planes);
+}
+
+static void
+pgs_composition_object_clear (PgsCompositionObject * obj)
+{
+ if (obj->rle_data) {
+ g_free (obj->rle_data);
+ obj->rle_data = NULL;
+ }
+ obj->rle_data_size = obj->rle_data_used = 0;
+}
+
+static void
+pgs_presentation_segment_set_object_count (PgsPresentationSegment * ps,
+ guint8 n_objects)
+{
+ if (ps->objects == NULL) {
+ ps->objects =
+ g_array_sized_new (FALSE, TRUE, sizeof (PgsCompositionObject),
+ n_objects);
+ g_array_set_size (ps->objects, n_objects);
+ return;
+ }
+
+ /* Clear memory in any extraneous objects */
+ if (ps->objects->len > n_objects) {
+ guint i;
+ for (i = n_objects; i < ps->objects->len; i++) {
+ PgsCompositionObject *cur =
+ &g_array_index (ps->objects, PgsCompositionObject, i);
+ pgs_composition_object_clear (cur);
+ }
+ }
+
+ g_array_set_size (ps->objects, n_objects);
+
+ if (n_objects == 0) {
+ g_array_free (ps->objects, TRUE);
+ ps->objects = NULL;
+ }
+}
+
+static PgsCompositionObject *
+pgs_presentation_segment_find_object (PgsPresentationSegment * ps,
+ guint16 obj_id)
+{
+ guint i;
+ if (ps->objects == NULL)
+ return NULL;
+
+ for (i = 0; i < ps->objects->len; i++) {
+ PgsCompositionObject *cur =
+ &g_array_index (ps->objects, PgsCompositionObject, i);
+ if (cur->id == obj_id)
+ return cur;
+ }
+
+ return NULL;
+}
+
+static int
+parse_presentation_segment (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
+ guint16 len)
+{
+ guint8 *end = payload + len;
+ PgsPresentationSegment *ps = &dvdspu->spu_state.pgs.pres_seg;
+ guint8 n_objects, palette_id;
+ gint i;
+
+ /* Parse video descriptor */
+ if (payload + 5 > end)
+ return 0;
+
+ ps->vid_w = GST_READ_UINT16_BE (payload);
+ ps->vid_h = GST_READ_UINT16_BE (payload + 2);
+ ps->vid_fps_code = payload[4];
+ payload += 5;
+
+ /* Parse composition descriptor */
+ if (payload + 3 > end)
+ return 0;
+ ps->composition_no = GST_READ_UINT16_BE (payload);
+ ps->composition_state = payload[2];
+ payload += 3;
+
+ /* Parse other bits */
+ if (payload + 3 > end)
+ return 0;
+
+ ps->flags = payload[0];
+
+ palette_id = payload[1];
+ n_objects = payload[2];
+ payload += 3;
+
+ if (ps->flags & PGS_PRES_SEGMENT_FLAG_UPDATE_PALETTE)
+ ps->palette_id = palette_id;
+
+ PGS_DUMP ("Video width %u height %u fps code %u\n", ps->vid_w, ps->vid_h,
+ ps->vid_fps_code);
+ PGS_DUMP
+ ("Composition num %u state 0x%02x flags 0x%02x palette id %u n_objects %u\n",
+ ps->composition_no, ps->composition_state, ps->flags, ps->palette_id,
+ n_objects);
+
+ pgs_presentation_segment_set_object_count (ps, n_objects);
+
+ for (i = 0; i < (gint) n_objects; i++) {
+ PgsCompositionObject *obj =
+ &g_array_index (ps->objects, PgsCompositionObject, i);
+
+ if (payload + 8 > end)
+ break;
+ obj->id = GST_READ_UINT16_BE (payload);
+ obj->win_id = payload[2];
+ obj->flags = payload[3];
+ obj->x = GST_READ_UINT16_BE (payload + 4);
+ obj->y = GST_READ_UINT16_BE (payload + 6);
+ obj->rle_data_size = obj->rle_data_used = 0;
+
+ payload += 8;
+
+ PGS_DUMP ("Composition object %d Object ID %u Window ID %u flags 0x%02x "
+ "x %u y %u\n", i, obj->id, obj->win_id, obj->flags, obj->x, obj->y);
+
+ if (obj->flags & PGS_COMPOSITION_OBJECT_FLAG_CROPPED) {
+ if (payload + 8 > end)
+ break;
+
+ obj->crop_x = GST_READ_UINT16_BE (payload);
+ obj->crop_y = GST_READ_UINT16_BE (payload + 2);
+ obj->crop_w = GST_READ_UINT16_BE (payload + 4);
+ obj->crop_h = GST_READ_UINT16_BE (payload + 6);
+
+ payload += 8;
+
+ PGS_DUMP ("Cropping window x %u y %u w %u h %u\n",
+ obj->crop_x, obj->crop_y, obj->crop_w, obj->crop_h);
+ }
+
+ if (obj->flags & ~(PGS_COMPOSITION_OBJECT_FLAG_CROPPED |
+ PGS_COMPOSITION_OBJECT_FLAG_FORCED))
+ g_warning ("PGS Composition Object has unknown flags: 0x%02x",
+ obj->flags);
+ }
+
+ if (payload != end) {
+ g_warning ("PGS Composition Object: %ld bytes not consumed", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_palette (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
+ guint16 len)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ const gint PGS_PALETTE_ENTRY_SIZE = 5;
+ guint8 *end = payload + len;
+ guint8 palette_id;
+ guint8 palette_version;
+ gint n_entries, i;
+
+ if (len < 2) /* Palette command too short */
+ return 0;
+ palette_id = payload[0];
+ palette_version = payload[1];
+ payload += 2;
+
+ n_entries = (len - 2) / PGS_PALETTE_ENTRY_SIZE;
+
+ PGS_DUMP ("Palette ID %u version %u. %d entries\n",
+ palette_id, palette_version, n_entries);
+ for (i = 0; i < 256; i++)
+ state->pgs.palette[i].A = 0;
+ for (i = 0; i < n_entries; i++) {
+ guint8 n, Y, U, V, A;
+ n = payload[0];
+ Y = payload[1];
+ U = payload[2];
+ V = payload[3];
+ A = payload[4];
+
+#if DUMP_FULL_PALETTE
+ PGS_DUMP ("Entry %3d: Y %3d U %3d V %3d A %3d ", n, Y, U, V, A);
+ if (((i + 1) % 2) == 0)
+ PGS_DUMP ("\n");
+#endif
+
+ /* Premultiply the palette entries by the alpha */
+ state->pgs.palette[n].Y = Y * A;
+ state->pgs.palette[n].U = U * A;
+ state->pgs.palette[n].V = V * A;
+ state->pgs.palette[n].A = A;
+
+ payload += PGS_PALETTE_ENTRY_SIZE;
+ }
+
+#if DUMP_FULL_PALETTE
+ if (n_entries > 0 && (i % 2))
+ PGS_DUMP ("\n");
+#endif
+
+ if (payload != end) {
+ g_warning ("PGS Set Palette: %ld bytes not consumed", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_window (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
+ guint16 len)
+{
+ SpuState *state = &dvdspu->spu_state;
+ guint8 *end = payload + len;
+ guint8 win_id, win_ver;
+
+ if (payload + 10 > end)
+ return 0;
+
+ dump_bytes (payload, len);
+
+ /* FIXME: This is just a guess as to what the numbers mean: */
+ win_id = payload[0];
+ win_ver = payload[1];
+ state->pgs.win_x = GST_READ_UINT16_BE (payload + 2);
+ state->pgs.win_y = GST_READ_UINT16_BE (payload + 4);
+ state->pgs.win_w = GST_READ_UINT16_BE (payload + 6);
+ state->pgs.win_h = GST_READ_UINT16_BE (payload + 8);
+ payload += 10;
+
+ PGS_DUMP ("Win ID %u version %d x %d y %d w %d h %d\n",
+ win_id, win_ver, state->pgs.win_x, state->pgs.win_y, state->pgs.win_w,
+ state->pgs.win_h);
+
+ if (payload != end) {
+ g_warning ("PGS Set Window: %ld bytes not consumed", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_set_object_data (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
+ guint16 len)
+{
+ SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
+ PgsCompositionObject *obj;
+ guint8 *end = payload + len;
+ guint16 obj_id;
+ guint8 obj_ver, flags;
+
+ if (payload + 4 > end)
+ return 0;
+
+ obj_id = GST_READ_UINT16_BE (payload);
+ obj_ver = payload[2];
+ flags = payload[3];
+ payload += 4;
+
+ obj = pgs_presentation_segment_find_object (&(pgs_state->pres_seg), obj_id);
+
+ PGS_DUMP ("Object ID %d ver %u flags 0x%02x\n", obj_id, obj_ver, flags);
+
+ if (flags & PGS_OBJECT_UPDATE_FLAG_START_RLE) {
+ obj->rle_data_ver = obj_ver;
+
+ if (payload + 3 > end)
+ return 0;
+
+ obj->rle_data_size = GST_READ_UINT24_BE (payload);
+ payload += 3;
+
+ PGS_DUMP ("%d bytes of RLE data, of %d bytes total.\n",
+ end - payload, obj->rle_data_size);
+
+ obj->rle_data = g_realloc (obj->rle_data, obj->rle_data_size);
+ obj->rle_data_used = end - payload;
+ memcpy (obj->rle_data, payload, end - payload);
+ payload = end;
+ } else {
+ PGS_DUMP ("%d bytes of additional RLE data\n", end - payload);
+ /* Check that the data chunk is for this object version, and fits in the buffer */
+ if (obj->rle_data_ver == obj_ver &&
+ obj->rle_data_used + end - payload <= obj->rle_data_size) {
+
+ memcpy (obj->rle_data + obj->rle_data_used, payload, end - payload);
+ obj->rle_data_used += end - payload;
+ payload = end;
+ }
+ }
+
+ if (obj->rle_data_size == obj->rle_data_used)
+ dump_rle_data (dvdspu, obj->rle_data, obj->rle_data_size);
+
+ if (payload != end) {
+ g_warning ("PGS Set Object Data: %ld bytes not consumed", end - payload);
+ dump_bytes (payload, end - payload);
+ }
+
+ return 0;
+}
+
+static int
+parse_pgs_packet (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
+ guint16 len)
+{
+ SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
+ int ret = 0;
+
+ if (!pgs_state->in_presentation_segment
+ && type != PGS_COMMAND_PRESENTATION_SEGMENT) {
+ PGS_DUMP ("Expected BEGIN PRESENTATION SEGMENT command. "
+ "Got command type 0x%02x len %u. Skipping\n", type, len);
+ return 0;
+ }
+
+ switch (type) {
+ case PGS_COMMAND_PRESENTATION_SEGMENT:
+ PGS_DUMP ("*******************************************\n"
+ "Begin PRESENTATION_SEGMENT (0x%02x) packet len %u\n", type, len);
+ pgs_state->in_presentation_segment =
+ pgs_state->have_presentation_segment = TRUE;
+ ret = parse_presentation_segment (dvdspu, type, payload, len);
+ break;
+ case PGS_COMMAND_SET_OBJECT_DATA:
+ PGS_DUMP ("*** Set Object Data (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_object_data (dvdspu, type, payload, len);
+ break;
+ case PGS_COMMAND_SET_PALETTE:
+ PGS_DUMP ("*** Set Palette (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_palette (dvdspu, type, payload, len);
+ break;
+ case PGS_COMMAND_SET_WINDOW:
+ PGS_DUMP ("*** Set Window command (0x%02x) packet len %u\n", type, len);
+ ret = parse_set_window (dvdspu, type, payload, len);
+ break;
+ case PGS_COMMAND_INTERACTIVE_SEGMENT:
+ PGS_DUMP ("*** Interactive Segment command(0x%02x) packet len %u\n",
+ type, len);
+ dump_bytes (payload, len);
+ break;
+ case PGS_COMMAND_END_DISPLAY:
+ PGS_DUMP ("*** End Display command (0x%02x) packet len %u\n", type,
+ len);
+ pgs_state->in_presentation_segment = FALSE;
+ break;
+ default:
+ g_warning ("Unknown PGS command: type 0x%02x len %u", type, len);
+ dump_bytes (payload, len);
+ break;
+ }
+ PGS_DUMP ("\n");
+
+ return ret;
+}
+
+gint
+gstspu_exec_pgs_buffer (GstDVDSpu * dvdspu, GstBuffer * buf)
+{
+ guint8 *pos, *end;
+ guint8 type;
+ guint16 packet_len;
+
+ pos = GST_BUFFER_DATA (buf);
+ end = pos + GST_BUFFER_SIZE (buf);
+
+ /* Need at least 3 bytes */
+ if (pos + 3 > end) {
+ PGS_DUMP ("Not enough bytes to be a PGS packet\n");
+ return -1;
+ }
+
+ PGS_DUMP ("Begin dumping command buffer of size %u ts %" GST_TIME_FORMAT "\n",
+ end - pos, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+ do {
+ type = *pos++;
+ packet_len = GST_READ_UINT16_BE (pos);
+ pos += 2;
+
+ if (pos + packet_len > end) {
+ PGS_DUMP ("Invalid packet length %u (only have %u bytes)\n", packet_len,
+ end - pos);
+ return -1;
+ }
+
+ if (parse_pgs_packet (dvdspu, type, pos, packet_len))
+ return -1;
+
+ pos += packet_len;
+ } while (pos + 3 <= end);
+
+ PGS_DUMP ("End dumping command buffer with %u bytes remaining\n", end - pos);
+ return (pos - GST_BUFFER_DATA (buf));
+}
+
+void
+gstspu_pgs_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts,
+ GstBuffer * buf)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ state->next_ts = event_ts;
+ state->pgs.pending_cmd = buf;
+}
+
+gboolean
+gstspu_pgs_execute_event (GstDVDSpu * dvdspu)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ if (state->pgs.pending_cmd) {
+ gstspu_exec_pgs_buffer (dvdspu, state->pgs.pending_cmd);
+ gst_buffer_unref (state->pgs.pending_cmd);
+ state->pgs.pending_cmd = NULL;
+ }
+
+ state->next_ts = GST_CLOCK_TIME_NONE;
+
+ state->flags &= ~SPU_STATE_DISPLAY;
+ if (state->pgs.have_presentation_segment) {
+ if (state->pgs.pres_seg.objects && state->pgs.pres_seg.objects->len > 0)
+ state->flags |= SPU_STATE_DISPLAY;
+ }
+ return FALSE;
+}
+
+void
+gstspu_pgs_render (GstDVDSpu * dvdspu, GstBuffer * buf)
+{
+ SpuState *state = &dvdspu->spu_state;
+ PgsPresentationSegment *ps = &state->pgs.pres_seg;
+ guint i;
+
+ if (ps->objects == NULL)
+ return;
+
+ for (i = 0; i < ps->objects->len; i++) {
+ PgsCompositionObject *cur =
+ &g_array_index (ps->objects, PgsCompositionObject, i);
+ pgs_composition_object_render (cur, state, buf);
+ }
+}
+
+gboolean
+gstspu_pgs_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
+{
+ return FALSE;
+}
+
+void
+gstspu_pgs_flush (GstDVDSpu * dvdspu)
+{
+ SpuPgsState *pgs_state = &dvdspu->spu_state.pgs;
+
+ if (pgs_state->pending_cmd) {
+ gst_buffer_unref (pgs_state->pending_cmd);
+ pgs_state->pending_cmd = NULL;
+ }
+
+ pgs_state->have_presentation_segment = FALSE;
+ pgs_state->in_presentation_segment = FALSE;
+ pgs_presentation_segment_set_object_count (&pgs_state->pres_seg, 0);
+
+ pgs_state->win_x = pgs_state->win_y = pgs_state->win_w = pgs_state->win_h = 0;
+}
diff --git a/gst/dvdspu/gstspu-pgs.h b/gst/dvdspu/gstspu-pgs.h
new file mode 100644
index 00000000..164f4d81
--- /dev/null
+++ b/gst/dvdspu/gstspu-pgs.h
@@ -0,0 +1,106 @@
+/* GStreamer Sub-Picture Unit - PGS handling
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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 __GSTSPU_PGS_H__
+#define __GSTSPU_PGS_H__
+
+#include "gstspu-common.h"
+
+typedef struct SpuPgsState SpuPgsState;
+typedef enum PgsCompositionObjectFlags PgsCompositionObjectFlags;
+typedef enum PgsPresentationSegmentFlags PgsPresentationSegmentFlags;
+typedef enum PgsObjectUpdateFlags PgsObjectUpdateFlags;
+
+typedef struct PgsPresentationSegment PgsPresentationSegment;
+typedef struct PgsCompositionObject PgsCompositionObject;
+
+enum PgsPresentationSegmentFlags
+{
+ PGS_PRES_SEGMENT_FLAG_UPDATE_PALETTE = 0x80
+};
+
+enum PgsCompositionObjectFlags
+{
+ PGS_COMPOSITION_OBJECT_FLAG_CROPPED = 0x80,
+ PGS_COMPOSITION_OBJECT_FLAG_FORCED = 0x40
+};
+
+enum PgsObjectUpdateFlags
+{
+ /* Set in an object_update if this is the beginning of new RLE data.
+ * If not set, the data is a continuation to be appended */
+ PGS_OBJECT_UPDATE_FLAG_START_RLE = 0x80,
+ PGS_OBJECT_UPDATE_FLAG_END_RLE = 0x40 /* This one is a guess */
+};
+
+struct PgsPresentationSegment
+{
+ guint16 composition_no;
+ guint8 composition_state;
+
+ PgsPresentationSegmentFlags flags;
+
+ guint8 palette_id;
+
+ guint16 vid_w, vid_h;
+ guint8 vid_fps_code;
+
+ GArray *objects;
+};
+
+struct PgsCompositionObject
+{
+ guint16 id;
+ guint8 version;
+ PgsCompositionObjectFlags flags;
+
+ guint8 win_id;
+
+ guint8 rle_data_ver;
+ guint8 *rle_data;
+ guint32 rle_data_size;
+ guint32 rle_data_used;
+
+ /* Top left corner of this object */
+ guint16 x, y;
+
+ /* Only valid if PGS_COMPOSITION_OBJECT_FLAG_CROPPED is set */
+ guint16 crop_x, crop_y, crop_w, crop_h;
+};
+
+struct SpuPgsState {
+ GstBuffer *pending_cmd;
+
+ gboolean in_presentation_segment;
+ gboolean have_presentation_segment;
+
+ PgsPresentationSegment pres_seg;
+
+ SpuColour palette[256];
+
+ guint16 win_x, win_y, win_w, win_h;
+};
+
+void gstspu_pgs_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
+gboolean gstspu_pgs_execute_event (GstDVDSpu *dvdspu);
+void gstspu_pgs_render (GstDVDSpu *dvdspu, GstBuffer *buf);
+gboolean gstspu_pgs_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
+void gstspu_pgs_flush (GstDVDSpu *dvdspu);
+
+#endif
diff --git a/gst/dvdspu/gstspu-vobsub-render.c b/gst/dvdspu/gstspu-vobsub-render.c
new file mode 100644
index 00000000..07abff22
--- /dev/null
+++ b/gst/dvdspu/gstspu-vobsub-render.c
@@ -0,0 +1,536 @@
+/* GStreamer DVD Sub-Picture Unit
+ * Copyright (C) 2007 Fluendo S.A. <info@fluendo.com>
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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 <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstdvdspu.h"
+
+GST_DEBUG_CATEGORY_EXTERN (dvdspu_debug);
+#define GST_CAT_DEFAULT dvdspu_debug
+
+static void
+gstspu_vobsub_recalc_palette (GstDVDSpu * dvdspu,
+ SpuColour * dest, guint8 * idx, guint8 * alpha)
+{
+ SpuState *state = &dvdspu->spu_state;
+ gint i;
+
+ for (i = 0; i < 4; i++, dest++) {
+ guint32 col = state->vobsub.current_clut[idx[i]];
+
+ /* Convert incoming 4-bit alpha to 8 bit for blending */
+ dest->A = (alpha[i] << 4) | alpha[i];
+ dest->Y = ((guint16) ((col >> 16) & 0xff)) * dest->A;
+ /* U/V are stored as V/U in the clut words, so switch them */
+ dest->V = ((guint16) ((col >> 8) & 0xff)) * dest->A;
+ dest->U = ((guint16) (col & 0xff)) * dest->A;
+ }
+}
+
+/* Recalculate the main, HL & ChgCol palettes */
+static void
+gstspu_vobsub_update_palettes (GstDVDSpu * dvdspu, SpuState * state)
+{
+ guint8 index[4]; /* Indices for the palette */
+ guint8 alpha[4]; /* Alpha values the palette */
+
+ if (state->vobsub.main_pal_dirty) {
+ gstspu_vobsub_recalc_palette (dvdspu, state->vobsub.main_pal,
+ state->vobsub.main_idx, state->vobsub.main_alpha);
+
+ /* Need to refresh the hl_ctrl info copies of the main palette too */
+ memcpy (state->vobsub.hl_ctrl_i.pix_ctrl_i[0].pal_cache,
+ state->vobsub.main_pal, 4 * sizeof (SpuColour));
+ memcpy (state->vobsub.hl_ctrl_i.pix_ctrl_i[2].pal_cache,
+ state->vobsub.main_pal, 4 * sizeof (SpuColour));
+
+ state->vobsub.main_pal_dirty = FALSE;
+ }
+
+ if (state->vobsub.hl_pal_dirty) {
+ gstspu_vobsub_recalc_palette (dvdspu,
+ state->vobsub.hl_ctrl_i.pix_ctrl_i[1].pal_cache, state->vobsub.hl_idx,
+ state->vobsub.hl_alpha);
+ state->vobsub.hl_pal_dirty = FALSE;
+ }
+
+ /* Update the offset positions for the highlight region */
+ if (state->vobsub.hl_rect.top != -1) {
+ state->vobsub.hl_ctrl_i.top = state->vobsub.hl_rect.top;
+ state->vobsub.hl_ctrl_i.bottom = state->vobsub.hl_rect.bottom;
+ state->vobsub.hl_ctrl_i.n_changes = 3;
+ state->vobsub.hl_ctrl_i.pix_ctrl_i[0].left = 0;
+ state->vobsub.hl_ctrl_i.pix_ctrl_i[1].left = state->vobsub.hl_rect.left;
+ state->vobsub.hl_ctrl_i.pix_ctrl_i[2].left =
+ state->vobsub.hl_rect.right + 1;
+ }
+
+ if (state->vobsub.line_ctrl_i_pal_dirty) {
+ gint16 l, c;
+ GST_LOG_OBJECT (dvdspu, "Updating chg-col-con palettes");
+ for (l = 0; l < state->vobsub.n_line_ctrl_i; l++) {
+ SpuVobsubLineCtrlI *cur_line_ctrl = state->vobsub.line_ctrl_i + l;
+
+ for (c = 0; c < cur_line_ctrl->n_changes; c++) {
+ SpuVobsubPixCtrlI *cur = cur_line_ctrl->pix_ctrl_i + c;
+
+ index[3] = (cur->palette >> 28) & 0x0f;
+ index[2] = (cur->palette >> 24) & 0x0f;
+ index[1] = (cur->palette >> 20) & 0x0f;
+ index[0] = (cur->palette >> 16) & 0x0f;
+
+ alpha[3] = (cur->palette >> 12) & 0x0f;
+ alpha[2] = (cur->palette >> 8) & 0x0f;
+ alpha[1] = (cur->palette >> 4) & 0x0f;
+ alpha[0] = (cur->palette) & 0x0f;
+ gstspu_vobsub_recalc_palette (dvdspu, cur->pal_cache, index, alpha);
+ }
+ }
+ state->vobsub.line_ctrl_i_pal_dirty = FALSE;
+ }
+}
+
+static inline guint8
+gstspu_vobsub_get_nibble (SpuState * state, guint16 * rle_offset)
+{
+ guint8 ret;
+
+ if (G_UNLIKELY (*rle_offset >= state->vobsub.max_offset))
+ return 0; /* Overran the buffer */
+
+ ret = GST_BUFFER_DATA (state->vobsub.pix_buf)[(*rle_offset) / 2];
+
+ /* If the offset is even, we shift the answer down 4 bits, otherwise not */
+ if (*rle_offset & 0x01)
+ ret &= 0x0f;
+ else
+ ret = ret >> 4;
+
+ (*rle_offset)++;
+ return ret;
+}
+
+static guint16
+gstspu_vobsub_get_rle_code (SpuState * state, guint16 * rle_offset)
+{
+ guint16 code;
+
+ code = gstspu_vobsub_get_nibble (state, rle_offset);
+ if (code < 0x4) { /* 4 .. f */
+ code = (code << 4) | gstspu_vobsub_get_nibble (state, rle_offset);
+ if (code < 0x10) { /* 1x .. 3x */
+ code = (code << 4) | gstspu_vobsub_get_nibble (state, rle_offset);
+ if (code < 0x40) { /* 04x .. 0fx */
+ code = (code << 4) | gstspu_vobsub_get_nibble (state, rle_offset);
+ }
+ }
+ }
+ return code;
+}
+
+static inline void
+gstspu_vobsub_draw_rle_run (SpuState * state, gint16 x, gint16 end,
+ SpuColour * colour)
+{
+#if 0
+ GST_LOG ("Y: %d x: %d end %d col %d %d %d %d",
+ state->vobsub.cur_Y, x, end, colour->Y, colour->U, colour->V, colour->A);
+#endif
+
+ if (colour->A != 0) {
+ guint32 inv_A = 0xff - colour->A;
+
+ /* FIXME: This could be more efficient */
+ while (x < end) {
+ state->vobsub.out_Y[x] =
+ (inv_A * state->vobsub.out_Y[x] + colour->Y) / 0xff;
+ state->vobsub.out_U[x / 2] += colour->U;
+ state->vobsub.out_V[x / 2] += colour->V;
+ state->vobsub.out_A[x / 2] += colour->A;
+ x++;
+ }
+ /* Update the compositing buffer so we know how much to blend later */
+ *(state->vobsub.comp_last_x_ptr) = end;
+ }
+}
+
+static inline gint16
+rle_end_x (guint16 rle_code, gint16 x, gint16 end)
+{
+ /* run length = rle_code >> 2 */
+ if (G_UNLIKELY (((rle_code >> 2) == 0)))
+ return end;
+ else
+ return MIN (end, x + (rle_code >> 2));
+}
+
+static void gstspu_vobsub_render_line_with_chgcol (SpuState * state,
+ guint8 * planes[3], guint16 * rle_offset);
+static gboolean gstspu_vobsub_update_chgcol (SpuState * state);
+
+static void
+gstspu_vobsub_render_line (SpuState * state, guint8 * planes[3],
+ guint16 * rle_offset)
+{
+ gint16 x, next_x, end, rle_code;
+ SpuColour *colour;
+
+ /* Check for special case of chg_col info to use (either highlight or
+ * ChgCol command */
+ if (state->vobsub.cur_chg_col != NULL) {
+ if (gstspu_vobsub_update_chgcol (state)) {
+ /* Check the top & bottom, because we might not be within the region yet */
+ if (state->vobsub.cur_Y >= state->vobsub.cur_chg_col->top &&
+ state->vobsub.cur_Y <= state->vobsub.cur_chg_col->bottom) {
+ gstspu_vobsub_render_line_with_chgcol (state, planes, rle_offset);
+ return;
+ }
+ }
+ }
+
+ /* No special case. Render as normal */
+
+ /* Set up our output pointers */
+ state->vobsub.out_Y = planes[0];
+ state->vobsub.out_U = state->comp_bufs[0];
+ state->vobsub.out_V = state->comp_bufs[1];
+ state->vobsub.out_A = state->comp_bufs[2];
+ /* We always need to start our RLE decoding byte_aligned */
+ *rle_offset = GST_ROUND_UP_2 (*rle_offset);
+
+ x = state->vobsub.disp_rect.left;
+ end = state->vobsub.disp_rect.right + 1;
+ while (x < end) {
+ rle_code = gstspu_vobsub_get_rle_code (state, rle_offset);
+ colour = &state->vobsub.main_pal[rle_code & 3];
+ next_x = rle_end_x (rle_code, x, end);
+ /* Now draw the run between [x,next_x) */
+ gstspu_vobsub_draw_rle_run (state, x, next_x, colour);
+ x = next_x;
+ }
+}
+
+static gboolean
+gstspu_vobsub_update_chgcol (SpuState * state)
+{
+ if (state->vobsub.cur_chg_col == NULL)
+ return FALSE;
+
+ if (state->vobsub.cur_Y <= state->vobsub.cur_chg_col->bottom)
+ return TRUE;
+
+ while (state->vobsub.cur_chg_col < state->vobsub.cur_chg_col_end) {
+ if (state->vobsub.cur_Y >= state->vobsub.cur_chg_col->top &&
+ state->vobsub.cur_Y <= state->vobsub.cur_chg_col->bottom) {
+#if 0
+ g_print ("Stopped @ entry %d with top %d bottom %d, cur_y %d",
+ (gint16) (state->vobsub.cur_chg_col - state->vobsub.line_ctrl_i),
+ state->vobsub.cur_chg_col->top, state->vobsub.cur_chg_col->bottom, y);
+#endif
+ return TRUE;
+ }
+ state->vobsub.cur_chg_col++;
+ }
+
+ /* Finished all our cur_chg_col entries. Use the main palette from here on */
+ state->vobsub.cur_chg_col = NULL;
+ return FALSE;
+}
+
+static void
+gstspu_vobsub_render_line_with_chgcol (SpuState * state, guint8 * planes[3],
+ guint16 * rle_offset)
+{
+ SpuVobsubLineCtrlI *chg_col = state->vobsub.cur_chg_col;
+
+ gint16 x, next_x, disp_end, rle_code, run_end;
+ SpuColour *colour;
+ SpuVobsubPixCtrlI *cur_pix_ctrl;
+ SpuVobsubPixCtrlI *next_pix_ctrl;
+ SpuVobsubPixCtrlI *end_pix_ctrl;
+ SpuVobsubPixCtrlI dummy_pix_ctrl;
+ gint16 cur_reg_end;
+ gint i;
+
+ state->vobsub.out_Y = planes[0];
+ state->vobsub.out_U = state->comp_bufs[0];
+ state->vobsub.out_V = state->comp_bufs[1];
+ state->vobsub.out_A = state->comp_bufs[2];
+
+ /* We always need to start our RLE decoding byte_aligned */
+ *rle_offset = GST_ROUND_UP_2 (*rle_offset);
+
+ /* Our run will cover the display rect */
+ x = state->vobsub.disp_rect.left;
+ disp_end = state->vobsub.disp_rect.right + 1;
+
+ /* Work out the first pixel control info, which may point to the dummy entry if
+ * the global palette/alpha need using initally */
+ cur_pix_ctrl = chg_col->pix_ctrl_i;
+ end_pix_ctrl = chg_col->pix_ctrl_i + chg_col->n_changes;
+
+ if (cur_pix_ctrl->left != 0) {
+ next_pix_ctrl = cur_pix_ctrl;
+ cur_pix_ctrl = &dummy_pix_ctrl;
+ for (i = 0; i < 4; i++) /* Copy the main palette to our dummy entry */
+ dummy_pix_ctrl.pal_cache[i] = state->vobsub.main_pal[i];
+ } else {
+ next_pix_ctrl = cur_pix_ctrl + 1;
+ }
+ if (next_pix_ctrl < end_pix_ctrl)
+ cur_reg_end = next_pix_ctrl->left;
+ else
+ cur_reg_end = disp_end;
+
+ /* Render stuff */
+ while (x < disp_end) {
+ rle_code = gstspu_vobsub_get_rle_code (state, rle_offset);
+ next_x = rle_end_x (rle_code, x, disp_end);
+
+ /* Now draw the run between [x,next_x), crossing palette regions as needed */
+ while (x < next_x) {
+ run_end = MIN (next_x, cur_reg_end);
+
+ if (G_LIKELY (x < run_end)) {
+ colour = &cur_pix_ctrl->pal_cache[rle_code & 3];
+ gstspu_vobsub_draw_rle_run (state, x, run_end, colour);
+ x = run_end;
+ }
+
+ if (x >= cur_reg_end) {
+ /* Advance to next region */
+ cur_pix_ctrl = next_pix_ctrl;
+ next_pix_ctrl++;
+
+ if (next_pix_ctrl < end_pix_ctrl)
+ cur_reg_end = next_pix_ctrl->left;
+ else
+ cur_reg_end = disp_end;
+ }
+ }
+ }
+}
+
+static void
+gstspu_vobsub_blend_comp_buffers (SpuState * state, guint8 * planes[3])
+{
+ state->comp_left = state->vobsub.disp_rect.left;
+ state->comp_right =
+ MAX (state->vobsub.comp_last_x[0], state->vobsub.comp_last_x[1]);
+
+ gstspu_blend_comp_buffers (state, planes);
+}
+
+void
+gstspu_vobsub_clear_comp_buffers (SpuState * state)
+{
+ state->comp_left = state->vobsub.disp_rect.left;
+ state->comp_right = state->vobsub.disp_rect.right;
+
+ gstspu_clear_comp_buffers (state);
+
+ state->vobsub.comp_last_x[0] = -1;
+ state->vobsub.comp_last_x[1] = -1;
+}
+
+void
+gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
+{
+ SpuState *state = &dvdspu->spu_state;
+ guint8 *planes[3]; /* YUV frame pointers */
+ gint y, last_y;
+
+ /* Set up our initial state */
+ if (G_UNLIKELY (state->vobsub.pix_buf == NULL))
+ return;
+
+ /* Store the start of each plane */
+ planes[0] = GST_BUFFER_DATA (buf);
+ planes[1] = planes[0] + (state->Y_height * state->Y_stride);
+ planes[2] = planes[1] + (state->UV_height * state->UV_stride);
+
+ /* Sanity check */
+ g_return_if_fail (planes[2] + (state->UV_height * state->UV_stride) <=
+ GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf));
+
+ GST_DEBUG ("Rendering SPU. disp_rect %d,%d to %d,%d. hl_rect %d,%d to %d,%d",
+ state->vobsub.disp_rect.left, state->vobsub.disp_rect.top,
+ state->vobsub.disp_rect.right, state->vobsub.disp_rect.bottom,
+ state->vobsub.hl_rect.left, state->vobsub.hl_rect.top,
+ state->vobsub.hl_rect.right, state->vobsub.hl_rect.bottom);
+
+ GST_DEBUG ("vid_disp %d,%d", state->vid_width, state->vid_height);
+
+ /* When reading RLE data, we track the offset in nibbles... */
+ state->vobsub.cur_offsets[0] = state->vobsub.pix_data[0] * 2;
+ state->vobsub.cur_offsets[1] = state->vobsub.pix_data[1] * 2;
+ state->vobsub.max_offset = GST_BUFFER_SIZE (state->vobsub.pix_buf) * 2;
+
+ /* Update all the palette caches */
+ gstspu_vobsub_update_palettes (dvdspu, state);
+
+ /* Set up HL or Change Color & Contrast rect tracking */
+ if (state->vobsub.hl_rect.top != -1) {
+ state->vobsub.cur_chg_col = &state->vobsub.hl_ctrl_i;
+ state->vobsub.cur_chg_col_end = state->vobsub.cur_chg_col + 1;
+ } else if (state->vobsub.n_line_ctrl_i > 0) {
+ state->vobsub.cur_chg_col = state->vobsub.line_ctrl_i;
+ state->vobsub.cur_chg_col_end =
+ state->vobsub.cur_chg_col + state->vobsub.n_line_ctrl_i;
+ } else
+ state->vobsub.cur_chg_col = NULL;
+
+ /* We start rendering from the first line of the display rect */
+ y = state->vobsub.disp_rect.top;
+ /* start_y is always an even number and we render lines in pairs from there,
+ * accumulating 2 lines of chroma then blending it. We might need to render a
+ * single line at the end if the display rect ends on an even line too. */
+ last_y = (state->vobsub.disp_rect.bottom - 1) & ~(0x01);
+
+ /* center the image when display rectangle exceeds the video width */
+ if (state->vid_width < state->vobsub.disp_rect.right) {
+ gint diff, disp_width;
+
+ disp_width = state->vobsub.disp_rect.left - state->vobsub.disp_rect.right;
+ diff = (disp_width - state->vid_width) / 2;
+
+ /* fixme, this is not used yet */
+ state->vobsub.clip_rect.left = state->vobsub.disp_rect.left + diff;
+ state->vobsub.clip_rect.right = state->vobsub.disp_rect.right - diff;
+
+ GST_DEBUG ("clipping width to %d,%d", state->vobsub.clip_rect.left,
+ state->vobsub.clip_rect.right);
+ } else {
+ state->vobsub.clip_rect.left = state->vobsub.disp_rect.left;
+ state->vobsub.clip_rect.right = state->vobsub.disp_rect.right;
+ }
+
+ /* for the height, chop off the bottom bits of the diplay rectangle because we
+ * assume the picture is in the lower part. We should better check where it
+ * is and do something more clever. */
+ state->vobsub.clip_rect.bottom = state->vobsub.disp_rect.bottom;
+ if (state->vid_height < state->vobsub.disp_rect.bottom) {
+ state->vobsub.clip_rect.top =
+ state->vobsub.disp_rect.bottom - state->vid_height;
+ GST_DEBUG ("clipping height to %d,%d", state->vobsub.clip_rect.top,
+ state->vobsub.clip_rect.bottom);
+ } else {
+ state->vobsub.clip_rect.top = state->vobsub.disp_rect.top;
+ /* Update our plane references to the first line of the disp_rect */
+ planes[0] += state->Y_stride * y;
+ planes[1] += state->UV_stride * (y / 2);
+ planes[2] += state->UV_stride * (y / 2);
+ }
+
+ for (state->vobsub.cur_Y = y; state->vobsub.cur_Y <= last_y;
+ state->vobsub.cur_Y++) {
+ gboolean clip;
+
+ clip = (state->vobsub.cur_Y < state->vobsub.clip_rect.top
+ || state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
+
+ /* Reset the compositing buffer */
+ gstspu_clear_comp_buffers (state);
+ /* Render even line */
+ state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
+ gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
+ if (!clip) {
+ /* Advance the luminance output pointer */
+ planes[0] += state->Y_stride;
+ }
+ state->vobsub.cur_Y++;
+
+ /* Render odd line */
+ state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x + 1;
+ gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[1]);
+ /* Blend the accumulated UV compositing buffers onto the output */
+ gstspu_vobsub_blend_comp_buffers (state, planes);
+
+ if (!clip) {
+ /* Update all the output pointers */
+ planes[0] += state->Y_stride;
+ planes[1] += state->UV_stride;
+ planes[2] += state->UV_stride;
+ }
+ }
+ if (state->vobsub.cur_Y == state->vobsub.disp_rect.bottom) {
+ g_assert ((state->vobsub.disp_rect.bottom & 0x01) == 0);
+
+ /* Render a remaining lone last even line. y already has the correct value
+ * after the above loop exited. */
+ gstspu_clear_comp_buffers (state);
+ state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
+ gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
+ gstspu_vobsub_blend_comp_buffers (state, planes);
+ }
+
+ /* for debugging purposes, draw a faint rectangle at the edges of the disp_rect */
+#if 0
+ do {
+ guint8 *cur;
+ gint16 pos;
+
+ cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->vobsub.disp_rect.top;
+ for (pos = state->vobsub.disp_rect.left + 1;
+ pos < state->vobsub.disp_rect.right; pos++)
+ cur[pos] = (cur[pos] / 2) + 0x8;
+ cur =
+ GST_BUFFER_DATA (buf) +
+ state->Y_stride * state->vobsub.disp_rect.bottom;
+ for (pos = state->vobsub.disp_rect.left + 1;
+ pos < state->vobsub.disp_rect.right; pos++)
+ cur[pos] = (cur[pos] / 2) + 0x8;
+ cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->vobsub.disp_rect.top;
+ for (pos = state->vobsub.disp_rect.top;
+ pos <= state->vobsub.disp_rect.bottom; pos++) {
+ cur[state->vobsub.disp_rect.left] =
+ (cur[state->vobsub.disp_rect.left] / 2) + 0x8;
+ cur[state->vobsub.disp_rect.right] =
+ (cur[state->vobsub.disp_rect.right] / 2) + 0x8;
+ cur += state->Y_stride;
+ }
+ } while (0);
+#endif
+ /* For debugging purposes, draw a faint rectangle around the highlight rect */
+#if 0
+ if (state->hl_rect.top != -1) {
+ guint8 *cur;
+ gint16 pos;
+
+ cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.top;
+ for (pos = state->hl_rect.left + 1; pos < state->hl_rect.right; pos++)
+ cur[pos] = (cur[pos] / 2) + 0x8;
+ cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.bottom;
+ for (pos = state->hl_rect.left + 1; pos < state->hl_rect.right; pos++)
+ cur[pos] = (cur[pos] / 2) + 0x8;
+ cur = GST_BUFFER_DATA (buf) + state->Y_stride * state->hl_rect.top;
+ for (pos = state->hl_rect.top; pos <= state->hl_rect.bottom; pos++) {
+ cur[state->hl_rect.left] = (cur[state->hl_rect.left] / 2) + 0x8;
+ cur[state->hl_rect.right] = (cur[state->hl_rect.right] / 2) + 0x8;
+ cur += state->Y_stride;
+ }
+ }
+#endif
+}
diff --git a/gst/dvdspu/gstspu-vobsub.c b/gst/dvdspu/gstspu-vobsub.c
new file mode 100644
index 00000000..1757feb7
--- /dev/null
+++ b/gst/dvdspu/gstspu-vobsub.c
@@ -0,0 +1,513 @@
+/* GStreamer Sub-Picture Unit - VobSub/DVD handling
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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 <config.h>
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+
+#include "gstdvdspu.h"
+#include "gstspu-vobsub.h"
+
+GST_DEBUG_CATEGORY_EXTERN (dvdspu_debug);
+#define GST_CAT_DEFAULT dvdspu_debug
+
+/* Define to dump out a text description of the incoming SPU commands */
+#define DUMP_DCSQ 0
+
+/* Convert an STM offset in the SPU sequence to a GStreamer timestamp */
+#define STM_TO_GST(stm) ((GST_MSECOND * 1024 * (stm)) / 90)
+
+typedef enum SpuVobsubCmd SpuVobsubCmd;
+
+enum SpuVobsubCmd
+{
+ SPU_CMD_FSTA_DSP = 0x00, /* Forced Display */
+ SPU_CMD_DSP = 0x01, /* Display Start */
+ SPU_CMD_STP_DSP = 0x02, /* Display Off */
+ SPU_CMD_SET_COLOR = 0x03, /* Set the color indexes for the palette */
+ SPU_CMD_SET_ALPHA = 0x04, /* Set the alpha indexes for the palette */
+ SPU_CMD_SET_DAREA = 0x05, /* Set the display area for the SPU */
+ SPU_CMD_DSPXA = 0x06, /* Pixel data addresses */
+ SPU_CMD_CHG_COLCON = 0x07, /* Change Color & Contrast */
+ SPU_CMD_END = 0xff
+};
+
+static void
+gst_dvd_spu_parse_chg_colcon (GstDVDSpu * dvdspu, guint8 * data, guint8 * end)
+{
+ SpuState *state = &dvdspu->spu_state;
+ guint8 *cur;
+ gint16 n_entries;
+ gint16 i;
+
+ /* Clear any existing chg colcon info */
+ state->vobsub.n_line_ctrl_i = 0;
+ if (state->vobsub.line_ctrl_i != NULL) {
+ g_free (state->vobsub.line_ctrl_i);
+ state->vobsub.line_ctrl_i = NULL;
+ }
+ GST_DEBUG_OBJECT (dvdspu, "Change Color & Contrast. Pixel data = %d bytes",
+ (gint16) (end - data));
+
+ /* Count the number of entries we'll need */
+ n_entries = 0;
+ for (cur = data; cur < end;) {
+ guint8 n_changes;
+ guint32 code;
+
+ if (cur + 4 > end)
+ break;
+
+ code = GST_READ_UINT32_BE (cur);
+ if (code == 0x0fffffff)
+ break; /* Termination code */
+
+ n_changes = CLAMP ((cur[2] >> 4), 1, 8);
+ cur += 4 + (6 * n_changes);
+
+ if (cur > end)
+ break; /* Invalid entry overrunning buffer */
+
+ n_entries++;
+ }
+
+ state->vobsub.n_line_ctrl_i = n_entries;
+ state->vobsub.line_ctrl_i = g_new (SpuVobsubLineCtrlI, n_entries);
+
+ cur = data;
+ for (i = 0; i < n_entries; i++) {
+ SpuVobsubLineCtrlI *cur_line_ctrl = state->vobsub.line_ctrl_i + i;
+ guint8 n_changes = CLAMP ((cur[2] >> 4), 1, 8);
+ guint8 c;
+
+ cur_line_ctrl->n_changes = n_changes;
+ cur_line_ctrl->top = ((cur[0] << 8) & 0x300) | cur[1];
+ cur_line_ctrl->bottom = ((cur[2] << 8) & 0x300) | cur[3];
+
+ GST_LOG_OBJECT (dvdspu, "ChgColcon Entry %d Top: %d Bottom: %d Changes: %d",
+ i, cur_line_ctrl->top, cur_line_ctrl->bottom, n_changes);
+ cur += 4;
+
+ for (c = 0; c < n_changes; c++) {
+ SpuVobsubPixCtrlI *cur_pix_ctrl = cur_line_ctrl->pix_ctrl_i + c;
+
+ cur_pix_ctrl->left = ((cur[0] << 8) & 0x300) | cur[1];
+ cur_pix_ctrl->palette = GST_READ_UINT32_BE (cur + 2);
+ GST_LOG_OBJECT (dvdspu, " %d: left: %d palette 0x%x", c,
+ cur_pix_ctrl->left, cur_pix_ctrl->palette);
+ cur += 6;
+ }
+ }
+}
+
+static void
+gst_dvd_spu_exec_cmd_blk (GstDVDSpu * dvdspu, guint8 * data, guint8 * end)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ while (data < end) {
+ guint8 cmd;
+
+ cmd = data[0];
+
+ switch (cmd) {
+ case SPU_CMD_FSTA_DSP:
+ GST_DEBUG_OBJECT (dvdspu, " Forced Display");
+ state->flags |= SPU_STATE_FORCED_DSP;
+ data += 1;
+ break;
+ case SPU_CMD_DSP:
+ GST_DEBUG_OBJECT (dvdspu, " Display On");
+ state->flags |= SPU_STATE_DISPLAY;
+ data += 1;
+ break;
+ case SPU_CMD_STP_DSP:
+ GST_DEBUG_OBJECT (dvdspu, " Display Off");
+ state->flags &= ~(SPU_STATE_FORCED_DSP | SPU_STATE_DISPLAY);
+ data += 1;
+ break;
+ case SPU_CMD_SET_COLOR:{
+ if (G_UNLIKELY (data + 3 >= end))
+ return; /* Invalid SET_COLOR cmd at the end of the blk */
+
+ state->vobsub.main_idx[3] = data[1] >> 4;
+ state->vobsub.main_idx[2] = data[1] & 0x0f;
+ state->vobsub.main_idx[1] = data[2] >> 4;
+ state->vobsub.main_idx[0] = data[2] & 0x0f;
+
+ state->vobsub.main_pal_dirty = TRUE;
+
+ GST_DEBUG_OBJECT (dvdspu,
+ " Set Color bg %u pattern %u emph-1 %u emph-2 %u",
+ state->vobsub.main_idx[0], state->vobsub.main_idx[1],
+ state->vobsub.main_idx[2], state->vobsub.main_idx[3]);
+ data += 3;
+ break;
+ }
+ case SPU_CMD_SET_ALPHA:{
+ if (G_UNLIKELY (data + 3 >= end))
+ return; /* Invalid SET_ALPHA cmd at the end of the blk */
+
+ state->vobsub.main_alpha[3] = data[1] >> 4;
+ state->vobsub.main_alpha[2] = data[1] & 0x0f;
+ state->vobsub.main_alpha[1] = data[2] >> 4;
+ state->vobsub.main_alpha[0] = data[2] & 0x0f;
+
+ state->vobsub.main_pal_dirty = TRUE;
+
+ GST_DEBUG_OBJECT (dvdspu,
+ " Set Alpha bg %u pattern %u emph-1 %u emph-2 %u",
+ state->vobsub.main_alpha[0], state->vobsub.main_alpha[1],
+ state->vobsub.main_alpha[2], state->vobsub.main_alpha[3]);
+ data += 3;
+ break;
+ }
+ case SPU_CMD_SET_DAREA:{
+ SpuRect *r = &state->vobsub.disp_rect;
+
+ if (G_UNLIKELY (data + 7 >= end))
+ return; /* Invalid SET_DAREA cmd at the end of the blk */
+
+ r->top = ((data[4] & 0x3f) << 4) | ((data[5] & 0xe0) >> 4);
+ r->left = ((data[1] & 0x3f) << 4) | ((data[2] & 0xf0) >> 4);
+ r->right = ((data[2] & 0x03) << 8) | data[3];
+ r->bottom = ((data[5] & 0x03) << 8) | data[6];
+
+ GST_DEBUG_OBJECT (dvdspu,
+ " Set Display Area top %u left %u bottom %u right %u", r->top,
+ r->left, r->bottom, r->right);
+
+ data += 7;
+ break;
+ }
+ case SPU_CMD_DSPXA:{
+ if (G_UNLIKELY (data + 5 >= end))
+ return; /* Invalid SET_DSPXE cmd at the end of the blk */
+
+ state->vobsub.pix_data[0] = GST_READ_UINT16_BE (data + 1);
+ state->vobsub.pix_data[1] = GST_READ_UINT16_BE (data + 3);
+ /* Store a reference to the current command buffer, as that's where
+ * we'll need to take our pixel data from */
+ gst_buffer_replace (&state->vobsub.pix_buf, state->vobsub.buf);
+
+ GST_DEBUG_OBJECT (dvdspu, " Set Pixel Data Offsets top: %u bot: %u",
+ state->vobsub.pix_data[0], state->vobsub.pix_data[1]);
+
+ data += 5;
+ break;
+ }
+ case SPU_CMD_CHG_COLCON:{
+ guint16 field_size;
+
+ GST_DEBUG_OBJECT (dvdspu, " Set Color & Contrast Change");
+ if (G_UNLIKELY (data + 3 >= end))
+ return; /* Invalid CHG_COLCON cmd at the end of the blk */
+
+ data++;
+ field_size = GST_READ_UINT16_BE (data);
+
+ if (G_UNLIKELY (data + field_size >= end))
+ return; /* Invalid CHG_COLCON cmd at the end of the blk */
+
+ gst_dvd_spu_parse_chg_colcon (dvdspu, data + 2, data + field_size);
+ state->vobsub.line_ctrl_i_pal_dirty = TRUE;
+ data += field_size;
+ break;
+ }
+ case SPU_CMD_END:
+ default:
+ GST_DEBUG_OBJECT (dvdspu, " END");
+ data = end;
+ break;
+ }
+ }
+}
+
+static void
+gst_dvd_spu_finish_spu_buf (GstDVDSpu * dvdspu)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ state->next_ts = state->vobsub.base_ts = GST_CLOCK_TIME_NONE;
+ gst_buffer_replace (&state->vobsub.buf, NULL);
+
+ GST_DEBUG_OBJECT (dvdspu, "Finished SPU buffer");
+}
+
+static gboolean
+gst_dvd_spu_setup_cmd_blk (GstDVDSpu * dvdspu, guint16 cmd_blk_offset,
+ guint8 * start, guint8 * end)
+{
+ SpuState *state = &dvdspu->spu_state;
+ guint16 delay;
+ guint8 *cmd_blk = start + cmd_blk_offset;
+
+ if (G_UNLIKELY (cmd_blk + 5 >= end))
+ return FALSE; /* No valid command block to read */
+
+ delay = GST_READ_UINT16_BE (cmd_blk);
+ state->next_ts = state->vobsub.base_ts + STM_TO_GST (delay);
+ state->vobsub.cur_cmd_blk = cmd_blk_offset;
+
+ GST_DEBUG_OBJECT (dvdspu, "Setup CMD Block @ %u with TS %" GST_TIME_FORMAT,
+ state->vobsub.cur_cmd_blk, GST_TIME_ARGS (state->next_ts));
+ return TRUE;
+}
+
+#if DUMP_DCSQ
+static void
+gst_dvd_spu_dump_dcsq (GstDVDSpu * dvdspu,
+ GstClockTime start_ts, GstBuffer * spu_buf)
+{
+ guint16 cmd_blk_offset;
+ guint16 next_blk;
+ guint8 *start, *end;
+
+ start = GST_BUFFER_DATA (spu_buf);
+ end = start + GST_BUFFER_SIZE (spu_buf);
+
+ g_return_if_fail (start != NULL);
+
+ /* First command */
+ next_blk = GST_READ_UINT16_BE (start + 2);
+ cmd_blk_offset = 0;
+
+ /* Loop through all commands */
+ g_print ("SPU begins @ %" GST_TIME_FORMAT " offset %u\n",
+ GST_TIME_ARGS (start_ts), next_blk);
+
+ while (cmd_blk_offset != next_blk) {
+ guint8 *data;
+ GstClockTime cmd_blk_ts;
+
+ cmd_blk_offset = next_blk;
+
+ if (G_UNLIKELY (start + cmd_blk_offset + 5 >= end))
+ break; /* No valid command to read */
+
+ data = start + cmd_blk_offset;
+
+ cmd_blk_ts = start_ts + STM_TO_GST (GST_READ_UINT16_BE (data));
+ next_blk = GST_READ_UINT16_BE (data + 2);
+
+ g_print ("Cmd Blk @ offset %u next %u ts %" GST_TIME_FORMAT "\n",
+ cmd_blk_offset, next_blk, GST_TIME_ARGS (cmd_blk_ts));
+
+ data += 4;
+ gst_dvd_spu_exec_cmd_blk (dvdspu, data, end);
+ }
+}
+#endif
+
+void
+gstspu_vobsub_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts,
+ GstBuffer * buf)
+{
+ guint8 *start, *end;
+ SpuState *state = &dvdspu->spu_state;
+
+#if DUMP_DCSQ
+ gst_dvd_spu_dump_dcsq (dvdspu, event_ts, buf);
+#endif
+
+ if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < 4))
+ goto invalid;
+
+ if (state->vobsub.buf != NULL) {
+ gst_buffer_unref (state->vobsub.buf);
+ state->vobsub.buf = NULL;
+ }
+ state->vobsub.buf = buf;
+ state->vobsub.base_ts = event_ts;
+
+ start = GST_BUFFER_DATA (state->vobsub.buf);
+ end = start + GST_BUFFER_SIZE (state->vobsub.buf);
+
+ /* Configure the first command block in this buffer as our initial blk */
+ state->vobsub.cur_cmd_blk = GST_READ_UINT16_BE (start + 2);
+ gst_dvd_spu_setup_cmd_blk (dvdspu, state->vobsub.cur_cmd_blk, start, end);
+ /* Clear existing chg-colcon info */
+ state->vobsub.n_line_ctrl_i = 0;
+ if (state->vobsub.line_ctrl_i != NULL) {
+ g_free (state->vobsub.line_ctrl_i);
+ state->vobsub.line_ctrl_i = NULL;
+ }
+ return;
+
+invalid:
+ /* Invalid buffer */
+ gst_dvd_spu_finish_spu_buf (dvdspu);
+}
+
+gboolean
+gstspu_vobsub_execute_event (GstDVDSpu * dvdspu)
+{
+ guint8 *start, *cmd_blk, *end;
+ guint16 next_blk;
+ SpuState *state = &dvdspu->spu_state;
+
+ if (state->vobsub.buf == NULL)
+ return FALSE;
+
+ GST_DEBUG_OBJECT (dvdspu, "Executing cmd blk with TS %" GST_TIME_FORMAT
+ " @ offset %u", GST_TIME_ARGS (state->next_ts),
+ state->vobsub.cur_cmd_blk);
+
+ start = GST_BUFFER_DATA (state->vobsub.buf);
+ end = start + GST_BUFFER_SIZE (state->vobsub.buf);
+
+ cmd_blk = start + state->vobsub.cur_cmd_blk;
+
+ if (G_UNLIKELY (cmd_blk + 5 >= end)) {
+ /* Invalid. Finish the buffer and loop again */
+ gst_dvd_spu_finish_spu_buf (dvdspu);
+ return FALSE;
+ }
+
+ gst_dvd_spu_exec_cmd_blk (dvdspu, cmd_blk + 4, end);
+
+ next_blk = GST_READ_UINT16_BE (cmd_blk + 2);
+ if (next_blk != state->vobsub.cur_cmd_blk) {
+ /* Advance to the next block of commands */
+ gst_dvd_spu_setup_cmd_blk (dvdspu, next_blk, start, end);
+ } else {
+ /* Next Block points to the current block, so we're finished with this
+ * SPU buffer */
+ gst_dvd_spu_finish_spu_buf (dvdspu);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gstspu_vobsub_handle_dvd_event (GstDVDSpu * dvdspu, GstEvent * event)
+{
+ const gchar *event_type;
+ const GstStructure *structure = gst_event_get_structure (event);
+ SpuState *state = &dvdspu->spu_state;
+ gboolean hl_change = FALSE;
+
+ event_type = gst_structure_get_string (structure, "event");
+
+ if (strcmp (event_type, "dvd-spu-clut-change") == 0) {
+ gchar prop_name[32];
+ gint i;
+ gint entry;
+
+ for (i = 0; i < 16; i++) {
+ g_snprintf (prop_name, 32, "clut%02d", i);
+ if (!gst_structure_get_int (structure, prop_name, &entry))
+ entry = 0;
+ state->vobsub.current_clut[i] = (guint32) entry;
+ }
+
+ state->vobsub.main_pal_dirty = TRUE;
+ state->vobsub.hl_pal_dirty = TRUE;
+ state->vobsub.line_ctrl_i_pal_dirty = TRUE;
+ hl_change = TRUE;
+ } else if (strcmp (event_type, "dvd-spu-highlight") == 0) {
+ gint val;
+
+ if (gst_structure_get_int (structure, "palette", &val)) {
+ state->vobsub.hl_idx[3] = ((guint32) (val) >> 28) & 0x0f;
+ state->vobsub.hl_idx[2] = ((guint32) (val) >> 24) & 0x0f;
+ state->vobsub.hl_idx[1] = ((guint32) (val) >> 20) & 0x0f;
+ state->vobsub.hl_idx[0] = ((guint32) (val) >> 16) & 0x0f;
+
+ state->vobsub.hl_alpha[3] = ((guint32) (val) >> 12) & 0x0f;
+ state->vobsub.hl_alpha[2] = ((guint32) (val) >> 8) & 0x0f;
+ state->vobsub.hl_alpha[1] = ((guint32) (val) >> 4) & 0x0f;
+ state->vobsub.hl_alpha[0] = ((guint32) (val) >> 0) & 0x0f;
+
+ state->vobsub.hl_pal_dirty = TRUE;
+ }
+ if (gst_structure_get_int (structure, "sx", &val))
+ state->vobsub.hl_rect.left = (gint16) val;
+ if (gst_structure_get_int (structure, "sy", &val))
+ state->vobsub.hl_rect.top = (gint16) val;
+ if (gst_structure_get_int (structure, "ex", &val))
+ state->vobsub.hl_rect.right = (gint16) val;
+ if (gst_structure_get_int (structure, "ey", &val))
+ state->vobsub.hl_rect.bottom = (gint16) val;
+
+ GST_INFO_OBJECT (dvdspu, "Highlight rect is now (%d,%d) to (%d,%d)",
+ state->vobsub.hl_rect.left, state->vobsub.hl_rect.top,
+ state->vobsub.hl_rect.right, state->vobsub.hl_rect.bottom);
+ hl_change = TRUE;
+ } else if (strcmp (event_type, "dvd-spu-reset-highlight") == 0) {
+ if (state->vobsub.hl_rect.top != -1 || state->vobsub.hl_rect.bottom != -1)
+ hl_change = TRUE;
+ state->vobsub.hl_rect.top = -1;
+ state->vobsub.hl_rect.bottom = -1;
+ GST_INFO_OBJECT (dvdspu, "Highlight off");
+ } else if (strcmp (event_type, "dvd-set-subpicture-track") == 0) {
+ gboolean forced_only;
+
+ if (gst_structure_get_boolean (structure, "forced-only", &forced_only)) {
+ gboolean was_forced = (state->flags & SPU_STATE_FORCED_ONLY);
+
+ if (forced_only)
+ state->flags |= SPU_STATE_FORCED_ONLY;
+ else
+ state->flags &= ~(SPU_STATE_FORCED_ONLY);
+
+ if (was_forced != forced_only)
+ hl_change = TRUE;
+ }
+ }
+
+ gst_event_unref (event);
+
+ return hl_change;
+}
+
+void
+gstspu_vobsub_flush (GstDVDSpu * dvdspu)
+{
+ SpuState *state = &dvdspu->spu_state;
+
+ if (state->vobsub.buf) {
+ gst_buffer_unref (state->vobsub.buf);
+ state->vobsub.buf = NULL;
+ }
+ if (state->vobsub.pix_buf) {
+ gst_buffer_unref (state->vobsub.pix_buf);
+ state->vobsub.pix_buf = NULL;
+ }
+
+ state->vobsub.base_ts = GST_CLOCK_TIME_NONE;
+ state->vobsub.pix_data[0] = 0;
+ state->vobsub.pix_data[1] = 0;
+
+ state->vobsub.hl_rect.top = -1;
+ state->vobsub.hl_rect.bottom = -1;
+
+ state->vobsub.disp_rect.top = -1;
+ state->vobsub.disp_rect.bottom = -1;
+
+ state->vobsub.n_line_ctrl_i = 0;
+ if (state->vobsub.line_ctrl_i != NULL) {
+ g_free (state->vobsub.line_ctrl_i);
+ state->vobsub.line_ctrl_i = NULL;
+ }
+}
diff --git a/gst/dvdspu/gstspu-vobsub.h b/gst/dvdspu/gstspu-vobsub.h
new file mode 100644
index 00000000..9b4196bc
--- /dev/null
+++ b/gst/dvdspu/gstspu-vobsub.h
@@ -0,0 +1,110 @@
+/* GStreamer Sub-Picture Unit - VobSub/DVD handling
+ * Copyright (C) 2009 Jan Schmidt <thaytan@noraisin.net>
+ *
+ * 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 __GSTSPU_VOBSUB_H__
+#define __GSTSPU_VOBSUB_H__
+
+#include "gstspu-common.h"
+
+typedef struct SpuVobsubState SpuVobsubState;
+typedef struct SpuVobsubPixCtrlI SpuVobsubPixCtrlI;
+typedef struct SpuVobsubLineCtrlI SpuVobsubLineCtrlI;
+
+/* Pixel Control Info from a Change Color Contrast command */
+struct SpuVobsubPixCtrlI {
+ gint16 left;
+ guint32 palette;
+
+ /* Pre-multiplied palette values, updated as
+ * needed */
+ SpuColour pal_cache[4];
+};
+
+struct SpuVobsubLineCtrlI {
+ guint8 n_changes; /* 1 to 8 */
+ SpuVobsubPixCtrlI pix_ctrl_i[8];
+
+ gint16 top;
+ gint16 bottom;
+};
+
+struct SpuVobsubState {
+ GstClockTime base_ts; /* base TS for cmd blk delays in running time */
+ GstBuffer *buf; /* Current SPU packet we're executing commands from */
+ guint16 cur_cmd_blk; /* Offset into the buf for the current cmd block */
+
+ /* Top + Bottom field offsets in the buffer. 0 = not set */
+ guint16 pix_data[2];
+ GstBuffer *pix_buf; /* Current SPU packet the pix_data references */
+
+ SpuRect disp_rect;
+ SpuRect clip_rect;
+ SpuRect hl_rect;
+
+ guint32 current_clut[16]; /* Colour lookup table from incoming events */
+
+ guint8 main_idx[4]; /* Indices for current main palette */
+ guint8 main_alpha[4]; /* Alpha values for main palette */
+
+ guint8 hl_idx[4]; /* Indices for current highlight palette */
+ guint8 hl_alpha[4]; /* Alpha values for highlight palette */
+
+ /* Pre-multiplied colour palette for the main palette */
+ SpuColour main_pal[4];
+ gboolean main_pal_dirty;
+
+ /* Line control info for rendering the highlight palette */
+ SpuVobsubLineCtrlI hl_ctrl_i;
+ gboolean hl_pal_dirty; /* Indicates that the HL palette info needs refreshing */
+
+ /* LineCtrlI Info from a Change Color & Contrast command */
+ SpuVobsubLineCtrlI *line_ctrl_i;
+ gint16 n_line_ctrl_i;
+ gboolean line_ctrl_i_pal_dirty; /* Indicates that the palettes for the line_ctrl_i
+ * need recalculating */
+
+ /* Rendering state vars below */
+ gint16 comp_last_x[2]; /* Maximum X values we rendered into the comp buffer (odd & even) */
+ gint16 *comp_last_x_ptr; /* Ptr to the current comp_last_x value to be updated by the render */
+
+ /* Current Y Position */
+ gint16 cur_Y;
+
+ /* Current offset in nibbles into the pix_data */
+ guint16 cur_offsets[2];
+ guint16 max_offset;
+
+ /* current ChgColCon Line Info */
+ SpuVobsubLineCtrlI *cur_chg_col;
+ SpuVobsubLineCtrlI *cur_chg_col_end;
+
+ /* Output position tracking */
+ guint8 *out_Y;
+ guint32 *out_U;
+ guint32 *out_V;
+ guint32 *out_A;
+};
+
+void gstspu_vobsub_handle_new_buf (GstDVDSpu * dvdspu, GstClockTime event_ts, GstBuffer *buf);
+gboolean gstspu_vobsub_execute_event (GstDVDSpu *dvdspu);
+void gstspu_vobsub_render (GstDVDSpu *dvdspu, GstBuffer *buf);
+gboolean gstspu_vobsub_handle_dvd_event (GstDVDSpu *dvdspu, GstEvent *event);
+void gstspu_vobsub_flush (GstDVDSpu *dvdspu);
+
+#endif
diff --git a/gst/flv/Makefile.am b/gst/flv/Makefile.am
deleted file mode 100644
index 6e1a58b2..00000000
--- a/gst/flv/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-plugin_LTLIBRARIES = libgstflv.la
-
-libgstflv_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
-libgstflv_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
-libgstflv_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS}
-libgstflv_la_SOURCES = gstflvdemux.c gstflvparse.c gstflvmux.c
-libgstflv_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = gstflvdemux.h gstflvparse.h gstflvmux.h
diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c
deleted file mode 100644
index f31a22e8..00000000
--- a/gst/flv/gstflvdemux.c
+++ /dev/null
@@ -1,1323 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
- *
- * 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-flvdemux
- *
- * flvdemux demuxes an FLV file into the different contained streams.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
- * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstflvdemux.h"
-#include "gstflvparse.h"
-#include "gstflvmux.h"
-
-#include <string.h>
-
-static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-flv")
- );
-
-static GstStaticPadTemplate audio_src_template =
-GST_STATIC_PAD_TEMPLATE ("audio",
- GST_PAD_SRC,
- GST_PAD_SOMETIMES,
- GST_STATIC_CAPS_ANY);
-
-static GstStaticPadTemplate video_src_template =
-GST_STATIC_PAD_TEMPLATE ("video",
- GST_PAD_SRC,
- GST_PAD_SOMETIMES,
- GST_STATIC_CAPS_ANY);
-
-GST_DEBUG_CATEGORY (flvdemux_debug);
-#define GST_CAT_DEFAULT flvdemux_debug
-
-GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
-
-/* 9 bytes of header + 4 bytes of first previous tag size */
-#define FLV_HEADER_SIZE 13
-/* 1 byte of tag type + 3 bytes of tag data size */
-#define FLV_TAG_TYPE_SIZE 4
-
-static void
-gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
-{
- GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
-
- gst_adapter_clear (demux->adapter);
-
- demux->audio_need_discont = TRUE;
- demux->video_need_discont = TRUE;
-
- demux->flushing = FALSE;
-
- /* Only in push mode */
- if (!demux->random_access) {
- /* After a flush we expect a tag_type */
- demux->state = FLV_STATE_TAG_TYPE;
- /* We reset the offset and will get one from first push */
- demux->offset = 0;
- }
-}
-
-static void
-gst_flv_demux_cleanup (GstFLVDemux * demux)
-{
- GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
-
- demux->state = FLV_STATE_HEADER;
-
- demux->flushing = FALSE;
- demux->need_header = TRUE;
- demux->audio_need_segment = TRUE;
- demux->video_need_segment = TRUE;
- demux->audio_need_discont = TRUE;
- demux->video_need_discont = TRUE;
-
- /* By default we consider them as linked */
- demux->audio_linked = TRUE;
- demux->video_linked = TRUE;
-
- demux->has_audio = FALSE;
- demux->has_video = FALSE;
- demux->push_tags = FALSE;
- demux->got_par = FALSE;
-
- gst_segment_init (&demux->segment, GST_FORMAT_TIME);
-
- demux->w = demux->h = 0;
- demux->par_x = demux->par_y = 1;
- demux->video_offset = 0;
- demux->audio_offset = 0;
- demux->offset = demux->cur_tag_offset = 0;
- demux->tag_size = demux->tag_data_size = 0;
- demux->duration = GST_CLOCK_TIME_NONE;
-
- if (demux->new_seg_event) {
- gst_event_unref (demux->new_seg_event);
- demux->new_seg_event = NULL;
- }
-
- if (demux->close_seg_event) {
- gst_event_unref (demux->close_seg_event);
- demux->close_seg_event = NULL;
- }
-
- gst_adapter_clear (demux->adapter);
-
- if (demux->audio_codec_data) {
- gst_buffer_unref (demux->audio_codec_data);
- demux->audio_codec_data = NULL;
- }
-
- if (demux->video_codec_data) {
- gst_buffer_unref (demux->video_codec_data);
- demux->video_codec_data = NULL;
- }
-
- if (demux->audio_pad) {
- gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
- gst_object_unref (demux->audio_pad);
- demux->audio_pad = NULL;
- }
-
- if (demux->video_pad) {
- gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
- gst_object_unref (demux->video_pad);
- demux->video_pad = NULL;
- }
-
- if (demux->times) {
- g_array_free (demux->times, TRUE);
- demux->times = NULL;
- }
-
- if (demux->filepositions) {
- g_array_free (demux->filepositions, TRUE);
- demux->filepositions = NULL;
- }
-}
-
-static GstFlowReturn
-gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstFLVDemux *demux = NULL;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
- G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
-
- if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
- GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
- demux->state = FLV_STATE_HEADER;
- demux->offset = 0;
- }
-
- if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
- GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
- demux->offset = GST_BUFFER_OFFSET (buffer);
- }
-
- gst_adapter_push (demux->adapter, buffer);
-
-parse:
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
- || demux->video_linked)) {
- ret = GST_FLOW_OK;
- } else {
- GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
- goto beach;
- }
- }
-
- if (G_UNLIKELY (demux->flushing)) {
- GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
- ret = GST_FLOW_WRONG_STATE;
- goto beach;
- }
-
- switch (demux->state) {
- case FLV_STATE_HEADER:
- {
- if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
- GstBuffer *buffer;
-
- buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
-
- ret = gst_flv_parse_header (demux, buffer);
-
- gst_buffer_unref (buffer);
- demux->offset += FLV_HEADER_SIZE;
-
- demux->state = FLV_STATE_TAG_TYPE;
- goto parse;
- } else {
- goto beach;
- }
- }
- case FLV_STATE_TAG_TYPE:
- {
- if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
- GstBuffer *buffer;
-
- /* Remember the tag offset in bytes */
- demux->cur_tag_offset = demux->offset;
-
- buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
-
- ret = gst_flv_parse_tag_type (demux, buffer);
-
- gst_buffer_unref (buffer);
- demux->offset += FLV_TAG_TYPE_SIZE;
-
- goto parse;
- } else {
- goto beach;
- }
- }
- case FLV_STATE_TAG_VIDEO:
- {
- if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
- GstBuffer *buffer;
-
- buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
-
- ret = gst_flv_parse_tag_video (demux, buffer);
-
- gst_buffer_unref (buffer);
- demux->offset += demux->tag_size;
-
- demux->state = FLV_STATE_TAG_TYPE;
- goto parse;
- } else {
- goto beach;
- }
- }
- case FLV_STATE_TAG_AUDIO:
- {
- if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
- GstBuffer *buffer;
-
- buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
-
- ret = gst_flv_parse_tag_audio (demux, buffer);
-
- gst_buffer_unref (buffer);
- demux->offset += demux->tag_size;
-
- demux->state = FLV_STATE_TAG_TYPE;
- goto parse;
- } else {
- goto beach;
- }
- }
- case FLV_STATE_TAG_SCRIPT:
- {
- if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
- GstBuffer *buffer;
-
- buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
-
- ret = gst_flv_parse_tag_script (demux, buffer);
-
- gst_buffer_unref (buffer);
- demux->offset += demux->tag_size;
-
- demux->state = FLV_STATE_TAG_TYPE;
- goto parse;
- } else {
- goto beach;
- }
- }
- default:
- GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
- }
-
-beach:
- if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
- /* If either audio or video is linked we return GST_FLOW_OK */
- if (demux->audio_linked || demux->video_linked) {
- ret = GST_FLOW_OK;
- }
- }
-
- gst_object_unref (demux);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_demux_pull_range (GstFLVDemux * demux, GstPad * pad, guint64 offset,
- guint size, GstBuffer ** buffer)
-{
- GstFlowReturn ret;
-
- ret = gst_pad_pull_range (pad, offset, size, buffer);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- GST_WARNING_OBJECT (demux,
- "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
- size, offset, gst_flow_get_name (ret));
- *buffer = NULL;
- return ret;
- }
-
- if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
- GST_WARNING_OBJECT (demux,
- "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (*buffer), size, offset);
- gst_buffer_unref (*buffer);
- ret = GST_FLOW_UNEXPECTED;
- *buffer = NULL;
- return ret;
- }
-
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux)
-{
- GstBuffer *buffer = NULL;
- GstFlowReturn ret = GST_FLOW_OK;
-
- /* Store tag offset */
- demux->cur_tag_offset = demux->offset;
-
- /* Get the first 4 bytes to identify tag type and size */
- if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
- FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
- goto beach;
-
- /* Identify tag type */
- ret = gst_flv_parse_tag_type (demux, buffer);
-
- gst_buffer_unref (buffer);
-
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto beach;
-
- /* Jump over tag type + size */
- demux->offset += FLV_TAG_TYPE_SIZE;
-
- /* Pull the whole tag */
- if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
- demux->tag_size, &buffer)) != GST_FLOW_OK))
- goto beach;
-
- switch (demux->state) {
- case FLV_STATE_TAG_VIDEO:
- ret = gst_flv_parse_tag_video (demux, buffer);
- break;
- case FLV_STATE_TAG_AUDIO:
- ret = gst_flv_parse_tag_audio (demux, buffer);
- break;
- case FLV_STATE_TAG_SCRIPT:
- ret = gst_flv_parse_tag_script (demux, buffer);
- break;
- default:
- GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
- }
-
- gst_buffer_unref (buffer);
-
- /* Jump over that part we've just parsed */
- demux->offset += demux->tag_size;
-
- /* Make sure we reinitialize the tag size */
- demux->tag_size = 0;
-
- /* Ready for the next tag */
- demux->state = FLV_STATE_TAG_TYPE;
-
- if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
- /* If either audio or video is linked we return GST_FLOW_OK */
- if (demux->audio_linked || demux->video_linked) {
- ret = GST_FLOW_OK;
- } else {
- GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
- "neither video nor audio are linked");
- }
- }
-
-beach:
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_demux_pull_header (GstPad * pad, GstFLVDemux * demux)
-{
- GstBuffer *buffer = NULL;
- GstFlowReturn ret = GST_FLOW_OK;
-
- /* Get the first 9 bytes */
- if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
- FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
- goto beach;
-
- ret = gst_flv_parse_header (demux, buffer);
-
- gst_buffer_unref (buffer);
-
- /* Jump over the header now */
- demux->offset += FLV_HEADER_SIZE;
- demux->state = FLV_STATE_TAG_TYPE;
-
-beach:
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_demux_seek_to_prev_keyframe (GstFLVDemux * demux)
-{
- return GST_FLOW_OK;
-}
-
-static gboolean
-gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
-{
- gboolean ret = TRUE;
-
- if (demux->audio_pad)
- ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
-
- if (demux->video_pad)
- ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
-
- gst_event_unref (event);
-
- return ret;
-}
-
-static void
-gst_flv_demux_create_index (GstFLVDemux * demux)
-{
- gint64 size;
- GstFormat fmt = GST_FORMAT_BYTES;
- size_t tag_size;
- guint64 old_offset;
- GstBuffer *buffer;
- GstFlowReturn ret;
-
- if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
- fmt != GST_FORMAT_BYTES)
- return;
-
- old_offset = demux->offset;
-
- while ((ret =
- gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12,
- &buffer)) == GST_FLOW_OK) {
- if (gst_flv_parse_tag_timestamp (demux, buffer,
- &tag_size) == GST_CLOCK_TIME_NONE) {
- gst_buffer_unref (buffer);
- break;
- }
-
- gst_buffer_unref (buffer);
- demux->offset += tag_size;
- }
-
- demux->offset = old_offset;
-}
-
-static void
-gst_flv_demux_loop (GstPad * pad)
-{
- GstFLVDemux *demux = NULL;
- GstFlowReturn ret = GST_FLOW_OK;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
-
- if (demux->segment.rate >= 0) {
- /* pull in data */
- switch (demux->state) {
- case FLV_STATE_TAG_TYPE:
- ret = gst_flv_demux_pull_tag (pad, demux);
- break;
- case FLV_STATE_DONE:
- ret = GST_FLOW_UNEXPECTED;
- break;
- default:
- ret = gst_flv_demux_pull_header (pad, demux);
- if (ret == GST_FLOW_OK)
- gst_flv_demux_create_index (demux);
-
- }
-
- /* pause if something went wrong */
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto pause;
-
- /* check EOS condition */
- if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
- (demux->segment.stop != -1) &&
- (demux->segment.last_stop >= demux->segment.stop)) {
- ret = GST_FLOW_UNEXPECTED;
- goto pause;
- }
- } else { /* Reverse playback */
- /* pull in data */
- switch (demux->state) {
- case FLV_STATE_TAG_TYPE:
- ret = gst_flv_demux_pull_tag (pad, demux);
- /* When packet parsing returns UNEXPECTED that means we ve reached the
- point where we want to go to the previous keyframe. This is either
- the last FLV tag or the keyframe we used last time */
- if (ret == GST_FLOW_UNEXPECTED) {
- ret = gst_flv_demux_seek_to_prev_keyframe (demux);
- demux->state = FLV_STATE_TAG_TYPE;
- }
- break;
- default:
- ret = gst_flv_demux_pull_header (pad, demux);
- if (ret == GST_FLOW_OK)
- gst_flv_demux_create_index (demux);
- }
-
- /* pause if something went wrong */
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto pause;
-
- /* check EOS condition */
- if (demux->segment.last_stop <= demux->segment.start) {
- ret = GST_FLOW_UNEXPECTED;
- goto pause;
- }
- }
-
- gst_object_unref (demux);
-
- return;
-
-pause:
- {
- const gchar *reason = gst_flow_get_name (ret);
-
- GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
- gst_pad_pause_task (pad);
-
- if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
- if (ret == GST_FLOW_UNEXPECTED) {
- /* perform EOS logic */
- gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
- if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- gint64 stop;
-
- /* for segment playback we need to post when (in stream time)
- * we stopped, this is either stop (when set) or the duration. */
- if ((stop = demux->segment.stop) == -1)
- stop = demux->segment.duration;
-
- if (demux->segment.rate >= 0) {
- GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
- gst_element_post_message (GST_ELEMENT_CAST (demux),
- gst_message_new_segment_done (GST_OBJECT_CAST (demux),
- GST_FORMAT_TIME, stop));
- } else { /* Reverse playback */
- GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
- "segment");
- gst_element_post_message (GST_ELEMENT_CAST (demux),
- gst_message_new_segment_done (GST_OBJECT_CAST (demux),
- GST_FORMAT_TIME, demux->segment.start));
- }
- } else {
- /* normal playback, send EOS to all linked pads */
- gst_element_no_more_pads (GST_ELEMENT (demux));
- GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
- if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
- GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
- }
- } else {
- GST_ELEMENT_ERROR (demux, STREAM, FAILED,
- ("Internal data stream error."),
- ("stream stopped, reason %s", reason));
- gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
- }
- }
- gst_object_unref (demux);
- return;
- }
-}
-
-static guint64
-gst_flv_demux_find_offset (GstFLVDemux * demux, GstSegment * segment)
-{
- gint64 bytes = 0;
- gint64 time = 0;
- GstIndexEntry *entry;
-
- g_return_val_if_fail (segment != NULL, 0);
-
- time = segment->start;
-
- if (demux->index) {
- /* Let's check if we have an index entry for that seek time */
- entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
- GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
- GST_FORMAT_TIME, time);
-
- if (entry) {
- gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
- gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
-
- GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
- " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
- GST_TIME_ARGS (segment->start), GST_TIME_ARGS (time), bytes);
-
- /* Key frame seeking */
- if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
- /* Adjust the segment so that the keyframe fits in */
- if (time < segment->start) {
- segment->start = segment->time = time;
- }
- segment->last_stop = time;
- }
- } else {
- GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
- GST_TIME_ARGS (segment->start));
- }
- }
-
- return bytes;
-}
-
-static gboolean
-gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
-{
- GstFormat format;
- GstSeekFlags flags;
- GstSeekType start_type, stop_type;
- gint64 start, stop;
- gdouble rate;
- gboolean update, flush, keyframe, ret;
- GstSegment seeksegment;
-
- gst_event_parse_seek (event, &rate, &format, &flags,
- &start_type, &start, &stop_type, &stop);
-
- if (format != GST_FORMAT_TIME)
- goto wrong_format;
-
- flush = !!(flags & GST_SEEK_FLAG_FLUSH);
- keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
-
- /* Work on a copy until we are sure the seek succeeded. */
- memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
-
- GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
- &demux->segment);
-
- /* Apply the seek to our segment */
- gst_segment_set_seek (&seeksegment, rate, format, flags,
- start_type, start, stop_type, stop, &update);
-
- GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
- &seeksegment);
-
- if (flush || seeksegment.last_stop != demux->segment.last_stop) {
- /* Do the actual seeking */
- guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
-
- GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
- G_GUINT64_FORMAT, offset);
- ret = gst_pad_push_event (demux->sinkpad,
- gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
- seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
- offset, GST_SEEK_TYPE_NONE, 0));
- if (G_UNLIKELY (!ret)) {
- GST_WARNING_OBJECT (demux, "upstream seek failed");
- }
-
- /* Tell all the stream we moved to a different position (discont) */
- demux->audio_need_discont = TRUE;
- demux->video_need_discont = TRUE;
- } else {
- ret = TRUE;
- }
-
- if (ret) {
- /* Ok seek succeeded, take the newly configured segment */
- memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
-
- /* Tell all the stream a new segment is needed */
- demux->audio_need_segment = TRUE;
- demux->video_need_segment = TRUE;
- /* Clean any potential newsegment event kept for the streams. The first
- * stream needing a new segment will create a new one. */
- if (G_UNLIKELY (demux->new_seg_event)) {
- gst_event_unref (demux->new_seg_event);
- demux->new_seg_event = NULL;
- }
- gst_event_unref (event);
- } else {
- ret = gst_pad_push_event (demux->sinkpad, event);
- }
-
- return ret;
-
-/* ERRORS */
-wrong_format:
- {
- GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
- return gst_pad_push_event (demux->sinkpad, event);
- }
-}
-
-static gboolean
-gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event)
-{
- GstFormat format;
- GstSeekFlags flags;
- GstSeekType start_type, stop_type;
- gint64 start, stop;
- gdouble rate;
- gboolean update, flush, keyframe, ret;
- GstSegment seeksegment;
-
- gst_event_parse_seek (event, &rate, &format, &flags,
- &start_type, &start, &stop_type, &stop);
-
- gst_event_unref (event);
-
- if (format != GST_FORMAT_TIME)
- goto wrong_format;
-
- flush = !!(flags & GST_SEEK_FLAG_FLUSH);
- keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
-
- if (flush) {
- /* Flush start up and downstream to make sure data flow and loops are
- idle */
- gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
- gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
- } else {
- /* Pause the pulling task */
- gst_pad_pause_task (demux->sinkpad);
- }
-
- /* Take the stream lock */
- GST_PAD_STREAM_LOCK (demux->sinkpad);
-
- if (flush) {
- /* Stop flushing upstream we need to pull */
- gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
- }
-
- /* Work on a copy until we are sure the seek succeeded. */
- memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
-
- GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
- &demux->segment);
-
- /* Apply the seek to our segment */
- gst_segment_set_seek (&seeksegment, rate, format, flags,
- start_type, start, stop_type, stop, &update);
-
- GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
- &seeksegment);
-
- if (flush || seeksegment.last_stop != demux->segment.last_stop) {
- /* Do the actual seeking */
- demux->offset = gst_flv_demux_find_offset (demux, &seeksegment);
-
- /* Tell all the stream we moved to a different position (discont) */
- demux->audio_need_discont = TRUE;
- demux->video_need_discont = TRUE;
-
- /* If we seeked at the beginning of the file parse the header again */
- if (G_UNLIKELY (!demux->offset)) {
- demux->state = FLV_STATE_HEADER;
- } else { /* or parse a tag */
- demux->state = FLV_STATE_TAG_TYPE;
- }
- ret = TRUE;
- } else {
- ret = TRUE;
- }
-
- if (G_UNLIKELY (demux->close_seg_event)) {
- gst_event_unref (demux->close_seg_event);
- demux->close_seg_event = NULL;
- }
-
- if (flush) {
- /* Stop flushing, the sinks are at time 0 now */
- gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
- } else {
- GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
- &demux->segment);
-
- /* Close the current segment for a linear playback */
- if (demux->segment.rate >= 0) {
- /* for forward playback, we played from start to last_stop */
- demux->close_seg_event = gst_event_new_new_segment (TRUE,
- demux->segment.rate, demux->segment.format,
- demux->segment.start, demux->segment.last_stop, demux->segment.time);
- } else {
- gint64 stop;
-
- if ((stop = demux->segment.stop) == -1)
- stop = demux->segment.duration;
-
- /* for reverse playback, we played from stop to last_stop. */
- demux->close_seg_event = gst_event_new_new_segment (TRUE,
- demux->segment.rate, demux->segment.format,
- demux->segment.last_stop, stop, demux->segment.last_stop);
- }
- }
-
- if (ret) {
- /* Ok seek succeeded, take the newly configured segment */
- memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
-
- /* Notify about the start of a new segment */
- if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- gst_element_post_message (GST_ELEMENT (demux),
- gst_message_new_segment_start (GST_OBJECT (demux),
- demux->segment.format, demux->segment.last_stop));
- }
-
- /* Tell all the stream a new segment is needed */
- demux->audio_need_segment = TRUE;
- demux->video_need_segment = TRUE;
- /* Clean any potential newsegment event kept for the streams. The first
- * stream needing a new segment will create a new one. */
- if (G_UNLIKELY (demux->new_seg_event)) {
- gst_event_unref (demux->new_seg_event);
- demux->new_seg_event = NULL;
- }
- }
-
- gst_pad_start_task (demux->sinkpad,
- (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
-
- GST_PAD_STREAM_UNLOCK (demux->sinkpad);
-
- return ret;
-
- /* ERRORS */
-wrong_format:
- {
- GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
- return FALSE;
- }
-}
-
-/* If we can pull that's prefered */
-static gboolean
-gst_flv_demux_sink_activate (GstPad * sinkpad)
-{
- if (gst_pad_check_pull_range (sinkpad)) {
- return gst_pad_activate_pull (sinkpad, TRUE);
- } else {
- return gst_pad_activate_push (sinkpad, TRUE);
- }
-}
-
-/* This function gets called when we activate ourselves in push mode.
- * We cannot seek (ourselves) in the stream */
-static gboolean
-gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
-{
- GstFLVDemux *demux;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
-
- demux->random_access = FALSE;
-
- gst_object_unref (demux);
-
- return TRUE;
-}
-
-/* this function gets called when we activate ourselves in pull mode.
- * We can perform random access to the resource and we start a task
- * to start reading */
-static gboolean
-gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
-{
- GstFLVDemux *demux;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
-
- if (active) {
- demux->random_access = TRUE;
- gst_object_unref (demux);
- return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
- sinkpad);
- } else {
- demux->random_access = FALSE;
- gst_object_unref (demux);
- return gst_pad_stop_task (sinkpad);
- }
-}
-
-static gboolean
-gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
-{
- GstFLVDemux *demux;
- gboolean ret = FALSE;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
- demux->flushing = TRUE;
- ret = gst_flv_demux_push_src_event (demux, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
- gst_flv_demux_flush (demux, TRUE);
- ret = gst_flv_demux_push_src_event (demux, event);
- break;
- case GST_EVENT_EOS:
- GST_DEBUG_OBJECT (demux, "received EOS");
- if (demux->index) {
- GST_DEBUG_OBJECT (demux, "committing index");
- gst_index_commit (demux->index, demux->index_id);
- }
- gst_element_no_more_pads (GST_ELEMENT (demux));
- if (!gst_flv_demux_push_src_event (demux, event))
- GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
- ret = TRUE;
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate;
- gint64 start, stop, time;
- gboolean update;
-
- GST_DEBUG_OBJECT (demux, "received new segment");
-
- gst_event_parse_new_segment (event, &update, &rate, &format, &start,
- &stop, &time);
-
- if (format == GST_FORMAT_TIME) {
- /* time segment, this is perfect, copy over the values. */
- gst_segment_set_newsegment (&demux->segment, update, rate, format,
- start, stop, time);
-
- GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
- &demux->segment);
-
- /* and forward */
- ret = gst_flv_demux_push_src_event (demux, event);
- } else {
- /* non-time format */
- demux->audio_need_segment = TRUE;
- demux->video_need_segment = TRUE;
- ret = TRUE;
- gst_event_unref (event);
- }
- break;
- }
- default:
- ret = gst_flv_demux_push_src_event (demux, event);
- break;
- }
-
- gst_object_unref (demux);
-
- return ret;
-}
-
-gboolean
-gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
-{
- GstFLVDemux *demux;
- gboolean ret = FALSE;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- if (demux->random_access) {
- ret = gst_flv_demux_handle_seek_pull (demux, event);
- } else {
- ret = gst_flv_demux_handle_seek_push (demux, event);
- }
- break;
- default:
- ret = gst_pad_push_event (demux->sinkpad, event);
- break;
- }
-
- gst_object_unref (demux);
-
- return ret;
-}
-
-gboolean
-gst_flv_demux_query (GstPad * pad, GstQuery * query)
-{
- gboolean res = TRUE;
- GstFLVDemux *demux;
-
- demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_DURATION:
- {
- GstFormat format;
-
- gst_query_parse_duration (query, &format, NULL);
-
- /* duration is time only */
- if (format != GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (demux, "duration query only supported for time "
- "format");
- res = FALSE;
- goto beach;
- }
-
- GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->duration));
-
- gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
-
- break;
- }
- case GST_QUERY_POSITION:
- {
- GstFormat format;
-
- gst_query_parse_position (query, &format, NULL);
-
- /* position is time only */
- if (format != GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (demux, "position query only supported for time "
- "format");
- res = FALSE;
- goto beach;
- }
-
- GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->segment.last_stop));
-
- gst_query_set_duration (query, GST_FORMAT_TIME, demux->segment.last_stop);
-
- break;
- }
-
- case GST_QUERY_LATENCY:
- default:
- {
- GstPad *peer;
-
- if ((peer = gst_pad_get_peer (demux->sinkpad))) {
- /* query latency on peer pad */
- res = gst_pad_query (peer, query);
- gst_object_unref (peer);
- } else {
- /* no peer, we don't know */
- res = FALSE;
- }
- break;
- }
- }
-
-beach:
- gst_object_unref (demux);
-
- return res;
-}
-
-static GstStateChangeReturn
-gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
-{
- GstFLVDemux *demux;
- GstStateChangeReturn ret;
-
- demux = GST_FLV_DEMUX (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- /* If this is our own index destroy it as the
- * old entries might be wrong for the new stream */
- if (demux->own_index) {
- gst_object_unref (demux->index);
- demux->index = NULL;
- demux->own_index = FALSE;
- }
-
- /* If no index was created, generate one */
- if (G_UNLIKELY (!demux->index)) {
- GST_DEBUG_OBJECT (demux, "no index provided creating our own");
-
- demux->index = gst_index_factory_make ("memindex");
-
- gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
- &demux->index_id);
- demux->own_index = TRUE;
- }
- gst_flv_demux_cleanup (demux);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_flv_demux_cleanup (demux);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void
-gst_flv_demux_set_index (GstElement * element, GstIndex * index)
-{
- GstFLVDemux *demux = GST_FLV_DEMUX (element);
-
- GST_OBJECT_LOCK (demux);
- if (demux->index)
- gst_object_unref (demux->index);
- demux->index = gst_object_ref (index);
- GST_OBJECT_UNLOCK (demux);
-
- gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
- demux->own_index = FALSE;
-}
-
-static GstIndex *
-gst_flv_demux_get_index (GstElement * element)
-{
- GstIndex *result = NULL;
-
- GstFLVDemux *demux = GST_FLV_DEMUX (element);
-
- GST_OBJECT_LOCK (demux);
- if (demux->index)
- result = gst_object_ref (demux->index);
- GST_OBJECT_UNLOCK (demux);
-
- return result;
-}
-
-static void
-gst_flv_demux_dispose (GObject * object)
-{
- GstFLVDemux *demux = GST_FLV_DEMUX (object);
-
- GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
-
- if (demux->adapter) {
- gst_adapter_clear (demux->adapter);
- g_object_unref (demux->adapter);
- demux->adapter = NULL;
- }
-
- if (demux->taglist) {
- gst_tag_list_free (demux->taglist);
- demux->taglist = NULL;
- }
-
- if (demux->new_seg_event) {
- gst_event_unref (demux->new_seg_event);
- demux->new_seg_event = NULL;
- }
-
- if (demux->close_seg_event) {
- gst_event_unref (demux->close_seg_event);
- demux->close_seg_event = NULL;
- }
-
- if (demux->audio_codec_data) {
- gst_buffer_unref (demux->audio_codec_data);
- demux->audio_codec_data = NULL;
- }
-
- if (demux->video_codec_data) {
- gst_buffer_unref (demux->video_codec_data);
- demux->video_codec_data = NULL;
- }
-
- if (demux->audio_pad) {
- gst_object_unref (demux->audio_pad);
- demux->audio_pad = NULL;
- }
-
- if (demux->video_pad) {
- gst_object_unref (demux->video_pad);
- demux->video_pad = NULL;
- }
-
- if (demux->index) {
- gst_object_unref (demux->index);
- demux->index = NULL;
- }
-
- if (demux->times) {
- g_array_free (demux->times, TRUE);
- demux->times = NULL;
- }
-
- if (demux->filepositions) {
- g_array_free (demux->filepositions, TRUE);
- demux->filepositions = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
-}
-
-static void
-gst_flv_demux_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 (&flv_sink_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&audio_src_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&video_src_template));
- gst_element_class_set_details_simple (element_class, "FLV Demuxer",
- "Codec/Demuxer",
- "Demux FLV feeds into digital streams",
- "Julien Moutte <julien@moutte.net>");
-}
-
-static void
-gst_flv_demux_class_init (GstFLVDemuxClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_flv_demux_dispose);
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
- gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
- gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
-}
-
-static void
-gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class)
-{
- demux->sinkpad =
- gst_pad_new_from_static_template (&flv_sink_template, "sink");
-
- gst_pad_set_event_function (demux->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
- gst_pad_set_chain_function (demux->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
- gst_pad_set_activate_function (demux->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
- gst_pad_set_activatepull_function (demux->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
- gst_pad_set_activatepush_function (demux->sinkpad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
-
- gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
-
- demux->adapter = gst_adapter_new ();
- demux->taglist = gst_tag_list_new ();
- gst_segment_init (&demux->segment, GST_FORMAT_TIME);
-
- demux->own_index = FALSE;
-
- gst_flv_demux_cleanup (demux);
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
-
- if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
- gst_flv_demux_get_type ()) ||
- !gst_element_register (plugin, "flvmux", GST_RANK_NONE,
- gst_flv_mux_get_type ()))
- return FALSE;
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
- "flv", "FLV muxing and demuxing plugin",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h
deleted file mode 100644
index 72c0bcd4..00000000
--- a/gst/flv/gstflvdemux.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
- *
- * 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 __FLV_DEMUX_H__
-#define __FLV_DEMUX_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
-
-G_BEGIN_DECLS
-#define GST_TYPE_FLV_DEMUX \
- (gst_flv_demux_get_type())
-#define GST_FLV_DEMUX(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLV_DEMUX,GstFLVDemux))
-#define GST_FLV_DEMUX_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLV_DEMUX,GstFLVDemuxClass))
-#define GST_IS_FLV_DEMUX(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLV_DEMUX))
-#define GST_IS_FLV_DEMUX_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLV_DEMUX))
-typedef struct _GstFLVDemux GstFLVDemux;
-typedef struct _GstFLVDemuxClass GstFLVDemuxClass;
-
-typedef enum
-{
- FLV_STATE_HEADER,
- FLV_STATE_TAG_TYPE,
- FLV_STATE_TAG_VIDEO,
- FLV_STATE_TAG_AUDIO,
- FLV_STATE_TAG_SCRIPT,
- FLV_STATE_DONE,
- FLV_STATE_NONE
-} GstFLVDemuxState;
-
-struct _GstFLVDemux
-{
- GstElement element;
-
- GstPad *sinkpad;
-
- GstPad *audio_pad;
- GstPad *video_pad;
-
- /* <private> */
-
- GstIndex *index;
- gint index_id;
- gboolean own_index;
-
- GArray * times;
- GArray * filepositions;
-
- GstAdapter *adapter;
-
- GstSegment segment;
-
- GstEvent *close_seg_event;
- GstEvent *new_seg_event;
-
- GstTagList *taglist;
-
- GstFLVDemuxState state;
-
- guint64 offset;
- guint64 cur_tag_offset;
- GstClockTime duration;
- guint64 tag_size;
- guint64 tag_data_size;
-
- /* Audio infos */
- guint16 rate;
- guint16 channels;
- guint16 width;
- guint16 audio_codec_tag;
- guint64 audio_offset;
- gboolean audio_need_discont;
- gboolean audio_need_segment;
- gboolean audio_linked;
- GstBuffer * audio_codec_data;
-
- /* Video infos */
- guint32 w;
- guint32 h;
- guint32 par_x;
- guint32 par_y;
- guint16 video_codec_tag;
- guint64 video_offset;
- gboolean video_need_discont;
- gboolean video_need_segment;
- gboolean video_linked;
- gboolean got_par;
- GstBuffer * video_codec_data;
-
- gboolean random_access;
- gboolean need_header;
- gboolean has_audio;
- gboolean has_video;
- gboolean push_tags;
- gboolean strict;
- gboolean flushing;
-};
-
-struct _GstFLVDemuxClass
-{
- GstElementClass parent_class;
-};
-
-GType gst_flv_demux_get_type (void);
-
-gboolean gst_flv_demux_query (GstPad * pad, GstQuery * query);
-gboolean gst_flv_demux_src_event (GstPad * pad, GstEvent * event);
-
-G_END_DECLS
-#endif /* __FLV_DEMUX_H__ */
diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c
deleted file mode 100644
index dd27276a..00000000
--- a/gst/flv/gstflvmux.c
+++ /dev/null
@@ -1,1040 +0,0 @@
-/* GStreamer
- *
- * Copyright (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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-flvmux
- *
- * flvmux muxes different streams into an FLV file.
- *
- * <refsect2>
- * <title>Example launch line</title>
- * |[
- * gst-launch -v filesrc location=/path/to/audio ! decodebin2 ! queue ! flvmux name=m ! filesink location=file.flv filesrc location=/path/to/video ! decodebin2 ! queue ! m.
- * ]| This pipeline muxes an audio and video file into a single FLV file.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <math.h>
-#include <string.h>
-
-#include "gstflvmux.h"
-
-GST_DEBUG_CATEGORY_STATIC (flvmux_debug);
-#define GST_CAT_DEFAULT flvmux_debug
-
-static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-flv")
- );
-
-static GstStaticPadTemplate videosink_templ = GST_STATIC_PAD_TEMPLATE ("video",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS ("video/x-flash-video; "
- "video/x-flash-screen; "
- "video/x-vp6-flash; " "video/x-vp6-alpha; " "video/x-h264;")
- );
-
-static GstStaticPadTemplate audiosink_templ = GST_STATIC_PAD_TEMPLATE ("audio",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS
- ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
- "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
- "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; "
- "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
- "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 8, depth = (int) 8, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) FALSE; "
- "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 16, depth = (int) 16, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) TRUE; "
- "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
- "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
- "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
- );
-
-#define _do_init(type) \
- G_STMT_START{ \
- static const GInterfaceInfo tag_setter_info = { \
- NULL, \
- NULL, \
- NULL \
- }; \
- g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
- &tag_setter_info); \
- }G_STMT_END
-
-GST_BOILERPLATE_FULL (GstFlvMux, gst_flv_mux, GstElement, GST_TYPE_ELEMENT,
- _do_init);
-
-static void gst_flv_mux_finalize (GObject * object);
-static GstFlowReturn
-gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data);
-
-static gboolean gst_flv_mux_handle_src_event (GstPad * pad, GstEvent * event);
-static GstPad *gst_flv_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
-static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad);
-
-static GstStateChangeReturn
-gst_flv_mux_change_state (GstElement * element, GstStateChange transition);
-
-static void gst_flv_mux_reset (GstElement * element);
-
-static void
-gst_flv_mux_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 (&videosink_templ));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&audiosink_templ));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class, "FLV muxer",
- "Codec/Muxer",
- "Muxes video/audio streams into a FLV stream",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-
- GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
-}
-
-static void
-gst_flv_mux_class_init (GstFlvMuxClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- GST_DEBUG_CATEGORY_INIT (flvmux_debug, "flvmux", 0, "FLV muxer");
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- gobject_class->finalize = gst_flv_mux_finalize;
-
- gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_flv_mux_change_state);
- gstelement_class->request_new_pad =
- GST_DEBUG_FUNCPTR (gst_flv_mux_request_new_pad);
- gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_flv_mux_release_pad);
-}
-
-static void
-gst_flv_mux_init (GstFlvMux * mux, GstFlvMuxClass * g_class)
-{
- mux->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
- gst_pad_set_event_function (mux->srcpad, gst_flv_mux_handle_src_event);
- gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
-
- mux->collect = gst_collect_pads_new ();
- gst_collect_pads_set_function (mux->collect,
- (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_flv_mux_collected), mux);
-
- gst_flv_mux_reset (GST_ELEMENT (mux));
-}
-
-static void
-gst_flv_mux_finalize (GObject * object)
-{
- GstFlvMux *mux = GST_FLV_MUX (object);
-
- gst_object_unref (mux->collect);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_flv_mux_reset (GstElement * element)
-{
- GstFlvMux *mux = GST_FLV_MUX (element);
- GSList *sl;
-
- while ((sl = mux->collect->data) != NULL) {
- GstFlvPad *cpad = (GstFlvPad *) sl->data;
-
- if (cpad->audio_codec_data)
- gst_buffer_unref (cpad->audio_codec_data);
- if (cpad->video_codec_data)
- gst_buffer_unref (cpad->video_codec_data);
-
- gst_collect_pads_remove_pad (mux->collect, cpad->collect.pad);
- }
-
- if (mux->tags)
- gst_tag_list_free (mux->tags);
- mux->tags = NULL;
-
- mux->state = GST_FLV_MUX_STATE_HEADER;
-}
-
-static gboolean
-gst_flv_mux_handle_src_event (GstPad * pad, GstEvent * event)
-{
- GstEventType type;
-
- type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
-
- switch (type) {
- case GST_EVENT_SEEK:
- /* disable seeking for now */
- return FALSE;
- default:
- break;
- }
-
- return gst_pad_event_default (pad, event);
-}
-
-static gboolean
-gst_flv_mux_handle_sink_event (GstPad * pad, GstEvent * event)
-{
- GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
- gboolean ret = TRUE;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_TAG:{
- GstTagList *tags;
-
- if (!mux->tags)
- mux->tags = gst_tag_list_new ();
-
- gst_event_parse_tag (event, &tags);
- if (tags) {
- gst_tag_list_insert (mux->tags, tags,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
- }
-
- break;
- }
- case GST_EVENT_NEWSEGMENT:
- /* We don't support NEWSEGMENT events */
- ret = FALSE;
- gst_event_unref (event);
- break;
- default:
- break;
- }
-
- /* now GstCollectPads can take care of the rest, e.g. EOS */
- if (ret)
- ret = mux->collect_event (pad, event);
- gst_object_unref (mux);
-
- return ret;
-}
-
-static gboolean
-gst_flv_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
- GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad);
- gboolean ret = TRUE;
- GstStructure *s;
-
- s = gst_caps_get_structure (caps, 0);
-
- if (strcmp (gst_structure_get_name (s), "video/x-flash-video") == 0) {
- cpad->video_codec = 2;
- } else if (strcmp (gst_structure_get_name (s), "video/x-flash-screen") == 0) {
- cpad->video_codec = 3;
- } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-flash") == 0) {
- cpad->video_codec = 4;
- } else if (strcmp (gst_structure_get_name (s), "video/x-vp6-alpha") == 0) {
- cpad->video_codec = 5;
- } else if (strcmp (gst_structure_get_name (s), "video/x-h264") == 0) {
- cpad->video_codec = 7;
- } else {
- ret = FALSE;
- }
-
- if (ret && gst_structure_has_field (s, "codec_data")) {
- const GValue *val = gst_structure_get_value (s, "codec_data");
-
- if (val) {
- cpad->video_codec_data = gst_buffer_ref (gst_value_get_buffer (val));
- cpad->sent_codec_data = FALSE;
- } else {
- cpad->sent_codec_data = TRUE;
- }
- } else {
- cpad->sent_codec_data = TRUE;
- }
-
- gst_object_unref (mux);
-
- return ret;
-}
-
-static gboolean
-gst_flv_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
- GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad);
- gboolean ret = TRUE;
- GstStructure *s;
-
- s = gst_caps_get_structure (caps, 0);
-
- if (strcmp (gst_structure_get_name (s), "audio/x-adpcm") == 0) {
- const gchar *layout = gst_structure_get_string (s, "layout");
- if (layout && strcmp (layout, "swf") == 0) {
- cpad->audio_codec = 1;
- } else {
- ret = FALSE;
- }
- } else if (strcmp (gst_structure_get_name (s), "audio/mpeg") == 0) {
- gint mpegversion;
-
- if (gst_structure_get_int (s, "mpegversion", &mpegversion)) {
- if (mpegversion == 1) {
- gint layer;
-
- if (gst_structure_get_int (s, "layer", &layer) && layer == 3) {
- gint rate;
-
- if (gst_structure_get_int (s, "rate", &rate) && rate == 8000)
- cpad->audio_codec = 14;
- else
- cpad->audio_codec = 2;
- } else {
- ret = FALSE;
- }
- } else if (mpegversion == 4) {
- cpad->audio_codec = 10;
- } else {
- ret = FALSE;
- }
- } else {
- ret = FALSE;
- }
- } else if (strcmp (gst_structure_get_name (s), "audio/x-nellymoser") == 0) {
- gint rate, channels;
-
- if (gst_structure_get_int (s, "rate", &rate)
- && gst_structure_get_int (s, "channels", &channels)) {
- if (channels == 1 && rate == 16000)
- cpad->audio_codec = 4;
- else if (channels == 1 && rate == 8000)
- cpad->audio_codec = 5;
- } else {
- cpad->audio_codec = 6;
- }
- } else if (strcmp (gst_structure_get_name (s), "audio/x-raw-int") == 0) {
- gint endianness;
-
- if (gst_structure_get_int (s, "endianness", &endianness)
- && endianness == G_LITTLE_ENDIAN)
- cpad->audio_codec = 3;
- else
- ret = FALSE;
- } else if (strcmp (gst_structure_get_name (s), "audio/x-alaw") == 0) {
- cpad->audio_codec = 7;
- } else if (strcmp (gst_structure_get_name (s), "audio/x-mulaw") == 0) {
- cpad->audio_codec = 8;
- } else if (strcmp (gst_structure_get_name (s), "audio/x-speex") == 0) {
- cpad->audio_codec = 11;
- } else {
- ret = FALSE;
- }
-
- if (ret) {
- gint rate, channels, width;
-
- if (gst_structure_get_int (s, "rate", &rate)) {
- if (cpad->audio_codec == 10)
- cpad->rate = 3;
- else if (rate == 5512)
- cpad->rate = 0;
- else if (rate == 11025)
- cpad->rate = 1;
- else if (rate == 22050)
- cpad->rate = 2;
- else if (rate == 44100)
- cpad->rate = 3;
- else if (rate == 8000 && (cpad->audio_codec == 5
- || cpad->audio_codec == 14))
- cpad->rate = 0;
- else if (rate == 16000 && cpad->audio_codec == 4)
- cpad->rate = 0;
- else
- ret = FALSE;
- } else if (cpad->audio_codec == 10) {
- cpad->rate = 3;
- } else {
- ret = FALSE;
- }
-
- if (gst_structure_get_int (s, "channels", &channels)) {
- if (cpad->audio_codec == 4 || cpad->audio_codec == 5
- || cpad->audio_codec == 6)
- cpad->channels = 0;
- else if (cpad->audio_codec == 10)
- cpad->channels = 1;
- else if (channels == 1)
- cpad->channels = 0;
- else if (channels == 2)
- cpad->channels = 1;
- else
- ret = FALSE;
- } else if (cpad->audio_codec == 4 || cpad->audio_codec == 5
- || cpad->audio_codec == 6) {
- cpad->channels = 0;
- } else if (cpad->audio_codec == 10) {
- cpad->channels = 1;
- } else {
- ret = FALSE;
- }
-
- if (gst_structure_get_int (s, "width", &width)) {
- if (cpad->audio_codec != 3)
- cpad->width = 1;
- else if (width == 8)
- cpad->width = 0;
- else if (width == 16)
- cpad->width = 1;
- else
- ret = FALSE;
- } else if (cpad->audio_codec != 3) {
- cpad->width = 1;
- } else {
- ret = FALSE;
- }
- }
-
- if (ret && gst_structure_has_field (s, "codec_data")) {
- const GValue *val = gst_structure_get_value (s, "codec_data");
-
- if (val) {
- cpad->audio_codec_data = gst_buffer_ref (gst_value_get_buffer (val));
- cpad->sent_codec_data = FALSE;
- } else {
- cpad->sent_codec_data = TRUE;
- }
- } else {
- cpad->sent_codec_data = TRUE;
- }
-
- gst_object_unref (mux);
-
- return ret;
-}
-
-static GstPad *
-gst_flv_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * pad_name)
-{
- GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
- GstFlvMux *mux = GST_FLV_MUX (element);
- GstFlvPad *cpad;
- GstPad *pad = NULL;
- const gchar *name = NULL;
- GstPadSetCapsFunction setcapsfunc = NULL;
- gboolean video;
-
- if (mux->state != GST_FLV_MUX_STATE_HEADER) {
- GST_WARNING_OBJECT (mux, "Can't request pads after writing header");
- return NULL;
- }
-
- if (templ == gst_element_class_get_pad_template (klass, "audio")) {
- if (mux->have_audio) {
- GST_WARNING_OBJECT (mux, "Already have an audio pad");
- return NULL;
- }
- mux->have_audio = TRUE;
- name = "audio";
- video = FALSE;
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_flv_mux_audio_pad_setcaps);
- } else if (templ == gst_element_class_get_pad_template (klass, "video")) {
- if (mux->have_video) {
- GST_WARNING_OBJECT (mux, "Already have a video pad");
- return NULL;
- }
- mux->have_video = TRUE;
- name = "video";
- video = TRUE;
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_flv_mux_video_pad_setcaps);
- } else {
- GST_WARNING_OBJECT (mux, "Invalid template");
- return NULL;
- }
-
- pad = gst_pad_new_from_template (templ, name);
- cpad = (GstFlvPad *)
- gst_collect_pads_add_pad (mux->collect, pad, sizeof (GstFlvPad));
-
- cpad->video = video;
-
- cpad->audio_codec = G_MAXUINT;
- cpad->rate = G_MAXUINT;
- cpad->width = G_MAXUINT;
- cpad->channels = G_MAXUINT;
- cpad->audio_codec_data = NULL;
-
- cpad->video_codec = G_MAXUINT;
- cpad->video_codec_data = NULL;
-
- cpad->sent_codec_data = FALSE;
-
- cpad->last_timestamp = 0;
-
- /* FIXME: hacked way to override/extend the event function of
- * GstCollectPads; because it sets its own event function giving the
- * element no access to events.
- */
- mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
- gst_pad_set_event_function (pad,
- GST_DEBUG_FUNCPTR (gst_flv_mux_handle_sink_event));
-
- gst_pad_set_setcaps_function (pad, setcapsfunc);
- gst_pad_set_active (pad, TRUE);
- gst_element_add_pad (element, pad);
-
- return pad;
-}
-
-static void
-gst_flv_mux_release_pad (GstElement * element, GstPad * pad)
-{
- GstFlvMux *mux = GST_FLV_MUX (GST_PAD_PARENT (pad));
- GstFlvPad *cpad = (GstFlvPad *) gst_pad_get_element_private (pad);
-
- if (cpad && cpad->audio_codec_data)
- gst_buffer_unref (cpad->audio_codec_data);
- if (cpad && cpad->video_codec_data)
- gst_buffer_unref (cpad->video_codec_data);
-
- gst_collect_pads_remove_pad (mux->collect, pad);
- gst_element_remove_pad (element, pad);
-}
-
-static GstFlowReturn
-gst_flv_mux_write_metadata (GstFlvMux * mux)
-{
- GstTagList *merged_tags;
- const GstTagList *user_tags;
- GstFlowReturn ret = GST_FLOW_OK;
- GstBuffer *script_tag, *tmp;
- guint8 *data;
- gint i, n_tags, tags_written = 0;
-
- user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
- GST_DEBUG_OBJECT (mux, "upstream tags = %" GST_PTR_FORMAT, mux->tags);
- GST_DEBUG_OBJECT (mux, "user-set tags = %" GST_PTR_FORMAT, user_tags);
-
- merged_tags = gst_tag_list_merge (user_tags, mux->tags,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
-
- GST_DEBUG_OBJECT (mux, "merged tags = %" GST_PTR_FORMAT, merged_tags);
-
- script_tag = gst_buffer_new_and_alloc (11);
- data = GST_BUFFER_DATA (script_tag);
-
- data[0] = 18;
-
- /* Data size, unknown for now */
- data[1] = 0;
- data[2] = 0;
- data[3] = 0;
-
- /* Timestamp */
- data[4] = data[5] = data[6] = data[7] = 0;
-
- /* Stream ID */
- data[8] = data[9] = data[10] = 0;
-
- tmp = gst_buffer_new_and_alloc (13);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 2; /* string */
- data[1] = 0;
- data[2] = 0x0a; /* length 10 */
- memcpy (&data[3], "onMetaData", sizeof ("onMetaData"));
-
- script_tag = gst_buffer_join (script_tag, tmp);
-
- n_tags =
- (merged_tags) ? gst_structure_n_fields ((GstStructure *) merged_tags) : 0;
- tmp = gst_buffer_new_and_alloc (5);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 8; /* ECMA array */
- GST_WRITE_UINT32_BE (data + 1, n_tags);
- script_tag = gst_buffer_join (script_tag, tmp);
-
- for (i = 0; merged_tags && i < n_tags; i++) {
- const gchar *tag_name =
- gst_structure_nth_field_name ((const GstStructure *) merged_tags, i);
- if (!strcmp (tag_name, GST_TAG_DURATION)) {
- gdouble d;
- guint64 dur;
-
- if (!gst_tag_list_get_uint64 (merged_tags, GST_TAG_DURATION, &dur))
- continue;
-
- d = gst_guint64_to_gdouble (dur);
- d /= (gdouble) GST_SECOND;
-
- tmp = gst_buffer_new_and_alloc (2 + 8 + 1 + 8);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 8 bytes name */
- data[1] = 8;
- memcpy (&data[2], "duration", sizeof ("duration"));
- data[10] = 0; /* double */
- GST_WRITE_DOUBLE_BE (data + 11, d);
- script_tag = gst_buffer_join (script_tag, tmp);
- tags_written++;
- } else if (!strcmp (tag_name, GST_TAG_ARTIST) ||
- !strcmp (tag_name, GST_TAG_TITLE)) {
- gchar *s;
- const gchar *t;
-
- if (!strcmp (tag_name, GST_TAG_ARTIST))
- t = "creator";
- else if (!strcmp (tag_name, GST_TAG_TITLE))
- t = "title";
-
- if (!gst_tag_list_get_string (merged_tags, tag_name, &s))
- continue;
-
- tmp = gst_buffer_new_and_alloc (2 + strlen (t) + 1 + 2 + strlen (s));
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* tag name length */
- data[1] = strlen (t);
- memcpy (&data[2], t, strlen (t));
- data[2 + strlen (t)] = 2; /* string */
- data[3 + strlen (t)] = (strlen (s) >> 8) & 0xff;
- data[4 + strlen (t)] = (strlen (s)) & 0xff;
- memcpy (&data[5 + strlen (t)], s, strlen (s));
- script_tag = gst_buffer_join (script_tag, tmp);
-
- g_free (s);
- tags_written++;
- }
- }
-
- if (mux->have_video) {
- GstPad *video_pad = NULL;
- GSList *l = mux->collect->data;
-
- for (; l; l = l->next) {
- GstFlvPad *cpad = l->data;
- if (cpad && cpad->video) {
- video_pad = cpad->collect.pad;
- break;
- }
- }
-
- if (video_pad && GST_PAD_CAPS (video_pad)) {
- GstStructure *s = gst_caps_get_structure (GST_PAD_CAPS (video_pad), 0);
- gint par_x, par_y;
-
- if (gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_x, &par_y)) {
- gdouble d;
-
- d = par_x;
- tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 8);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 12 bytes name */
- data[1] = 12;
- memcpy (&data[2], "AspectRatioX", sizeof ("AspectRatioX"));
- data[14] = 0; /* double */
- GST_WRITE_DOUBLE_BE (data + 15, d);
- script_tag = gst_buffer_join (script_tag, tmp);
- tags_written++;
-
- d = par_y;
- tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 8);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 12 bytes name */
- data[1] = 12;
- memcpy (&data[2], "AspectRatioY", sizeof ("AspectRatioY"));
- data[14] = 0; /* double */
- GST_WRITE_DOUBLE_BE (data + 15, d);
- script_tag = gst_buffer_join (script_tag, tmp);
- tags_written++;
- }
- }
- }
-
- {
- const gchar *s = "GStreamer FLV muxer";
-
- tmp = gst_buffer_new_and_alloc (2 + 15 + 1 + 2 + strlen (s));
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 15 bytes name */
- data[1] = 15;
- memcpy (&data[2], "metadatacreator", sizeof ("metadatacreator"));
- data[17] = 2; /* string */
- data[18] = (strlen (s) >> 8) & 0xff;
- data[19] = (strlen (s)) & 0xff;
- memcpy (&data[20], s, strlen (s));
- script_tag = gst_buffer_join (script_tag, tmp);
-
- tags_written++;
- }
-
- {
- GTimeVal tv = { 0, };
- time_t secs;
- struct tm *tm;
- gchar *s;
- static const gchar *weekdays[] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
- static const gchar *months[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
- "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- g_get_current_time (&tv);
- secs = tv.tv_sec;
- tm = gmtime (&secs);
-
- s = g_strdup_printf ("%s %s %d %d:%d:%d %d", weekdays[tm->tm_wday],
- months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
- tm->tm_year + 1900);
-
- tmp = gst_buffer_new_and_alloc (2 + 12 + 1 + 2 + strlen (s));
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 12 bytes name */
- data[1] = 12;
- memcpy (&data[2], "creationdate", sizeof ("creationdate"));
- data[14] = 2; /* string */
- data[15] = (strlen (s) >> 8) & 0xff;
- data[16] = (strlen (s)) & 0xff;
- memcpy (&data[17], s, strlen (s));
- script_tag = gst_buffer_join (script_tag, tmp);
-
- g_free (s);
- tags_written++;
- }
-
- tmp = gst_buffer_new_and_alloc (2 + 0 + 1);
- data = GST_BUFFER_DATA (tmp);
- data[0] = 0; /* 0 byte size */
- data[1] = 0;
- data[2] = 9; /* end marker */
- script_tag = gst_buffer_join (script_tag, tmp);
- tags_written++;
-
-
- tmp = gst_buffer_new_and_alloc (4);
- data = GST_BUFFER_DATA (tmp);
- GST_WRITE_UINT32_BE (data, GST_BUFFER_SIZE (script_tag));
- script_tag = gst_buffer_join (script_tag, tmp);
-
- data = GST_BUFFER_DATA (script_tag);
- data[1] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 16) & 0xff;
- data[2] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 8) & 0xff;
- data[3] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 0) & 0xff;
-
- GST_WRITE_UINT32_BE (data + 11 + 13 + 1, tags_written);
-
- gst_buffer_set_caps (script_tag, GST_PAD_CAPS (mux->srcpad));
- ret = gst_pad_push (mux->srcpad, script_tag);
-
- if (merged_tags)
- gst_tag_list_free (merged_tags);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_mux_write_header (GstFlvMux * mux)
-{
- GstBuffer *header = gst_buffer_new_and_alloc (9 + 4);
- guint8 *data = GST_BUFFER_DATA (header);
- GstFlowReturn ret;
-
- if (GST_PAD_CAPS (mux->srcpad) == NULL) {
- GstCaps *caps = gst_caps_new_simple ("video/x-flv", NULL);
-
- gst_pad_set_caps (mux->srcpad, caps);
- gst_caps_unref (caps);
- }
- gst_buffer_set_caps (header, GST_PAD_CAPS (mux->srcpad));
-
- data[0] = 'F';
- data[1] = 'L';
- data[2] = 'V';
- data[3] = 0x01; /* Version */
-
- data[4] = (mux->have_audio << 2) | mux->have_video; /* flags */
- GST_WRITE_UINT32_BE (data + 5, 9); /* data offset */
-
- GST_WRITE_UINT32_BE (data + 9, 0); /* previous tag size */
-
- ret = gst_pad_push (mux->srcpad, header);
- if (ret != GST_FLOW_OK)
- return ret;
-
- return gst_flv_mux_write_metadata (mux);
-}
-
-static GstFlowReturn
-gst_flv_mux_write_buffer (GstFlvMux * mux, GstFlvPad * cpad)
-{
- GstBuffer *tag;
- guint8 *data;
- guint size;
- GstBuffer *buffer =
- gst_collect_pads_pop (mux->collect, (GstCollectData *) cpad);
- guint32 timestamp =
- (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) ? GST_BUFFER_TIMESTAMP (buffer) /
- GST_MSECOND : cpad->last_timestamp / GST_MSECOND;
- gboolean second_run = FALSE;
- GstFlowReturn ret;
-
-next:
- size = 11;
- if (cpad->video) {
- size += 1;
- if (cpad->video_codec == 7 && !cpad->sent_codec_data)
- size += 4 + GST_BUFFER_SIZE (cpad->video_codec_data);
- else if (cpad->video_codec == 7)
- size += 4 + GST_BUFFER_SIZE (buffer);
- else
- size += GST_BUFFER_SIZE (buffer);
- } else {
- size += 1;
- if (cpad->audio_codec == 10 && !cpad->sent_codec_data)
- size += 1 + GST_BUFFER_SIZE (cpad->audio_codec_data);
- else if (cpad->audio_codec == 10)
- size += 1 + GST_BUFFER_SIZE (buffer);
- else
- size += GST_BUFFER_SIZE (buffer);
- }
- size += 4;
-
- tag = gst_buffer_new_and_alloc (size);
- data = GST_BUFFER_DATA (tag);
- memset (data, 0, size);
-
- data[0] = (cpad->video) ? 9 : 8;
-
- data[1] = ((size - 11 - 4) >> 16) & 0xff;
- data[2] = ((size - 11 - 4) >> 8) & 0xff;
- data[3] = ((size - 11 - 4) >> 0) & 0xff;
-
- data[4] = (timestamp >> 16) & 0xff;
- data[5] = (timestamp >> 8) & 0xff;
- data[6] = (timestamp >> 0) & 0xff;
- data[7] = (timestamp >> 24) & 0xff;
-
- data[8] = data[9] = data[10] = 0;
-
- if (cpad->video) {
- if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
- data[11] |= 2 << 4;
- else
- data[11] |= 1 << 4;
-
- data[11] |= cpad->video_codec & 0x0f;
-
- if (cpad->video_codec == 7 && !cpad->sent_codec_data) {
- data[12] = 0;
- data[13] = data[14] = data[15] = 0;
-
- memcpy (data + 11 + 1 + 4, GST_BUFFER_DATA (cpad->video_codec_data),
- GST_BUFFER_SIZE (cpad->video_codec_data));
- second_run = TRUE;
- } else if (cpad->video_codec == 7) {
- data[12] = 1;
-
- /* FIXME: what to do about composition time */
- data[13] = data[14] = data[15] = 0;
-
- memcpy (data + 11 + 1 + 4, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- } else {
- memcpy (data + 11 + 1, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- }
- } else {
- data[11] |= (cpad->audio_codec << 4) & 0xf0;
- data[11] |= (cpad->rate << 2) & 0x0c;
- data[11] |= (cpad->width << 1) & 0x02;
- data[11] |= (cpad->channels << 0) & 0x01;
-
- if (cpad->audio_codec == 10 && !cpad->sent_codec_data) {
- data[12] = 0;
-
- memcpy (data + 11 + 1 + 1, GST_BUFFER_DATA (cpad->audio_codec_data),
- GST_BUFFER_SIZE (cpad->audio_codec_data));
- second_run = TRUE;
- } else if (cpad->audio_codec == 10) {
- data[12] = 1;
-
- memcpy (data + 11 + 1 + 1, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- } else {
- memcpy (data + 11 + 1, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- }
- }
-
- GST_WRITE_UINT32_BE (data + size - 4, size - 4);
-
- gst_buffer_set_caps (tag, GST_PAD_CAPS (mux->srcpad));
-
- if (second_run) {
- second_run = FALSE;
- cpad->sent_codec_data = TRUE;
-
- ret = gst_pad_push (mux->srcpad, tag);
- if (ret != GST_FLOW_OK) {
- gst_buffer_unref (buffer);
- return ret;
- }
-
- cpad->last_timestamp = timestamp;
-
- tag = NULL;
- goto next;
- }
-
- gst_buffer_copy_metadata (tag, buffer, GST_BUFFER_COPY_TIMESTAMPS);
- GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) =
- GST_BUFFER_OFFSET_NONE;
-
- gst_buffer_unref (buffer);
-
- ret = gst_pad_push (mux->srcpad, tag);
-
- if (ret == GST_FLOW_OK)
- cpad->last_timestamp = timestamp;
-
- return ret;
-}
-
-static GstFlowReturn
-gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data)
-{
- GstFlvMux *mux = GST_FLV_MUX (user_data);
- GstFlvPad *best;
- GstClockTime best_time;
- GstFlowReturn ret;
- GSList *sl;
- gboolean eos = TRUE;
-
- if (mux->state == GST_FLV_MUX_STATE_HEADER) {
- if (mux->collect->data == NULL) {
- GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
- ("No input streams configured"));
- return GST_FLOW_ERROR;
- }
-
- if (gst_pad_push_event (mux->srcpad,
- gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)))
- ret = gst_flv_mux_write_header (mux);
- else
- ret = GST_FLOW_ERROR;
-
- if (ret != GST_FLOW_OK)
- return ret;
- mux->state = GST_FLV_MUX_STATE_DATA;
- }
-
- best = NULL;
- best_time = GST_CLOCK_TIME_NONE;
- for (sl = mux->collect->data; sl; sl = sl->next) {
- GstFlvPad *cpad = sl->data;
- GstBuffer *buffer = gst_collect_pads_peek (pads, (GstCollectData *) cpad);
- GstClockTime time;
-
- if (!buffer)
- continue;
-
- eos = FALSE;
-
- time = GST_BUFFER_TIMESTAMP (buffer);
- gst_buffer_unref (buffer);
-
- /* Use buffers without valid timestamp first */
- if (!GST_CLOCK_TIME_IS_VALID (time)) {
- GST_WARNING_OBJECT (pads, "Buffer without valid timestamp");
-
- best_time = cpad->last_timestamp;
- best = cpad;
- break;
- }
-
-
- if (best == NULL || (GST_CLOCK_TIME_IS_VALID (best_time)
- && time < best_time)) {
- best = cpad;
- best_time = time;
- }
- }
-
- if (GST_CLOCK_TIME_IS_VALID (best_time)
- && best_time / GST_MSECOND > G_MAXUINT32) {
- GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS");
- eos = TRUE;
- }
-
- if (!eos && best) {
- return gst_flv_mux_write_buffer (mux, best);
- } else if (eos) {
- gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
- return GST_FLOW_UNEXPECTED;
- } else {
- return GST_FLOW_OK;
- }
-}
-
-static GstStateChangeReturn
-gst_flv_mux_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret;
- GstFlvMux *mux = GST_FLV_MUX (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- gst_collect_pads_start (mux->collect);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_collect_pads_stop (mux->collect);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_flv_mux_reset (GST_ELEMENT (mux));
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return ret;
-}
diff --git a/gst/flv/gstflvmux.h b/gst/flv/gstflvmux.h
deleted file mode 100644
index 02df089d..00000000
--- a/gst/flv/gstflvmux.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* GStreamer
- *
- * Copyright (c) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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_FLV_MUX_H__
-#define __GST_FLV_MUX_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstcollectpads.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_FLV_MUX \
- (gst_flv_mux_get_type ())
-#define GST_FLV_MUX(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_FLV_MUX, GstFlvMux))
-#define GST_FLV_MUX_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_FLV_MUX, GstFlvMuxClass))
-#define GST_IS_FLV_MUX(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_FLV_MUX))
-#define GST_IS_FLV_MUX_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_FLV_MUX))
-
-typedef struct
-{
- GstCollectData collect;
-
- gboolean video;
-
- guint audio_codec;
- guint rate;
- guint width;
- guint channels;
- GstBuffer *audio_codec_data;
-
- guint video_codec;
- GstBuffer *video_codec_data;
-
- gboolean sent_codec_data;
- GstClockTime last_timestamp;
-} GstFlvPad;
-
-typedef enum
-{
- GST_FLV_MUX_STATE_HEADER,
- GST_FLV_MUX_STATE_DATA
-} GstFlvMuxState;
-
-typedef struct _GstFlvMux {
- GstElement element;
-
- GstPad *srcpad;
- GstCollectPads *collect;
-
- /* <private> */
- GstPadEventFunction collect_event;
-
- GstFlvMuxState state;
- gboolean have_audio;
- gboolean have_video;
-
- GstTagList *tags;
-} GstFlvMux;
-
-typedef struct _GstFlvMuxClass {
- GstElementClass parent;
-} GstFlvMuxClass;
-
-GType gst_flv_mux_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_FLV_MUX_H__ */
diff --git a/gst/flv/gstflvparse.c b/gst/flv/gstflvparse.c
deleted file mode 100644
index 59446512..00000000
--- a/gst/flv/gstflvparse.c
+++ /dev/null
@@ -1,1283 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "gstflvparse.h"
-
-#include <gst/base/gstbytereader.h>
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_EXTERN (flvdemux_debug);
-#define GST_CAT_DEFAULT flvdemux_debug
-
-static gchar *
-FLV_GET_STRING (GstByteReader * reader)
-{
- guint16 string_size = 0;
- gchar *string = NULL;
- const guint8 *str;
-
- g_return_val_if_fail (reader != NULL, NULL);
-
- if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
- return NULL;
-
- if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
- return NULL;
-
- string = g_try_malloc0 (string_size + 1);
- if (G_UNLIKELY (!string)) {
- return NULL;
- }
-
- if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
- g_free (string);
- return NULL;
- }
-
- memcpy (string, str, string_size);
- if (!g_utf8_validate (string, string_size, NULL)) {
- g_free (string);
- return NULL;
- }
-
- return string;
-}
-
-static const GstQueryType *
-gst_flv_demux_query_types (GstPad * pad)
-{
- static const GstQueryType query_types[] = {
- GST_QUERY_DURATION,
- 0
- };
-
- return query_types;
-}
-
-static void
-parse_flv_date_string (GDate * date, const gchar * s)
-{
- g_date_set_parse (date, s);
- if (g_date_valid (date))
- return;
-
- /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
- {
- static const gchar *months[] = {
- "Jan", "Feb", "Mar", "Apr",
- "May", "Jun", "Jul", "Aug",
- "Sep", "Oct", "Nov", "Dec"
- };
- gchar **tokens = g_strsplit (s, " ", -1);
- guint64 d;
- gchar *endptr;
- gint i;
-
- if (g_strv_length (tokens) != 5)
- goto out;
-
- if (strlen (tokens[1]) != 3)
- goto out;
- for (i = 0; i < 12; i++) {
- if (!strcmp (tokens[1], months[i])) {
- break;
- }
- }
- if (i == 12)
- goto out;
- g_date_set_month (date, i + 1);
-
- d = g_ascii_strtoull (tokens[2], &endptr, 10);
- if (d == 0 && *endptr != '\0')
- goto out;
-
- g_date_set_day (date, d);
-
- d = g_ascii_strtoull (tokens[4], &endptr, 10);
- if (d == 0 && *endptr != '\0')
- goto out;
-
- g_date_set_year (date, d);
-
- out:
- if (tokens)
- g_strfreev (tokens);
- }
-}
-
-static gboolean
-gst_flv_parse_metadata_item (GstFLVDemux * demux, GstByteReader * reader,
- gboolean * end_marker)
-{
- gchar *tag_name = NULL;
- guint8 tag_type = 0;
-
- /* Initialize the end_marker flag to FALSE */
- *end_marker = FALSE;
-
- /* Name of the tag */
- tag_name = FLV_GET_STRING (reader);
- if (G_UNLIKELY (!tag_name)) {
- GST_WARNING_OBJECT (demux, "failed reading tag name");
- return FALSE;
- }
-
- /* What kind of object is that */
- if (!gst_byte_reader_get_uint8 (reader, &tag_type))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
-
- switch (tag_type) {
- case 0: // Double
- { /* Use a union to read the uint64 and then as a double */
- gdouble d;
-
- if (!gst_byte_reader_get_float64_be (reader, &d))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
-
- if (!strcmp (tag_name, "duration")) {
- demux->duration = d * GST_SECOND;
-
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_DURATION, demux->duration, NULL);
- } else if (!strcmp (tag_name, "AspectRatioX")) {
- demux->par_x = d;
- demux->got_par = TRUE;
- } else if (!strcmp (tag_name, "AspectRatioY")) {
- demux->par_y = d;
- demux->got_par = TRUE;
- } else {
- GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
- }
-
- break;
- }
- case 1: // Boolean
- {
- guint8 b;
-
- if (!gst_byte_reader_get_uint8 (reader, &b))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
-
- GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
-
- break;
- }
- case 2: // String
- {
- gchar *s = NULL;
-
- s = FLV_GET_STRING (reader);
- if (s == NULL)
- goto error;
-
- GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
-
- if (!strcmp (tag_name, "creationdate")) {
- GDate *date = g_date_new ();
-
- parse_flv_date_string (date, s);
- if (!g_date_valid (date)) {
- GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
- } else {
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_DATE, date, NULL);
- }
- g_date_free (date);
- } else if (!strcmp (tag_name, "creator")) {
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_ARTIST, s, NULL);
- } else if (!strcmp (tag_name, "title")) {
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_TITLE, s, NULL);
- } else if (!strcmp (tag_name, "metadatacreator")) {
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_ENCODER, s, NULL);
- } else {
- GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
- }
-
- g_free (s);
-
- break;
- }
- case 3: // Object
- {
- gboolean end_of_object_marker = FALSE;
-
- while (!end_of_object_marker) {
- gboolean ok =
- gst_flv_parse_metadata_item (demux, reader, &end_of_object_marker);
-
- if (G_UNLIKELY (!ok)) {
- GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
- goto error;
- }
- }
-
- break;
- }
- case 8: // ECMA array
- {
- guint32 nb_elems;
- gboolean end_of_object_marker = FALSE;
-
- if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
- nb_elems);
-
- while (!end_of_object_marker) {
- gboolean ok =
- gst_flv_parse_metadata_item (demux, reader, &end_of_object_marker);
-
- if (G_UNLIKELY (!ok)) {
- GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
- goto error;
- }
- }
-
- break;
- }
- case 9: // End marker
- {
- GST_DEBUG_OBJECT (demux, "end marker ?");
- if (tag_name[0] == '\0') {
-
- GST_DEBUG_OBJECT (demux, "end marker detected");
-
- *end_marker = TRUE;
- }
-
- break;
- }
- case 10: // Array
- {
- guint32 nb_elems;
-
- if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
-
- if (!strcmp (tag_name, "times")) {
- if (demux->times) {
- g_array_free (demux->times, TRUE);
- }
- demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
- } else if (!strcmp (tag_name, "filepositions")) {
- if (demux->filepositions) {
- g_array_free (demux->filepositions, TRUE);
- }
- demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
- }
-
- while (nb_elems--) {
- guint8 elem_type;
-
- if (!gst_byte_reader_get_uint8 (reader, &elem_type))
- goto error;
-
- switch (elem_type) {
- case 0:
- {
- gdouble d;
-
- if (!gst_byte_reader_get_float64_be (reader, &d))
- goto error;
-
- GST_DEBUG_OBJECT (demux, "element is a double %f", d);
-
- if (!strcmp (tag_name, "times") && demux->times) {
- g_array_append_val (demux->times, d);
- } else if (!strcmp (tag_name, "filepositions") &&
- demux->filepositions) {
- g_array_append_val (demux->filepositions, d);
- }
- break;
- }
- default:
- GST_WARNING_OBJECT (demux, "unsupported array element type %d",
- elem_type);
- }
- }
-
- break;
- }
- case 11: // Date
- {
- gdouble d;
- gint16 i;
-
- if (!gst_byte_reader_get_float64_be (reader, &d))
- goto error;
-
- if (!gst_byte_reader_get_int16_be (reader, &i))
- goto error;
-
- GST_DEBUG_OBJECT (demux,
- "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
-
- GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
-
- break;
- }
- default:
- GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
- }
-
- g_free (tag_name);
-
- return TRUE;
-
-error:
- g_free (tag_name);
-
- return FALSE;
-}
-
-GstFlowReturn
-gst_flv_parse_tag_script (GstFLVDemux * demux, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
- guint8 type;
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 7, GST_FLOW_ERROR);
-
- gst_byte_reader_skip (&reader, 7);
-
- GST_LOG_OBJECT (demux, "parsing a script tag");
-
- if (!gst_byte_reader_get_uint8 (&reader, &type))
- return GST_FLOW_OK;
-
- /* Must be string */
- if (type == 2) {
- gchar *function_name;
- guint i;
-
- function_name = FLV_GET_STRING (&reader);
-
- GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
-
- if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
- guint32 nb_elems = 0;
- gboolean end_marker = FALSE;
-
- GST_DEBUG_OBJECT (demux, "we have a metadata script object");
-
- /* Next type must be a ECMA array */
- if (!gst_byte_reader_get_uint8 (&reader, &type) || type != 8) {
- g_free (function_name);
- return GST_FLOW_OK;
- }
-
- if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
- g_free (function_name);
- return GST_FLOW_OK;
- }
-
- GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
- nb_elems);
-
- while (nb_elems-- && !end_marker) {
- gboolean ok = gst_flv_parse_metadata_item (demux, &reader, &end_marker);
-
- if (G_UNLIKELY (!ok)) {
- GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
- break;
- }
- }
-
- demux->push_tags = TRUE;
- }
-
- g_free (function_name);
-
- if (demux->index && demux->times && demux->filepositions
- && !demux->random_access) {
- /* If an index was found and we're in push mode, insert associations */
- for (i = 0; i < MIN (demux->times->len, demux->filepositions->len); i++) {
- guint64 time, fileposition;
-
- time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
- fileposition = g_array_index (demux->filepositions, gdouble, i);
- GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
- G_GUINT64_FORMAT, GST_TIME_ARGS (time), fileposition);
- gst_index_add_association (demux->index, demux->index_id,
- GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time,
- GST_FORMAT_BYTES, fileposition, NULL);
- }
- }
- }
-
- return ret;
-}
-
-static gboolean
-gst_flv_parse_audio_negotiate (GstFLVDemux * demux, guint32 codec_tag,
- guint32 rate, guint32 channels, guint32 width)
-{
- GstCaps *caps = NULL;
- gchar *codec_name = NULL;
- gboolean ret = FALSE;
-
- switch (codec_tag) {
- case 1:
- caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
- "swf", NULL);
- codec_name = "Shockwave ADPCM";
- break;
- case 2:
- case 14:
- caps = gst_caps_new_simple ("audio/mpeg",
- "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
- "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
- codec_name = "MPEG 1 Audio, Layer 3 (MP3)";
- break;
- case 0:
- case 3:
- /* Assuming little endian for 0 (aka endianness of the
- * system on which the file was created) as most people
- * are probably using little endian machines */
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
- "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
- "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
- codec_name = "Raw Audio";
- break;
- case 4:
- case 5:
- case 6:
- caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
- codec_name = "Nellymoser ASAO";
- break;
- case 10:
- caps = gst_caps_new_simple ("audio/mpeg",
- "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
- codec_name = "AAC";
- break;
- case 7:
- caps = gst_caps_new_simple ("audio/x-alaw", NULL);
- codec_name = "A-Law";
- break;
- case 8:
- caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
- codec_name = "Mu-Law";
- break;
- case 11:
- caps = gst_caps_new_simple ("audio/x-speex", NULL);
- codec_name = "Speex";
- break;
- default:
- GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
- }
-
- if (G_UNLIKELY (!caps)) {
- GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
- goto beach;
- }
-
- gst_caps_set_simple (caps,
- "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
-
- if (demux->audio_codec_data) {
- gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
- demux->audio_codec_data, NULL);
- }
-
- ret = gst_pad_set_caps (demux->audio_pad, caps);
-
- if (G_LIKELY (ret)) {
- /* Store the caps we have set */
- demux->audio_codec_tag = codec_tag;
- demux->rate = rate;
- demux->channels = channels;
- demux->width = width;
-
- if (codec_name) {
- if (demux->taglist == NULL)
- demux->taglist = gst_tag_list_new ();
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_AUDIO_CODEC, codec_name, NULL);
- }
-
- GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
- GST_PTR_FORMAT, caps);
- } else {
- GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
- GST_PTR_FORMAT, caps);
- }
-
- gst_caps_unref (caps);
-
-beach:
- return ret;
-}
-
-GstFlowReturn
-gst_flv_parse_tag_audio (GstFLVDemux * demux, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
- guint32 codec_data = 0, pts_ext = 0;
- guint8 flags = 0;
- guint8 *data = GST_BUFFER_DATA (buffer);
- GstBuffer *outbuf;
-
- GST_LOG_OBJECT (demux, "parsing an audio tag");
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
- GST_FLOW_ERROR);
-
- GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
- data[2], data[3]);
-
- /* Grab information about audio tag */
- pts = GST_READ_UINT24_BE (data);
- /* read the pts extension to 32 bits integer */
- pts_ext = GST_READ_UINT8 (data + 3);
- /* Combine them */
- pts |= pts_ext << 24;
-
- if (GST_BUFFER_SIZE (buffer) < 12) {
- GST_ERROR_OBJECT (demux, "Too small tag size");
- return GST_FLOW_ERROR;
- }
-
- /* Skip the stream id and go directly to the flags */
- flags = GST_READ_UINT8 (data + 7);
-
- /* Channels */
- if (flags & 0x01) {
- channels = 2;
- }
- /* Width */
- if (flags & 0x02) {
- width = 16;
- }
- /* Sampling rate */
- if ((flags & 0x0C) == 0x0C) {
- rate = 44100;
- } else if ((flags & 0x0C) == 0x08) {
- rate = 22050;
- } else if ((flags & 0x0C) == 0x04) {
- rate = 11025;
- }
- /* Codec tag */
- codec_tag = flags >> 4;
- if (codec_tag == 10) { /* AAC has an extra byte for packet type */
- codec_data = 2;
- } else {
- codec_data = 1;
- }
-
- /* codec tags with special rates */
- if (codec_tag == 5 || codec_tag == 14)
- rate = 8000;
- else if (codec_tag == 4)
- rate = 16000;
-
- GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
- "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
- codec_tag, flags);
-
- /* If we don't have our audio pad created, then create it. */
- if (G_UNLIKELY (!demux->audio_pad)) {
-
- demux->audio_pad =
- gst_pad_new_from_template (gst_element_class_get_pad_template
- (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
- if (G_UNLIKELY (!demux->audio_pad)) {
- GST_WARNING_OBJECT (demux, "failed creating audio pad");
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- /* Negotiate caps */
- if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels,
- width)) {
- gst_object_unref (demux->audio_pad);
- demux->audio_pad = NULL;
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
- GST_PAD_CAPS (demux->audio_pad));
-
- /* Set functions on the pad */
- gst_pad_set_query_type_function (demux->audio_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
- gst_pad_set_query_function (demux->audio_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_query));
- gst_pad_set_event_function (demux->audio_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
-
- gst_pad_use_fixed_caps (demux->audio_pad);
-
- /* Make it active */
- gst_pad_set_active (demux->audio_pad, TRUE);
-
- /* We need to set caps before adding */
- gst_element_add_pad (GST_ELEMENT (demux),
- gst_object_ref (demux->audio_pad));
-
- /* We only emit no more pads when we have audio and video. Indeed we can
- * not trust the FLV header to tell us if there will be only audio or
- * only video and we would just break discovery of some files */
- if (demux->audio_pad && demux->video_pad) {
- GST_DEBUG_OBJECT (demux, "emitting no more pads");
- gst_element_no_more_pads (GST_ELEMENT (demux));
- }
- }
-
- /* Check if caps have changed */
- if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
- codec_tag != demux->audio_codec_tag || width != demux->width)) {
- GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
-
- /* Negotiate caps */
- if (!gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels,
- width)) {
- ret = GST_FLOW_ERROR;
- goto beach;
- }
- }
-
- /* Push taglist if present */
- if ((demux->has_audio && !demux->audio_pad) &&
- (demux->has_video && !demux->video_pad)) {
- GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up "
- "before we can push tags");
- } else {
- if (demux->taglist && demux->push_tags) {
- GST_DEBUG_OBJECT (demux, "pushing tags out");
- gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
- demux->taglist = gst_tag_list_new ();
- demux->push_tags = FALSE;
- }
- }
-
- /* Check if we have anything to push */
- if (demux->tag_data_size <= codec_data) {
- GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
- goto beach;
- }
-
- /* Create buffer from pad */
- outbuf =
- gst_buffer_create_sub (buffer, 7 + codec_data,
- demux->tag_data_size - codec_data);
-
- if (demux->audio_codec_tag == 10) {
- guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
-
- switch (aac_packet_type) {
- case 0:
- {
- /* AudioSpecificConfic data */
- GST_LOG_OBJECT (demux, "got an AAC codec data packet");
- if (demux->audio_codec_data) {
- gst_buffer_unref (demux->audio_codec_data);
- }
- demux->audio_codec_data = outbuf;
- /* Use that buffer data in the caps */
- gst_flv_parse_audio_negotiate (demux, codec_tag, rate, channels, width);
- goto beach;
- break;
- }
- case 1:
- /* AAC raw packet */
- GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
- break;
- default:
- GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
- aac_packet_type);
- }
- }
-
- /* Fill buffer with data */
- GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
- GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
- GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->audio_pad));
-
- if (demux->duration == GST_CLOCK_TIME_NONE ||
- demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
- demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
-
- /* Only add audio frames to the index if we have no video
- * and if we don't have random access */
- if (!demux->has_video && demux->index && !demux->random_access) {
- GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
- G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
- demux->cur_tag_offset);
- gst_index_add_association (demux->index, demux->index_id,
- GST_ASSOCIATION_FLAG_KEY_UNIT,
- GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf),
- GST_FORMAT_BYTES, demux->cur_tag_offset, NULL);
- }
-
- if (G_UNLIKELY (demux->audio_need_discont)) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
- demux->audio_need_discont = FALSE;
- }
-
- gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (outbuf));
-
- /* Do we need a newsegment event ? */
- if (G_UNLIKELY (demux->audio_need_segment)) {
- if (demux->close_seg_event)
- gst_pad_push_event (demux->audio_pad,
- gst_event_ref (demux->close_seg_event));
-
- if (!demux->new_seg_event) {
- GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
- GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->segment.last_stop),
- GST_TIME_ARGS (demux->segment.stop));
- demux->new_seg_event =
- gst_event_new_new_segment (FALSE, demux->segment.rate,
- demux->segment.format, demux->segment.last_stop,
- demux->segment.stop, demux->segment.last_stop);
- } else {
- GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
- }
-
- gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
-
- demux->audio_need_segment = FALSE;
- }
-
- GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
- " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
-
- /* Push downstream */
- ret = gst_pad_push (demux->audio_pad, outbuf);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
- " bytes audio buffer: %s", demux->tag_data_size,
- gst_flow_get_name (ret));
- if (ret == GST_FLOW_NOT_LINKED) {
- demux->audio_linked = FALSE;
- }
- goto beach;
- }
-
- demux->audio_linked = TRUE;
-
-beach:
- return ret;
-}
-
-static gboolean
-gst_flv_parse_video_negotiate (GstFLVDemux * demux, guint32 codec_tag)
-{
- gboolean ret = FALSE;
- GstCaps *caps = NULL;
- gchar *codec_name = NULL;
-
- /* Generate caps for that pad */
- switch (codec_tag) {
- case 2:
- caps = gst_caps_new_simple ("video/x-flash-video", NULL);
- codec_name = "Sorenson Video";
- break;
- case 3:
- caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
- codec_name = "Flash Screen Video";
- case 4:
- caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
- codec_name = "On2 VP6 Video";
- break;
- case 5:
- caps = gst_caps_new_simple ("video/x-vp6-alpha", NULL);
- codec_name = "On2 VP6 Video with alpha channel";
- break;
- case 7:
- caps = gst_caps_new_simple ("video/x-h264", NULL);
- codec_name = "H.264/AVC Video";
- break;
- default:
- GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
- }
-
- if (G_UNLIKELY (!caps)) {
- GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
- goto beach;
- }
-
- gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
- demux->par_x, demux->par_y, NULL);
-
- if (demux->video_codec_data) {
- gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
- demux->video_codec_data, NULL);
- }
-
- ret = gst_pad_set_caps (demux->video_pad, caps);
-
- if (G_LIKELY (ret)) {
- /* Store the caps we have set */
- demux->video_codec_tag = codec_tag;
-
- if (codec_name) {
- if (demux->taglist == NULL)
- demux->taglist = gst_tag_list_new ();
- gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_VIDEO_CODEC, codec_name, NULL);
- }
-
- GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
- GST_PTR_FORMAT, caps);
- } else {
- GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
- GST_PTR_FORMAT, caps);
- }
-
- gst_caps_unref (caps);
-
-beach:
- return ret;
-}
-
-GstFlowReturn
-gst_flv_parse_tag_video (GstFLVDemux * demux, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- guint32 pts = 0, codec_data = 1, pts_ext = 0;
- gboolean keyframe = FALSE;
- guint8 flags = 0, codec_tag = 0;
- guint8 *data = GST_BUFFER_DATA (buffer);
- GstBuffer *outbuf;
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
- GST_FLOW_ERROR);
-
- GST_LOG_OBJECT (demux, "parsing a video tag");
-
- GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
- data[2], data[3]);
-
- /* Grab information about video tag */
- pts = GST_READ_UINT24_BE (data);
- /* read the pts extension to 32 bits integer */
- pts_ext = GST_READ_UINT8 (data + 3);
- /* Combine them */
- pts |= pts_ext << 24;
-
- if (GST_BUFFER_SIZE (buffer) < 12) {
- GST_ERROR_OBJECT (demux, "Too small tag size");
- return GST_FLOW_ERROR;
- }
-
- /* Skip the stream id and go directly to the flags */
- flags = GST_READ_UINT8 (data + 7);
-
- /* Keyframe */
- if ((flags >> 4) == 1) {
- keyframe = TRUE;
- }
- /* Codec tag */
- codec_tag = flags & 0x0F;
- if (codec_tag == 4 || codec_tag == 5) {
- codec_data = 2;
- } else if (codec_tag == 7) {
- codec_data = 5;
- }
-
- GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
- "(flags %02X)", codec_tag, keyframe, flags);
-
- /* If we don't have our video pad created, then create it. */
- if (G_UNLIKELY (!demux->video_pad)) {
- demux->video_pad =
- gst_pad_new_from_template (gst_element_class_get_pad_template
- (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
- if (G_UNLIKELY (!demux->video_pad)) {
- GST_WARNING_OBJECT (demux, "failed creating video pad");
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- if (!gst_flv_parse_video_negotiate (demux, codec_tag)) {
- gst_object_unref (demux->video_pad);
- demux->video_pad = NULL;
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- /* When we ve set pixel-aspect-ratio we use that boolean to detect a
- * metadata tag that would come later and trigger a caps change */
- demux->got_par = FALSE;
-
- GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
- GST_PAD_CAPS (demux->video_pad));
-
- /* Set functions on the pad */
- gst_pad_set_query_type_function (demux->video_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
- gst_pad_set_query_function (demux->video_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_query));
- gst_pad_set_event_function (demux->video_pad,
- GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
-
- gst_pad_use_fixed_caps (demux->video_pad);
-
- /* Make it active */
- gst_pad_set_active (demux->video_pad, TRUE);
-
- /* We need to set caps before adding */
- gst_element_add_pad (GST_ELEMENT (demux),
- gst_object_ref (demux->video_pad));
-
- /* We only emit no more pads when we have audio and video. Indeed we can
- * not trust the FLV header to tell us if there will be only audio or
- * only video and we would just break discovery of some files */
- if (demux->audio_pad && demux->video_pad) {
- GST_DEBUG_OBJECT (demux, "emitting no more pads");
- gst_element_no_more_pads (GST_ELEMENT (demux));
- }
- }
-
- /* Check if caps have changed */
- if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
-
- GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
-
- if (!gst_flv_parse_video_negotiate (demux, codec_tag)) {
- ret = GST_FLOW_ERROR;
- goto beach;
- }
-
- /* When we ve set pixel-aspect-ratio we use that boolean to detect a
- * metadata tag that would come later and trigger a caps change */
- demux->got_par = FALSE;
- }
-
- /* Push taglist if present */
- if ((demux->has_audio && !demux->audio_pad) &&
- (demux->has_video && !demux->video_pad)) {
- GST_DEBUG_OBJECT (demux, "we are still waiting for a stream to come up "
- "before we can push tags");
- } else {
- if (demux->taglist && demux->push_tags) {
- GST_DEBUG_OBJECT (demux, "pushing tags out");
- gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
- demux->taglist = gst_tag_list_new ();
- demux->push_tags = FALSE;
- }
- }
-
- /* Check if we have anything to push */
- if (demux->tag_data_size <= codec_data) {
- GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
- goto beach;
- }
-
- /* Create buffer from pad */
- outbuf =
- gst_buffer_create_sub (buffer, 7 + codec_data,
- demux->tag_data_size - codec_data);
-
- if (demux->video_codec_tag == 7) {
- guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
-
- switch (avc_packet_type) {
- case 0:
- {
- /* AVCDecoderConfigurationRecord data */
- GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
- if (demux->video_codec_data) {
- gst_buffer_unref (demux->video_codec_data);
- }
- demux->video_codec_data = outbuf;
- /* Use that buffer data in the caps */
- gst_flv_parse_video_negotiate (demux, codec_tag);
- goto beach;
- break;
- }
- case 1:
- /* H.264 NALU packet */
- GST_LOG_OBJECT (demux, "got a H.264 NALU audio packet");
- break;
- default:
- GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
- avc_packet_type);
- }
- }
-
- /* Fill buffer with data */
- GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND;
- GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
- GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->video_pad));
-
- if (demux->duration == GST_CLOCK_TIME_NONE ||
- demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
- demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
-
- if (!keyframe) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- if (demux->index && !demux->random_access) {
- GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
- G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
- demux->cur_tag_offset);
- gst_index_add_association (demux->index, demux->index_id,
- GST_ASSOCIATION_FLAG_NONE,
- GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf),
- GST_FORMAT_BYTES, demux->cur_tag_offset, NULL);
- }
- } else {
- if (demux->index && !demux->random_access) {
- GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
- G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
- demux->cur_tag_offset);
- gst_index_add_association (demux->index, demux->index_id,
- GST_ASSOCIATION_FLAG_KEY_UNIT,
- GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (outbuf),
- GST_FORMAT_BYTES, demux->cur_tag_offset, NULL);
- }
- }
-
- if (G_UNLIKELY (demux->video_need_discont)) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
- demux->video_need_discont = FALSE;
- }
-
- gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (outbuf));
-
- /* Do we need a newsegment event ? */
- if (G_UNLIKELY (demux->video_need_segment)) {
- if (demux->close_seg_event)
- gst_pad_push_event (demux->video_pad,
- gst_event_ref (demux->close_seg_event));
-
- if (!demux->new_seg_event) {
- GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
- GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (demux->segment.last_stop),
- GST_TIME_ARGS (demux->segment.stop));
- demux->new_seg_event =
- gst_event_new_new_segment (FALSE, demux->segment.rate,
- demux->segment.format, demux->segment.last_stop,
- demux->segment.stop, demux->segment.last_stop);
- } else {
- GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
- }
-
- gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
-
- demux->video_need_segment = FALSE;
- }
-
- GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
- " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
- ", keyframe (%d)", GST_BUFFER_SIZE (outbuf),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
- keyframe);
-
- /* Push downstream */
- ret = gst_pad_push (demux->video_pad, outbuf);
-
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
- " bytes video buffer: %s", demux->tag_data_size,
- gst_flow_get_name (ret));
- if (ret == GST_FLOW_NOT_LINKED) {
- demux->video_linked = FALSE;
- }
- goto beach;
- }
-
- demux->video_linked = TRUE;
-
-beach:
- return ret;
-}
-
-GstClockTime
-gst_flv_parse_tag_timestamp (GstFLVDemux * demux, GstBuffer * buffer,
- size_t * tag_size)
-{
- guint32 pts = 0, pts_ext = 0;
- guint32 tag_data_size;
- guint8 type;
- gboolean keyframe = TRUE;
- GstClockTime ret;
- guint8 *data = GST_BUFFER_DATA (buffer);
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 12, GST_CLOCK_TIME_NONE);
-
- type = data[0];
-
- if (type != 9 && type != 8 && type != 18) {
- GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
- return GST_CLOCK_TIME_NONE;
- }
-
- if (type == 9)
- demux->has_video = TRUE;
- else if (type == 8)
- demux->has_audio = TRUE;
-
- tag_data_size = GST_READ_UINT24_BE (data + 1);
-
- if (GST_BUFFER_SIZE (buffer) >= tag_data_size + 11 + 4) {
- if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
- GST_WARNING_OBJECT (demux, "Invalid tag size");
- return GST_CLOCK_TIME_NONE;
- }
- }
-
- if (tag_size)
- *tag_size = tag_data_size + 11 + 4;
-
- data += 4;
-
- GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
- data[2], data[3]);
-
- /* Grab timestamp of tag tag */
- pts = GST_READ_UINT24_BE (data);
- /* read the pts extension to 32 bits integer */
- pts_ext = GST_READ_UINT8 (data + 3);
- /* Combine them */
- pts |= pts_ext << 24;
-
- if (type == 9) {
- data += 7;
-
- keyframe = ((data[0] >> 4) == 1);
- }
-
- ret = pts * GST_MSECOND;
-
- if (demux->index && (type == 9 || (type == 8 && !demux->has_video))) {
- GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %"
- G_GUINT64_FORMAT, GST_TIME_ARGS (ret), demux->offset);
- gst_index_add_association (demux->index, demux->index_id,
- (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE,
- GST_FORMAT_TIME, ret, GST_FORMAT_BYTES, demux->offset, NULL);
- }
-
- if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
- demux->duration = ret;
-
- return ret;
-}
-
-GstFlowReturn
-gst_flv_parse_tag_type (GstFLVDemux * demux, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- guint8 tag_type = 0;
- guint8 *data = GST_BUFFER_DATA (buffer);
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 4, GST_FLOW_ERROR);
-
- tag_type = data[0];
-
- switch (tag_type) {
- case 9:
- demux->state = FLV_STATE_TAG_VIDEO;
- demux->has_video = TRUE;
- break;
- case 8:
- demux->state = FLV_STATE_TAG_AUDIO;
- demux->has_audio = TRUE;
- break;
- case 18:
- demux->state = FLV_STATE_TAG_SCRIPT;
- break;
- default:
- GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
- }
-
- /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
- * 4 bytes of previous tag size */
- demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
- demux->tag_size = demux->tag_data_size + 11;
-
- GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
- demux->tag_data_size);
-
- return ret;
-}
-
-GstFlowReturn
-gst_flv_parse_header (GstFLVDemux * demux, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- guint8 *data = GST_BUFFER_DATA (buffer);
-
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 9, GST_FLOW_ERROR);
-
- /* Check for the FLV tag */
- if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
- GST_DEBUG_OBJECT (demux, "FLV header detected");
- } else {
- if (G_UNLIKELY (demux->strict)) {
- GST_WARNING_OBJECT (demux, "invalid header tag detected");
- ret = GST_FLOW_UNEXPECTED;
- goto beach;
- }
- }
-
- /* Jump over the 4 first bytes */
- data += 4;
-
- /* Now look at audio/video flags */
- {
- guint8 flags = data[0];
-
- demux->has_video = demux->has_audio = FALSE;
-
- if (flags & 1) {
- GST_DEBUG_OBJECT (demux, "there is a video stream");
- demux->has_video = TRUE;
- }
- if (flags & 4) {
- GST_DEBUG_OBJECT (demux, "there is an audio stream");
- demux->has_audio = TRUE;
- }
- }
-
- /* We don't care about the rest */
- demux->need_header = FALSE;
-
-beach:
- return ret;
-}
diff --git a/gst/id3tag/Makefile.am b/gst/id3tag/Makefile.am
new file mode 100644
index 00000000..9595be0f
--- /dev/null
+++ b/gst/id3tag/Makefile.am
@@ -0,0 +1,19 @@
+plugin_LTLIBRARIES = libgstid3tag.la
+
+libgstid3tag_la_SOURCES = \
+ gsttagmux.c \
+ id3tag.c \
+ gstid3tag.c
+
+libgstid3tag_la_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(GST_CFLAGS)
+
+libgstid3tag_la_LIBADD = \
+ $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
+ $(GST_LIBS)
+
+libgstid3tag_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstid3tag_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstid3tag.h id3tag.h gsttagmux.h
diff --git a/gst/id3tag/gstid3tag.c b/gst/id3tag/gstid3tag.c
new file mode 100644
index 00000000..9c8072c0
--- /dev/null
+++ b/gst/id3tag/gstid3tag.c
@@ -0,0 +1,229 @@
+/* GStreamer ID3 v1 and v2 muxer
+ *
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * 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-id3tag
+ * @see_also: #GstID3Demux, #GstTagSetter
+ *
+ * This element adds ID3v2 tags to the beginning of a stream, and ID3v1 tags
+ * to the end.
+ *
+ * It defaults to writing ID3 version 2.3.0 tags (since those are the most
+ * widely supported), but can optionally write version 2.4.0 tags.
+ *
+ * Applications can set the tags to write using the #GstTagSetter interface.
+ * Tags sent by upstream elements will be picked up automatically (and merged
+ * according to the merge mode set via the tag setter interface).
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v filesrc location=foo.ogg ! decodebin ! audioconvert ! lame ! id3tag ! filesink location=foo.mp3
+ * ]| A pipeline that transcodes a file from Ogg/Vorbis to mp3 format with
+ * ID3 tags that contain the same metadata as the the Ogg/Vorbis file.
+ * Make sure the Ogg/Vorbis file actually has comments to preserve.
+ * |[
+ * gst-launch -m filesrc location=foo.mp3 ! id3demux ! fakesink silent=TRUE 2&gt; /dev/null | grep taglist
+ * ]| Verify that tags have been written.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstid3tag.h"
+#include <gst/tag/tag.h>
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY (gst_id3_tag_debug);
+#define GST_CAT_DEFAULT gst_id3_tag_debug
+
+enum
+{
+ ARG_0,
+ ARG_WRITE_V1,
+ ARG_WRITE_V2,
+ ARG_V2_MAJOR_VERSION
+};
+
+#define DEFAULT_WRITE_V1 TRUE
+#define DEFAULT_WRITE_V2 TRUE
+#define DEFAULT_V2_MAJOR_VERSION 3
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-id3"));
+
+GST_BOILERPLATE (GstId3Tag, gst_id3_tag, GstTagMux, GST_TYPE_TAG_MUX);
+
+static GstBuffer *gst_id3_tag_render_v2_tag (GstTagMux * mux,
+ GstTagList * taglist);
+static GstBuffer *gst_id3_tag_render_v1_tag (GstTagMux * mux,
+ GstTagList * taglist);
+
+static void gst_id3_tag_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_id3_tag_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void
+gst_id3_tag_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 (&src_template));
+
+ gst_element_class_set_details_simple (element_class,
+ "ID3 v1 and v2 Muxer", "Formatter/Metadata",
+ "Adds an ID3v2 header and ID3v1 footer to a file",
+ "Michael Smith <msmith@songbirdnest.com>, "
+ "Tim-Philipp Müller <tim centricular net>");
+
+ GST_DEBUG_CATEGORY_INIT (gst_id3_tag_debug, "id3tag", 0,
+ "ID3 v1 and v2 tag muxer");
+}
+
+static void
+gst_id3_tag_class_init (GstId3TagClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->set_property = gst_id3_tag_set_property;
+ gobject_class->get_property = gst_id3_tag_get_property;
+
+ g_object_class_install_property (gobject_class, ARG_WRITE_V1,
+ g_param_spec_boolean ("write-v1", "Write id3v1 tag",
+ "Write an id3v1 tag at the end of the file", DEFAULT_WRITE_V1,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class, ARG_WRITE_V2,
+ g_param_spec_boolean ("write-v2", "Write id3v2 tag",
+ "Write an id3v2 tag at the start of the file", DEFAULT_WRITE_V2,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class, ARG_V2_MAJOR_VERSION,
+ g_param_spec_int ("v2-version", "Version (3 or 4) of id3v2 tag",
+ "Set version (3 for id3v2.3, 4 for id3v2.4) of id3v2 tags",
+ 3, 4, DEFAULT_V2_MAJOR_VERSION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ GST_TAG_MUX_CLASS (klass)->render_start_tag =
+ GST_DEBUG_FUNCPTR (gst_id3_tag_render_v2_tag);
+
+ GST_TAG_MUX_CLASS (klass)->render_end_tag = gst_id3_tag_render_v1_tag;
+}
+
+static void
+gst_id3_tag_init (GstId3Tag * id3mux, GstId3TagClass * id3mux_class)
+{
+ id3mux->write_v1 = DEFAULT_WRITE_V1;
+ id3mux->write_v2 = DEFAULT_WRITE_V2;
+
+ id3mux->v2_major_version = DEFAULT_V2_MAJOR_VERSION;
+}
+
+static void
+gst_id3_tag_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstId3Tag *mux = GST_ID3TAG (object);
+
+ switch (prop_id) {
+ case ARG_WRITE_V1:
+ mux->write_v1 = g_value_get_boolean (value);
+ break;
+ case ARG_WRITE_V2:
+ mux->write_v2 = g_value_get_boolean (value);
+ break;
+ case ARG_V2_MAJOR_VERSION:
+ mux->v2_major_version = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_id3_tag_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstId3Tag *mux = GST_ID3TAG (object);
+
+ switch (prop_id) {
+ case ARG_WRITE_V1:
+ g_value_set_boolean (value, mux->write_v1);
+ break;
+ case ARG_WRITE_V2:
+ g_value_set_boolean (value, mux->write_v2);
+ break;
+ case ARG_V2_MAJOR_VERSION:
+ g_value_set_int (value, mux->v2_major_version);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstBuffer *
+gst_id3_tag_render_v2_tag (GstTagMux * mux, GstTagList * taglist)
+{
+ GstId3Tag *id3mux = GST_ID3TAG (mux);
+
+ if (id3mux->write_v2)
+ return gst_id3mux_render_v2_tag (mux, taglist, id3mux->v2_major_version);
+ else
+ return NULL;
+}
+
+static GstBuffer *
+gst_id3_tag_render_v1_tag (GstTagMux * mux, GstTagList * taglist)
+{
+ GstId3Tag *id3mux = GST_ID3TAG (mux);
+
+ if (id3mux->write_v1)
+ return gst_id3mux_render_v1_tag (mux, taglist);
+ else
+ return NULL;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "id3tag", GST_RANK_NONE, GST_TYPE_ID3TAG))
+ return FALSE;
+
+ gst_tag_register_musicbrainz_tags ();
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "id3tag",
+ "ID3 v1 and v2 muxing plugin",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
diff --git a/gst/id3tag/gstid3tag.h b/gst/id3tag/gstid3tag.h
new file mode 100644
index 00000000..a9a1ad1c
--- /dev/null
+++ b/gst/id3tag/gstid3tag.h
@@ -0,0 +1,63 @@
+/* GStreamer ID3 v1 and v2 muxer
+ *
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * 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_ID3TAG_H
+#define GST_ID3TAG_H
+
+#include "gsttagmux.h"
+#include "id3tag.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstId3Tag GstId3Tag;
+typedef struct _GstId3TagClass GstId3TagClass;
+
+struct _GstId3Tag {
+ GstTagMux tagmux;
+
+ gboolean write_v1;
+ gboolean write_v2;
+
+ gint v2_major_version;
+};
+
+struct _GstId3TagClass {
+ GstTagMuxClass tagmux_class;
+};
+
+#define GST_TYPE_ID3TAG \
+ (gst_id3_tag_get_type())
+#define GST_ID3TAG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ID3TAG,GstId3Tag))
+#define GST_ID3TAG_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ID3TAG,GstId3TagClass))
+#define GST_IS_ID3TAG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ID3TAG))
+#define GST_IS_ID3TAG_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ID3TAG))
+
+GType gst_id3_tag_get_type (void);
+
+G_END_DECLS
+
+#endif /* GST_ID3TAG_H */
+
diff --git a/gst/id3tag/gsttagmux.c b/gst/id3tag/gsttagmux.c
new file mode 100644
index 00000000..3b7ff119
--- /dev/null
+++ b/gst/id3tag/gsttagmux.c
@@ -0,0 +1,495 @@
+/* GStreamer tag muxer base class
+ *
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * 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 <config.h>
+#endif
+
+#include <string.h>
+#include <gst/gsttagsetter.h>
+#include <gst/tag/tag.h>
+
+#include "gsttagmux.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_tag_mux_debug);
+#define GST_CAT_DEFAULT gst_tag_mux_debug
+
+/* Subclass provides a src template and pad. We accept anything as input here,
+ however. */
+
+static GstStaticPadTemplate gst_tag_mux_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("ANY"));
+
+static void
+gst_tag_mux_iface_init (GType tag_type)
+{
+ static const GInterfaceInfo tag_setter_info = {
+ NULL,
+ NULL,
+ NULL
+ };
+
+ g_type_add_interface_static (tag_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
+}
+
+/* make sure to register a less generic type so we can easily move this
+ * GstTagMux base class into -base without causing GType name conflicts */
+typedef GstTagMux GstId3TagMux;
+typedef GstTagMuxClass GstId3TagMuxClass;
+
+GST_BOILERPLATE_FULL (GstId3TagMux, gst_tag_mux,
+ GstElement, GST_TYPE_ELEMENT, gst_tag_mux_iface_init);
+
+
+static GstStateChangeReturn
+gst_tag_mux_change_state (GstElement * element, GstStateChange transition);
+static GstFlowReturn gst_tag_mux_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_tag_mux_sink_event (GstPad * pad, GstEvent * event);
+
+static void
+gst_tag_mux_finalize (GObject * obj)
+{
+ GstTagMux *mux = GST_TAG_MUX (obj);
+
+ if (mux->newsegment_ev) {
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+ }
+
+ if (mux->event_tags) {
+ gst_tag_list_free (mux->event_tags);
+ mux->event_tags = NULL;
+ }
+
+ if (mux->final_tags) {
+ gst_tag_list_free (mux->final_tags);
+ mux->final_tags = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
+static void
+gst_tag_mux_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 (&gst_tag_mux_sink_template));
+
+ GST_DEBUG_CATEGORY_INIT (gst_tag_mux_debug, "tagmux", 0,
+ "tag muxer base class");
+}
+
+static void
+gst_tag_mux_class_init (GstTagMuxClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tag_mux_finalize);
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_tag_mux_change_state);
+}
+
+static void
+gst_tag_mux_init (GstTagMux * mux, GstTagMuxClass * mux_class)
+{
+ GstElementClass *element_klass = GST_ELEMENT_CLASS (mux_class);
+ GstPadTemplate *tmpl;
+
+ /* pad through which data comes in to the element */
+ mux->sinkpad =
+ gst_pad_new_from_static_template (&gst_tag_mux_sink_template, "sink");
+ gst_pad_set_chain_function (mux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_tag_mux_chain));
+ gst_pad_set_event_function (mux->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_tag_mux_sink_event));
+ gst_element_add_pad (GST_ELEMENT (mux), mux->sinkpad);
+
+ /* pad through which data goes out of the element */
+ tmpl = gst_element_class_get_pad_template (element_klass, "src");
+ if (tmpl) {
+ mux->srcpad = gst_pad_new_from_template (tmpl, "src");
+ gst_pad_use_fixed_caps (mux->srcpad);
+ gst_pad_set_caps (mux->srcpad, gst_pad_template_get_caps (tmpl));
+ gst_element_add_pad (GST_ELEMENT (mux), mux->srcpad);
+ }
+
+ mux->render_start_tag = TRUE;
+ mux->render_end_tag = TRUE;
+}
+
+static GstTagList *
+gst_tag_mux_get_tags (GstTagMux * mux)
+{
+ GstTagSetter *tagsetter = GST_TAG_SETTER (mux);
+ const GstTagList *tagsetter_tags;
+ GstTagMergeMode merge_mode;
+
+ if (mux->final_tags)
+ return mux->final_tags;
+
+ tagsetter_tags = gst_tag_setter_get_tag_list (tagsetter);
+ merge_mode = gst_tag_setter_get_tag_merge_mode (tagsetter);
+
+ GST_LOG_OBJECT (mux, "merging tags, merge mode = %d", merge_mode);
+ GST_LOG_OBJECT (mux, "event tags: %" GST_PTR_FORMAT, mux->event_tags);
+ GST_LOG_OBJECT (mux, "set tags: %" GST_PTR_FORMAT, tagsetter_tags);
+
+ mux->final_tags =
+ gst_tag_list_merge (tagsetter_tags, mux->event_tags, merge_mode);
+
+ GST_LOG_OBJECT (mux, "final tags: %" GST_PTR_FORMAT, mux->final_tags);
+
+ return mux->final_tags;
+}
+
+static GstFlowReturn
+gst_tag_mux_render_start_tag (GstTagMux * mux)
+{
+ GstTagMuxClass *klass;
+ GstBuffer *buffer;
+ GstTagList *taglist;
+ GstEvent *event;
+ GstFlowReturn ret;
+
+ taglist = gst_tag_mux_get_tags (mux);
+
+ klass = GST_TAG_MUX_CLASS (G_OBJECT_GET_CLASS (mux));
+
+ if (klass->render_start_tag == NULL)
+ goto no_vfunc;
+
+ buffer = klass->render_start_tag (mux, taglist);
+
+ /* Null buffer is ok, just means we're not outputting anything */
+ if (buffer == NULL) {
+ GST_INFO_OBJECT (mux, "No start tag generated");
+ mux->start_tag_size = 0;
+ return GST_FLOW_OK;
+ }
+
+ mux->start_tag_size = GST_BUFFER_SIZE (buffer);
+ GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes",
+ mux->start_tag_size);
+
+ /* Send newsegment event from byte position 0, so the tag really gets
+ * written to the start of the file, independent of the upstream segment */
+ gst_pad_push_event (mux->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
+
+ /* Send an event about the new tags to downstream elements */
+ /* gst_event_new_tag takes ownership of the list, so use a copy */
+ event = gst_event_new_tag (gst_tag_list_copy (taglist));
+ gst_pad_push_event (mux->srcpad, event);
+
+ GST_BUFFER_OFFSET (buffer) = 0;
+ ret = gst_pad_push (mux->srcpad, buffer);
+
+ mux->current_offset = mux->start_tag_size;
+ mux->max_offset = MAX (mux->max_offset, mux->current_offset);
+
+ return ret;
+
+no_vfunc:
+ {
+ GST_ERROR_OBJECT (mux, "Subclass does not implement "
+ "render_start_tag vfunc!");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstFlowReturn
+gst_tag_mux_render_end_tag (GstTagMux * mux)
+{
+ GstTagMuxClass *klass;
+ GstBuffer *buffer;
+ GstTagList *taglist;
+ GstFlowReturn ret;
+
+ taglist = gst_tag_mux_get_tags (mux);
+
+ klass = GST_TAG_MUX_CLASS (G_OBJECT_GET_CLASS (mux));
+
+ if (klass->render_end_tag == NULL)
+ goto no_vfunc;
+
+ buffer = klass->render_end_tag (mux, taglist);
+
+ if (buffer == NULL) {
+ GST_INFO_OBJECT (mux, "No end tag generated");
+ mux->end_tag_size = 0;
+ return GST_FLOW_OK;
+ }
+
+ mux->end_tag_size = GST_BUFFER_SIZE (buffer);
+ GST_LOG_OBJECT (mux, "tag size = %" G_GSIZE_FORMAT " bytes",
+ mux->end_tag_size);
+
+ /* Send newsegment event from the end of the file, so it gets written there,
+ independent of whatever new segment events upstream has sent us */
+ gst_pad_push_event (mux->srcpad,
+ gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, mux->max_offset,
+ -1, 0));
+
+ GST_BUFFER_OFFSET (buffer) = mux->max_offset;
+ ret = gst_pad_push (mux->srcpad, buffer);
+
+ return ret;
+
+no_vfunc:
+ {
+ GST_ERROR_OBJECT (mux, "Subclass does not implement "
+ "render_end_tag vfunc!");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static GstEvent *
+gst_tag_mux_adjust_event_offsets (GstTagMux * mux,
+ const GstEvent * newsegment_event)
+{
+ GstFormat format;
+ gint64 start, stop, cur;
+
+ gst_event_parse_new_segment ((GstEvent *) newsegment_event, NULL, NULL,
+ &format, &start, &stop, &cur);
+
+ g_assert (format == GST_FORMAT_BYTES);
+
+ if (start != -1)
+ start += mux->start_tag_size;
+ if (stop != -1)
+ stop += mux->start_tag_size;
+ if (cur != -1)
+ cur += mux->start_tag_size;
+
+ GST_DEBUG_OBJECT (mux, "adjusting newsegment event offsets to start=%"
+ G_GINT64_FORMAT ", stop=%" G_GINT64_FORMAT ", cur=%" G_GINT64_FORMAT
+ " (delta = +%" G_GSIZE_FORMAT ")", start, stop, cur, mux->start_tag_size);
+
+ return gst_event_new_new_segment (TRUE, 1.0, format, start, stop, cur);
+}
+
+static GstFlowReturn
+gst_tag_mux_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstTagMux *mux = GST_TAG_MUX (GST_OBJECT_PARENT (pad));
+ GstFlowReturn ret;
+ int length;
+
+ if (mux->render_start_tag) {
+
+ GST_INFO_OBJECT (mux, "Adding tags to stream");
+ ret = gst_tag_mux_render_start_tag (mux);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret));
+ gst_buffer_unref (buffer);
+ return ret;
+ }
+
+ /* Now send the cached newsegment event that we got from upstream */
+ if (mux->newsegment_ev) {
+ gint64 start;
+ GstEvent *newseg;
+
+ GST_DEBUG_OBJECT (mux, "sending cached newsegment event");
+ newseg = gst_tag_mux_adjust_event_offsets (mux, mux->newsegment_ev);
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+
+ gst_event_parse_new_segment (newseg, NULL, NULL, NULL, &start, NULL,
+ NULL);
+
+ gst_pad_push_event (mux->srcpad, newseg);
+ mux->current_offset = start;
+ mux->max_offset = MAX (mux->max_offset, mux->current_offset);
+ } else {
+ /* upstream sent no newsegment event or only one in a non-BYTE format */
+ }
+
+ mux->render_start_tag = FALSE;
+ }
+
+ buffer = gst_buffer_make_metadata_writable (buffer);
+
+ if (GST_BUFFER_OFFSET (buffer) != GST_BUFFER_OFFSET_NONE) {
+ GST_LOG_OBJECT (mux, "Adjusting buffer offset from %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT, GST_BUFFER_OFFSET (buffer),
+ GST_BUFFER_OFFSET (buffer) + mux->start_tag_size);
+ GST_BUFFER_OFFSET (buffer) += mux->start_tag_size;
+ }
+
+ length = GST_BUFFER_SIZE (buffer);
+
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (mux->srcpad));
+ ret = gst_pad_push (mux->srcpad, buffer);
+
+ mux->current_offset += length;
+ mux->max_offset = MAX (mux->max_offset, mux->current_offset);
+
+ return ret;
+}
+
+static gboolean
+gst_tag_mux_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstTagMux *mux;
+ gboolean result;
+
+ mux = GST_TAG_MUX (gst_pad_get_parent (pad));
+ result = FALSE;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_TAG:{
+ GstTagList *tags;
+
+ gst_event_parse_tag (event, &tags);
+
+ GST_INFO_OBJECT (mux, "Got tag event: %" GST_PTR_FORMAT, tags);
+
+ if (mux->event_tags != NULL) {
+ gst_tag_list_insert (mux->event_tags, tags, GST_TAG_MERGE_REPLACE);
+ } else {
+ mux->event_tags = gst_tag_list_copy (tags);
+ }
+
+ GST_INFO_OBJECT (mux, "Event tags are now: %" GST_PTR_FORMAT,
+ mux->event_tags);
+
+ /* just drop the event, we'll push a new tag event in render_start_tag */
+ gst_event_unref (event);
+ result = TRUE;
+ break;
+ }
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat fmt;
+ gint64 start;
+
+ gst_event_parse_new_segment (event, NULL, NULL, &fmt, &start, NULL, NULL);
+
+ if (fmt != GST_FORMAT_BYTES) {
+ GST_WARNING_OBJECT (mux, "dropping newsegment event in %s format",
+ gst_format_get_name (fmt));
+ gst_event_unref (event);
+ break;
+ }
+
+ if (mux->render_start_tag) {
+ /* we have not rendered the tag yet, which means that we don't know
+ * how large it is going to be yet, so we can't adjust the offsets
+ * here at this point and need to cache the newsegment event for now
+ * (also, there could be tag events coming after this newsegment event
+ * and before the first buffer). */
+ if (mux->newsegment_ev) {
+ GST_WARNING_OBJECT (mux, "discarding old cached newsegment event");
+ gst_event_unref (mux->newsegment_ev);
+ }
+
+ GST_LOG_OBJECT (mux, "caching newsegment event for later");
+ mux->newsegment_ev = event;
+ } else {
+ GST_DEBUG_OBJECT (mux, "got newsegment event, adjusting offsets");
+ gst_pad_push_event (mux->srcpad,
+ gst_tag_mux_adjust_event_offsets (mux, event));
+ gst_event_unref (event);
+
+ mux->current_offset = start;
+ mux->max_offset = MAX (mux->max_offset, mux->current_offset);
+ }
+ event = NULL;
+ result = TRUE;
+ break;
+ }
+ case GST_EVENT_EOS:{
+ if (mux->render_end_tag) {
+ GstFlowReturn ret;
+
+ GST_INFO_OBJECT (mux, "Adding tags to stream");
+ ret = gst_tag_mux_render_end_tag (mux);
+ if (ret != GST_FLOW_OK) {
+ GST_DEBUG_OBJECT (mux, "flow: %s", gst_flow_get_name (ret));
+ return ret;
+ }
+
+ mux->render_end_tag = FALSE;
+ }
+
+ /* Now forward EOS */
+ result = gst_pad_event_default (pad, event);
+ break;
+ }
+ default:
+ result = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (mux);
+
+ return result;
+}
+
+
+static GstStateChangeReturn
+gst_tag_mux_change_state (GstElement * element, GstStateChange transition)
+{
+ GstTagMux *mux;
+ GstStateChangeReturn result;
+
+ mux = GST_TAG_MUX (element);
+
+ result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (result != GST_STATE_CHANGE_SUCCESS) {
+ return result;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:{
+ if (mux->newsegment_ev) {
+ gst_event_unref (mux->newsegment_ev);
+ mux->newsegment_ev = NULL;
+ }
+ if (mux->event_tags) {
+ gst_tag_list_free (mux->event_tags);
+ mux->event_tags = NULL;
+ }
+ mux->start_tag_size = 0;
+ mux->end_tag_size = 0;
+ mux->render_start_tag = TRUE;
+ mux->render_end_tag = TRUE;
+ mux->current_offset = 0;
+ mux->max_offset = 0;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return result;
+}
diff --git a/gst/id3tag/gsttagmux.h b/gst/id3tag/gsttagmux.h
new file mode 100644
index 00000000..c13a7326
--- /dev/null
+++ b/gst/id3tag/gsttagmux.h
@@ -0,0 +1,79 @@
+/* GStreamer tag muxer base class
+ *
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * 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_TAG_MUX_H
+#define GST_TAG_MUX_H
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstTagMux GstTagMux;
+typedef struct _GstTagMuxClass GstTagMuxClass;
+
+/* Definition of structure storing data for this element. */
+struct _GstTagMux {
+ GstElement element;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+ GstTagList *event_tags; /* tags received from upstream elements */
+ GstTagList *final_tags; /* Final set of tags used for muxing */
+ gsize start_tag_size;
+ gsize end_tag_size;
+ gboolean render_start_tag;
+ gboolean render_end_tag;
+
+ gint64 current_offset;
+ gint64 max_offset;
+
+ GstEvent *newsegment_ev; /* cached newsegment event from upstream */
+};
+
+/* Standard definition defining a class for this element. */
+struct _GstTagMuxClass {
+ GstElementClass parent_class;
+
+ /* vfuncs */
+ GstBuffer * (*render_start_tag) (GstTagMux * mux, GstTagList * tag_list);
+ GstBuffer * (*render_end_tag) (GstTagMux * mux, GstTagList * tag_list);
+};
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_TAG_MUX \
+ (gst_tag_mux_get_type())
+#define GST_TAG_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAG_MUX,GstTagMux))
+#define GST_TAG_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAG_MUX,GstTagMuxClass))
+#define GST_IS_TAG_MUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAG_MUX))
+#define GST_IS_TAG_MUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAG_MUX))
+
+/* Standard function returning type information. */
+GType gst_tag_mux_get_type (void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/gst/id3tag/id3tag.c b/gst/id3tag/id3tag.c
new file mode 100644
index 00000000..a39e2a8e
--- /dev/null
+++ b/gst/id3tag/id3tag.c
@@ -0,0 +1,1194 @@
+/* GStreamer ID3v2 tag writer
+ *
+ * Copyright (C) 2006 Christophe Fergeau <teuf@gnome.org>
+ * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2009 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "id3tag.h"
+#include <string.h>
+
+#include <gst/tag/tag.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_id3_tag_debug);
+#define GST_CAT_DEFAULT gst_id3_tag_debug
+
+#define ID3V2_APIC_PICTURE_OTHER 0
+#define ID3V2_APIC_PICTURE_FILE_ICON 1
+
+/* ======================================================================== */
+
+typedef GString GstByteWriter;
+
+static inline GstByteWriter *
+gst_byte_writer_new (guint size)
+{
+ return (GstByteWriter *) g_string_sized_new (size);
+}
+
+static inline guint
+gst_byte_writer_get_length (GstByteWriter * w)
+{
+ return ((GString *) w)->len;
+}
+
+static inline void
+gst_byte_writer_write_bytes (GstByteWriter * w, const guint8 * data, guint len)
+{
+ g_string_append_len ((GString *) w, (const gchar *) data, len);
+}
+
+static inline void
+gst_byte_writer_write_uint8 (GstByteWriter * w, guint8 val)
+{
+ guint8 data[1];
+
+ GST_WRITE_UINT8 (data, val);
+ gst_byte_writer_write_bytes (w, data, 1);
+}
+
+static inline void
+gst_byte_writer_write_uint16 (GstByteWriter * w, guint16 val)
+{
+ guint8 data[2];
+
+ GST_WRITE_UINT16_BE (data, val);
+ gst_byte_writer_write_bytes (w, data, 2);
+}
+
+static inline void
+gst_byte_writer_write_uint32 (GstByteWriter * w, guint32 val)
+{
+ guint8 data[4];
+
+ GST_WRITE_UINT32_BE (data, val);
+ gst_byte_writer_write_bytes (w, data, 4);
+}
+
+static inline void
+gst_byte_writer_write_uint32_syncsafe (GstByteWriter * w, guint32 val)
+{
+ guint8 data[4];
+
+ data[0] = (guint8) ((val >> 21) & 0x7f);
+ data[1] = (guint8) ((val >> 14) & 0x7f);
+ data[2] = (guint8) ((val >> 7) & 0x7f);
+ data[3] = (guint8) ((val >> 0) & 0x7f);
+ gst_byte_writer_write_bytes (w, data, 4);
+}
+
+static void
+gst_byte_writer_copy_bytes (GstByteWriter * w, guint8 * dest, guint offset,
+ gint size)
+{
+ guint length;
+
+ length = gst_byte_writer_get_length (w);
+
+ if (size == -1)
+ size = length - offset;
+
+#if GLIB_CHECK_VERSION(2,16,0)
+ g_warn_if_fail (length >= (offset + size));
+#endif
+
+ memcpy (dest, w->str + offset, MIN (size, length - offset));
+}
+
+static inline void
+gst_byte_writer_free (GstByteWriter * w)
+{
+ g_string_free (w, TRUE);
+}
+
+/* ======================================================================== */
+
+/*
+typedef enum {
+ GST_ID3V2_FRAME_FLAG_NONE = 0,
+ GST_ID3V2_FRAME_FLAG_
+} GstID3v2FrameMsgFlags;
+*/
+
+typedef struct
+{
+ gchar id[5];
+ guint32 len; /* Length encoded in the header; this is the
+ total length - header size */
+ guint16 flags;
+ GstByteWriter *writer;
+ gboolean dirty; /* TRUE if frame header needs updating */
+} GstId3v2Frame;
+
+typedef struct
+{
+ GArray *frames;
+ guint major_version; /* The 3 in v2.3.0 */
+} GstId3v2Tag;
+
+typedef void (*GstId3v2AddTagFunc) (GstId3v2Tag * tag, const GstTagList * list,
+ const gchar * gst_tag, guint num_tags, const gchar * data);
+
+#define ID3V2_ENCODING_UTF8 0x03
+
+static gboolean id3v2_tag_init (GstId3v2Tag * tag, guint major_version);
+static void id3v2_tag_unset (GstId3v2Tag * tag);
+
+static void id3v2_frame_init (GstId3v2Frame * frame,
+ const gchar * frame_id, guint16 flags);
+static void id3v2_frame_unset (GstId3v2Frame * frame);
+static void id3v2_frame_finish (GstId3v2Tag * tag, GstId3v2Frame * frame);
+static guint id3v2_frame_get_size (GstId3v2Tag * tag, GstId3v2Frame * frame);
+
+static void id3v2_tag_add_text_frame (GstId3v2Tag * tag,
+ const gchar * frame_id, gchar ** strings, int num_strings);
+
+static gboolean
+id3v2_tag_init (GstId3v2Tag * tag, guint major_version)
+{
+ if (major_version != 3 && major_version != 4)
+ return FALSE;
+
+ tag->major_version = major_version;
+ tag->frames = g_array_new (TRUE, TRUE, sizeof (GstId3v2Frame));
+
+ return TRUE;
+}
+
+static void
+id3v2_tag_unset (GstId3v2Tag * tag)
+{
+ guint i;
+
+ for (i = 0; i < tag->frames->len; ++i)
+ id3v2_frame_unset (&g_array_index (tag->frames, GstId3v2Frame, i));
+
+ g_array_free (tag->frames, TRUE);
+ memset (tag, 0, sizeof (GstId3v2Tag));
+}
+
+#ifndef GST_ROUND_UP_1024
+#define GST_ROUND_UP_1024(num) (((num)+1023)&~1023)
+#endif
+
+static GstBuffer *
+id3v2_tag_to_buffer (GstId3v2Tag * tag)
+{
+ GstByteWriter *w;
+ GstBuffer *buf;
+ guint8 *dest;
+ guint i, size, offset, size_frames = 0;
+
+ GST_DEBUG ("Creating buffer for ID3v2 tag containing %d frames",
+ tag->frames->len);
+
+ for (i = 0; i < tag->frames->len; ++i) {
+ GstId3v2Frame *frame = &g_array_index (tag->frames, GstId3v2Frame, i);
+
+ id3v2_frame_finish (tag, frame);
+ size_frames += id3v2_frame_get_size (tag, frame);
+ }
+
+ size = GST_ROUND_UP_1024 (10 + size_frames);
+
+ w = gst_byte_writer_new (10);
+ gst_byte_writer_write_uint8 (w, 'I');
+ gst_byte_writer_write_uint8 (w, 'D');
+ gst_byte_writer_write_uint8 (w, '3');
+ gst_byte_writer_write_uint8 (w, tag->major_version);
+ gst_byte_writer_write_uint8 (w, 0); /* micro version */
+ gst_byte_writer_write_uint8 (w, 0); /* flags */
+ gst_byte_writer_write_uint32_syncsafe (w, size - 10);
+
+ buf = gst_buffer_new_and_alloc (size);
+ dest = GST_BUFFER_DATA (buf);
+ gst_byte_writer_copy_bytes (w, dest, 0, 10);
+ offset = 10;
+
+ for (i = 0; i < tag->frames->len; ++i) {
+ GstId3v2Frame *frame = &g_array_index (tag->frames, GstId3v2Frame, i);
+
+ gst_byte_writer_copy_bytes (frame->writer, dest + offset, 0, -1);
+ offset += id3v2_frame_get_size (tag, frame);
+ }
+
+ /* Zero out any additional space in our buffer as padding. */
+ memset (dest + offset, 0, size - offset);
+
+ gst_byte_writer_free (w);
+
+ return buf;
+}
+
+static inline void
+id3v2_frame_write_bytes (GstId3v2Frame * frame, const guint8 * data, guint len)
+{
+ gst_byte_writer_write_bytes (frame->writer, data, len);
+ frame->dirty = TRUE;
+}
+
+static inline void
+id3v2_frame_write_uint8 (GstId3v2Frame * frame, guint8 val)
+{
+ gst_byte_writer_write_uint8 (frame->writer, val);
+ frame->dirty = TRUE;
+}
+
+static inline void
+id3v2_frame_write_uint16 (GstId3v2Frame * frame, guint16 val)
+{
+ gst_byte_writer_write_uint16 (frame->writer, val);
+ frame->dirty = TRUE;
+}
+
+static inline void
+id3v2_frame_write_uint32 (GstId3v2Frame * frame, guint32 val)
+{
+ gst_byte_writer_write_uint32 (frame->writer, val);
+ frame->dirty = TRUE;
+}
+
+static inline void
+id3v2_frame_write_uint32_syncsafe (GstId3v2Frame * frame, guint32 val)
+{
+ guint8 data[4];
+
+ data[0] = (guint8) ((val >> 21) & 0x7f);
+ data[1] = (guint8) ((val >> 14) & 0x7f);
+ data[2] = (guint8) ((val >> 7) & 0x7f);
+ data[3] = (guint8) ((val >> 0) & 0x7f);
+ gst_byte_writer_write_bytes (frame->writer, data, 4);
+ frame->dirty = TRUE;
+}
+
+static void
+id3v2_frame_init (GstId3v2Frame * frame, const gchar * frame_id, guint16 flags)
+{
+ g_assert (strlen (frame_id) == 4); /* we only handle 2.3.0/2.4.0 */
+ memcpy (frame->id, frame_id, 4 + 1);
+ frame->flags = flags;
+ frame->len = 0;
+ frame->writer = gst_byte_writer_new (64);
+ id3v2_frame_write_bytes (frame, (const guint8 *) frame->id, 4);
+ id3v2_frame_write_uint32 (frame, 0); /* size, set later */
+ id3v2_frame_write_uint16 (frame, frame->flags);
+}
+
+static void
+id3v2_frame_finish (GstId3v2Tag * tag, GstId3v2Frame * frame)
+{
+ if (frame->dirty) {
+ frame->len = frame->writer->len - 10;
+ GST_LOG ("[%s] %u bytes", frame->id, frame->len);
+ if (tag->major_version == 3) {
+ GST_WRITE_UINT32_BE (frame->writer->str + 4, frame->len);
+ } else {
+ /* Version 4 uses a syncsafe int here */
+ GST_WRITE_UINT8 (frame->writer->str + 4, (frame->len >> 21) & 0x7f);
+ GST_WRITE_UINT8 (frame->writer->str + 5, (frame->len >> 14) & 0x7f);
+ GST_WRITE_UINT8 (frame->writer->str + 6, (frame->len >> 7) & 0x7f);
+ GST_WRITE_UINT8 (frame->writer->str + 7, (frame->len >> 0) & 0x7f);
+ }
+ frame->dirty = FALSE;
+ }
+}
+
+static guint
+id3v2_frame_get_size (GstId3v2Tag * tag, GstId3v2Frame * frame)
+{
+ id3v2_frame_finish (tag, frame);
+ return gst_byte_writer_get_length (frame->writer);
+}
+
+static void
+id3v2_frame_unset (GstId3v2Frame * frame)
+{
+ gst_byte_writer_free (frame->writer);
+ memset (frame, 0, sizeof (GstId3v2Frame));
+}
+
+static void
+id3v2_tag_add_text_frame (GstId3v2Tag * tag, const gchar * frame_id,
+ gchar ** strings_utf8, int num_strings)
+{
+ GstId3v2Frame frame;
+ guint len, i;
+
+ if (num_strings < 1 || strings_utf8 == NULL || strings_utf8[0] == NULL) {
+ GST_LOG ("Not adding text frame, no strings");
+ return;
+ }
+
+ id3v2_frame_init (&frame, frame_id, 0);
+ id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8);
+
+ GST_LOG ("Adding text frame %s with %d strings", frame_id, num_strings);
+
+ for (i = 0; i < num_strings; ++i) {
+ len = strlen (strings_utf8[i]);
+ g_return_if_fail (g_utf8_validate (strings_utf8[i], len, NULL));
+
+ /* write NUL terminator as well */
+ id3v2_frame_write_bytes (&frame, (const guint8 *) strings_utf8[i], len + 1);
+
+ /* only v2.4.0 supports multiple strings per frame (according to the
+ * earlier specs tag readers should just ignore everything after the first
+ * string, but we probably shouldn't write anything there, just in case
+ * tag readers that only support the old version are not expecting
+ * more data after the first string) */
+ if (tag->major_version < 4)
+ break;
+ }
+
+ if (i < num_strings - 1) {
+ GST_WARNING ("Only wrote one of multiple string values for text frame %s "
+ "- ID3v2 supports multiple string values only since v2.4.0, but writing"
+ "v2.%u.0 tag", frame_id, tag->major_version);
+ }
+
+ g_array_append_val (tag->frames, frame);
+}
+
+/* ====================================================================== */
+
+static void
+add_text_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ gchar **strings;
+ guint n, i;
+
+ GST_LOG ("Adding '%s' frame", frame_id);
+
+ strings = g_new0 (gchar *, num_tags + 1);
+ for (n = 0, i = 0; n < num_tags; ++n) {
+ if (gst_tag_list_get_string_index (list, tag, n, &strings[i]) &&
+ strings[i] != NULL) {
+ GST_LOG ("%s: %s[%u] = '%s'", frame_id, tag, i, strings[i]);
+ ++i;
+ }
+ }
+
+ if (strings[0] != NULL) {
+ id3v2_tag_add_text_frame (id3v2tag, frame_id, strings, i);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+
+ g_strfreev (strings);
+}
+
+static void
+add_id3v2frame_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint i;
+
+ for (i = 0; i < num_tags; ++i) {
+ const GValue *val;
+ GstBuffer *buf;
+
+ val = gst_tag_list_get_value_index (list, tag, i);
+ buf = (GstBuffer *) gst_value_get_mini_object (val);
+
+ if (buf && GST_BUFFER_CAPS (buf)) {
+ GstStructure *s;
+ gint version = 0;
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
+ /* We can only add it if this private buffer is for the same ID3 version,
+ because we don't understand the contents at all. */
+ if (s && gst_structure_get_int (s, "version", &version) &&
+ version == id3v2tag->major_version) {
+ GstId3v2Frame frame;
+ gchar frame_id[5];
+ guint16 flags;
+ guint8 *data = GST_BUFFER_DATA (buf);
+ gint size = GST_BUFFER_SIZE (buf);
+
+ if (size < 10) /* header size */
+ return;
+
+ /* We only reach here if the frame version matches the muxer. Since the
+ muxer only does v2.3 or v2.4, the frame must be one of those - and
+ so the frame header is the same format */
+ memcpy (frame_id, data, 4);
+ frame_id[4] = 0;
+ flags = GST_READ_UINT16_BE (data + 8);
+
+ id3v2_frame_init (&frame, frame_id, flags);
+ id3v2_frame_write_bytes (&frame, data + 10, size - 10);
+
+ g_array_append_val (id3v2tag->frames, frame);
+ GST_DEBUG ("Added unparsed tag with %d bytes", size);
+ } else {
+ GST_WARNING ("Discarding unrecognised ID3 tag for different ID3 "
+ "version");
+ }
+ }
+ }
+}
+
+static void
+add_text_tag_v4 (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ if (id3v2tag->major_version == 4)
+ add_text_tag (id3v2tag, list, tag, num_tags, frame_id);
+ else {
+ GST_WARNING ("Cannot serialise tag '%s' in ID3v2.%d", frame_id,
+ id3v2tag->major_version);
+ }
+}
+
+static void
+add_count_or_num_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ static const struct
+ {
+ const gchar *gst_tag;
+ const gchar *corr_count; /* corresponding COUNT tag (if number) */
+ const gchar *corr_num; /* corresponding NUMBER tag (if count) */
+ } corr[] = {
+ {
+ GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, NULL}, {
+ GST_TAG_TRACK_COUNT, NULL, GST_TAG_TRACK_NUMBER}, {
+ GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, NULL}, {
+ GST_TAG_ALBUM_VOLUME_COUNT, NULL, GST_TAG_ALBUM_VOLUME_NUMBER}
+ };
+ guint idx;
+
+ for (idx = 0; idx < G_N_ELEMENTS (corr); ++idx) {
+ if (strcmp (corr[idx].gst_tag, tag) == 0)
+ break;
+ }
+
+ g_assert (idx < G_N_ELEMENTS (corr));
+ g_assert (frame_id && strlen (frame_id) == 4);
+
+ if (corr[idx].corr_num == NULL) {
+ guint number;
+
+ /* number tag */
+ if (gst_tag_list_get_uint_index (list, tag, 0, &number)) {
+ gchar *tag_str;
+ guint count;
+
+ if (gst_tag_list_get_uint_index (list, corr[idx].corr_count, 0, &count))
+ tag_str = g_strdup_printf ("%u/%u", number, count);
+ else
+ tag_str = g_strdup_printf ("%u", number);
+
+ GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+
+ id3v2_tag_add_text_frame (id3v2tag, frame_id, &tag_str, 1);
+ g_free (tag_str);
+ }
+ } else if (corr[idx].corr_count == NULL) {
+ guint count;
+
+ /* count tag */
+ if (gst_tag_list_get_uint_index (list, corr[idx].corr_num, 0, &count)) {
+ GST_DEBUG ("%s handled with %s, skipping", tag, corr[idx].corr_num);
+ } else if (gst_tag_list_get_uint_index (list, tag, 0, &count)) {
+ gchar *tag_str = g_strdup_printf ("0/%u", count);
+ GST_DEBUG ("Setting %s to %s (frame_id = %s)", tag, tag_str, frame_id);
+
+ id3v2_tag_add_text_frame (id3v2tag, frame_id, &tag_str, 1);
+ g_free (tag_str);
+ }
+ }
+
+ if (num_tags > 1) {
+ GST_WARNING ("more than one %s, can only handle one", tag);
+ }
+}
+
+static void
+add_comment_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint n;
+
+ GST_LOG ("Adding comment frames");
+ for (n = 0; n < num_tags; ++n) {
+ gchar *s = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, n, &s) && s != NULL) {
+ gchar *desc = NULL, *val = NULL, *lang = NULL;
+ int desclen, vallen;
+ GstId3v2Frame frame;
+
+ id3v2_frame_init (&frame, "COMM", 0);
+ id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8);
+
+ if (strcmp (tag, GST_TAG_COMMENT) == 0 ||
+ !gst_tag_parse_extended_comment (s, &desc, &lang, &val, TRUE)) {
+ /* create dummy description fields */
+ desc = g_strdup ("Comment");
+ val = g_strdup (s);
+ }
+
+ /* If we don't have a valid language, match what taglib does for
+ unknown languages */
+ if (!lang || strlen (lang) < 3)
+ lang = g_strdup ("XXX");
+
+ desclen = strlen (desc);
+ g_return_if_fail (g_utf8_validate (desc, desclen, NULL));
+ vallen = strlen (val);
+ g_return_if_fail (g_utf8_validate (val, vallen, NULL));
+
+ GST_LOG ("%s[%u] = '%s' (%s|%s|%s)", tag, n, s, GST_STR_NULL (desc),
+ GST_STR_NULL (lang), GST_STR_NULL (val));
+
+ id3v2_frame_write_bytes (&frame, (const guint8 *) lang, 3);
+ /* write description and value, each including NULL terminator */
+ id3v2_frame_write_bytes (&frame, (const guint8 *) desc, desclen + 1);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) val, vallen + 1);
+
+ g_free (lang);
+ g_free (desc);
+ g_free (val);
+
+ g_array_append_val (id3v2tag->frames, frame);
+ }
+ g_free (s);
+ }
+}
+
+static void
+add_image_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint n;
+
+ for (n = 0; n < num_tags; ++n) {
+ const GValue *val;
+ GstBuffer *image;
+
+ GST_DEBUG ("image %u/%u", n + 1, num_tags);
+
+ val = gst_tag_list_get_value_index (list, tag, n);
+ image = (GstBuffer *) gst_value_get_mini_object (val);
+
+ if (GST_IS_BUFFER (image) && GST_BUFFER_SIZE (image) > 0 &&
+ GST_BUFFER_CAPS (image) != NULL &&
+ !gst_caps_is_empty (GST_BUFFER_CAPS (image))) {
+ const gchar *mime_type;
+ GstStructure *s;
+
+ s = gst_caps_get_structure (GST_BUFFER_CAPS (image), 0);
+ mime_type = gst_structure_get_name (s);
+ if (mime_type != NULL) {
+ const gchar *desc;
+ GstId3v2Frame frame;
+
+ /* APIC frame specifies "-->" if we're providing a URL to the image
+ rather than directly embedding it */
+ if (strcmp (mime_type, "text/uri-list") == 0)
+ mime_type = "-->";
+
+ GST_DEBUG ("Attaching picture of %u bytes and mime type %s",
+ GST_BUFFER_SIZE (image), mime_type);
+
+ id3v2_frame_init (&frame, "APIC", 0);
+ id3v2_frame_write_uint8 (&frame, ID3V2_ENCODING_UTF8);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) mime_type,
+ strlen (mime_type) + 1);
+
+ /* FIXME set image type properly from caps */
+ if (strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0)
+ id3v2_frame_write_uint8 (&frame, ID3V2_APIC_PICTURE_FILE_ICON);
+ else
+ id3v2_frame_write_uint8 (&frame, ID3V2_APIC_PICTURE_OTHER);
+
+ desc = gst_structure_get_string (s, "image-description");
+ if (!desc)
+ desc = "";
+ id3v2_frame_write_bytes (&frame, (const guint8 *) desc,
+ strlen (desc) + 1);
+
+ g_array_append_val (id3v2tag->frames, frame);
+ }
+ } else {
+ GST_WARNING ("NULL image or no caps on image buffer (%p, caps=%"
+ GST_PTR_FORMAT ")", image, (image) ? GST_BUFFER_CAPS (image) : NULL);
+ }
+ }
+}
+
+static void
+add_musicbrainz_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * data)
+{
+ static const struct
+ {
+ const gchar gst_tag[28];
+ const gchar spec_id[28];
+ const gchar realworld_id[28];
+ } mb_ids[] = {
+ {
+ GST_TAG_MUSICBRAINZ_ARTISTID, "MusicBrainz Artist Id",
+ "musicbrainz_artistid"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMID, "MusicBrainz Album Id", "musicbrainz_albumid"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMARTISTID, "MusicBrainz Album Artist Id",
+ "musicbrainz_albumartistid"}, {
+ GST_TAG_MUSICBRAINZ_TRMID, "MusicBrainz TRM Id", "musicbrainz_trmid"}, {
+ GST_TAG_CDDA_MUSICBRAINZ_DISCID, "MusicBrainz DiscID",
+ "musicbrainz_discid"}, {
+ /* the following one is more or less made up, there seems to be little
+ * evidence that any popular application is actually putting this info
+ * into TXXX frames; the first one comes from a musicbrainz wiki 'proposed
+ * tags' page, the second one is analogue to the vorbis/ape/flac tag. */
+ GST_TAG_CDDA_CDDB_DISCID, "CDDB DiscID", "discid"}
+ };
+ guint i, idx;
+
+ idx = (guint8) data[0];
+ g_assert (idx < G_N_ELEMENTS (mb_ids));
+
+ for (i = 0; i < num_tags; ++i) {
+ gchar *id_str;
+
+ if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+ /* add two frames, one with the ID the musicbrainz.org spec mentions
+ * and one with the ID that applications use in the real world */
+ GstId3v2Frame frame1, frame2;
+
+ GST_DEBUG ("Setting '%s' to '%s'", mb_ids[idx].spec_id, id_str);
+
+ id3v2_frame_init (&frame1, "TXXX", 0);
+ id3v2_frame_write_uint8 (&frame1, ID3V2_ENCODING_UTF8);
+ id3v2_frame_write_bytes (&frame1, (const guint8 *) mb_ids[idx].spec_id,
+ strlen (mb_ids[idx].spec_id) + 1);
+ id3v2_frame_write_bytes (&frame1, (const guint8 *) id_str,
+ strlen (id_str) + 1);
+ g_array_append_val (id3v2tag->frames, frame1);
+
+ id3v2_frame_init (&frame2, "TXXX", 0);
+ id3v2_frame_write_uint8 (&frame2, ID3V2_ENCODING_UTF8);
+ id3v2_frame_write_bytes (&frame2,
+ (const guint8 *) mb_ids[idx].realworld_id,
+ strlen (mb_ids[idx].realworld_id) + 1);
+ id3v2_frame_write_bytes (&frame2, (const guint8 *) id_str,
+ strlen (id_str) + 1);
+ g_array_append_val (id3v2tag->frames, frame2);
+
+ g_free (id_str);
+ }
+ }
+}
+
+static void
+add_unique_file_id_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ const gchar *origin = "http://musicbrainz.org";
+ gchar *id_str = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, 0, &id_str) && id_str) {
+ GstId3v2Frame frame;
+
+ GST_LOG ("Adding %s (%s): %s", tag, origin, id_str);
+
+ id3v2_frame_init (&frame, "UFID", 0);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) origin,
+ strlen (origin) + 1);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) id_str,
+ strlen (id_str) + 1);
+ g_array_append_val (id3v2tag->frames, frame);
+
+ g_free (id_str);
+ }
+}
+
+static void
+add_date_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint n;
+ guint i = 0;
+ const gchar *frame_id;
+ gchar **strings;
+
+ if (id3v2tag->major_version == 3)
+ frame_id = "TYER";
+ else
+ frame_id = "TDRC";
+
+ GST_LOG ("Adding date frame");
+
+ strings = g_new0 (gchar *, num_tags + 1);
+ for (n = 0; n < num_tags; ++n) {
+ GDate *date = NULL;
+
+ if (gst_tag_list_get_date_index (list, tag, n, &date) && date != NULL) {
+ GDateYear year;
+ gchar *s;
+
+ year = g_date_get_year (date);
+ if (year > 500 && year < 2100) {
+ s = g_strdup_printf ("%u", year);
+ GST_LOG ("%s[%u] = '%s'", tag, n, s);
+ strings[i] = s;
+ i++;
+ } else {
+ GST_WARNING ("invalid year %u, skipping", year);
+ }
+
+ g_date_free (date);
+ }
+ }
+
+ if (strings[0] != NULL) {
+ id3v2_tag_add_text_frame (id3v2tag, frame_id, strings, i);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+
+ g_strfreev (strings);
+}
+
+static void
+add_encoder_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ guint n;
+ gchar **strings;
+ int i = 0;
+
+ /* ENCODER_VERSION is either handled with the ENCODER tag or not at all */
+ if (strcmp (tag, GST_TAG_ENCODER_VERSION) == 0)
+ return;
+
+ strings = g_new0 (gchar *, num_tags + 1);
+ for (n = 0; n < num_tags; ++n) {
+ gchar *encoder = NULL;
+
+ if (gst_tag_list_get_string_index (list, tag, n, &encoder) && encoder) {
+ guint encoder_version;
+ gchar *s;
+
+ if (gst_tag_list_get_uint_index (list, GST_TAG_ENCODER_VERSION, n,
+ &encoder_version) && encoder_version > 0) {
+ s = g_strdup_printf ("%s %u", encoder, encoder_version);
+ } else {
+ s = g_strdup (encoder);
+ }
+
+ GST_LOG ("encoder[%u] = '%s'", n, s);
+ strings[i] = s;
+ i++;
+ g_free (encoder);
+ }
+ }
+
+ if (strings[0] != NULL) {
+ id3v2_tag_add_text_frame (id3v2tag, "TSSE", strings, i);
+ } else {
+ GST_WARNING ("Empty list for tag %s, skipping", tag);
+ }
+
+ g_strfreev (strings);
+}
+
+static void
+add_uri_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * frame_id)
+{
+ gchar *url = NULL;
+
+ g_assert (frame_id != NULL);
+
+ /* URI tags are limited to one of each per taglist */
+ if (gst_tag_list_get_string_index (list, tag, 0, &url) && url != NULL) {
+ guint url_len;
+
+ url_len = strlen (url);
+ if (url_len > 0 && gst_uri_is_valid (url)) {
+ GstId3v2Frame frame;
+
+ id3v2_frame_init (&frame, frame_id, 0);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) url, strlen (url) + 1);
+ g_array_append_val (id3v2tag->frames, frame);
+ } else {
+ GST_WARNING ("Tag %s does not contain a valid URI (%s)", tag, url);
+ }
+
+ g_free (url);
+ }
+}
+
+static void
+add_relative_volume_tag (GstId3v2Tag * id3v2tag, const GstTagList * list,
+ const gchar * tag, guint num_tags, const gchar * unused)
+{
+ const char *gain_tag_name;
+ const char *peak_tag_name;
+ gdouble peak_val;
+ gdouble gain_val;
+ const char *identification;
+ guint16 peak_int;
+ gint16 gain_int;
+ guint8 peak_bits;
+ GstId3v2Frame frame;
+ gchar *frame_id;
+
+ /* figure out tag names and the identification string to use */
+ if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+ strcmp (tag, GST_TAG_TRACK_GAIN) == 0) {
+ gain_tag_name = GST_TAG_TRACK_GAIN;
+ peak_tag_name = GST_TAG_TRACK_PEAK;
+ identification = "track";
+ GST_DEBUG ("adding track relative-volume frame");
+ } else {
+ gain_tag_name = GST_TAG_ALBUM_GAIN;
+ peak_tag_name = GST_TAG_ALBUM_PEAK;
+ identification = "album";
+
+ if (id3v2tag->major_version == 3) {
+ GST_WARNING ("Cannot store replaygain album gain data in ID3v2.3");
+ return;
+ }
+ GST_DEBUG ("adding album relative-volume frame");
+ }
+
+ /* find the value for the paired tag (gain, if this is peak, and
+ * vice versa). if both tags exist, only write the frame when
+ * we're processing the peak tag.
+ */
+ if (strcmp (tag, GST_TAG_TRACK_PEAK) == 0 ||
+ strcmp (tag, GST_TAG_ALBUM_PEAK) == 0) {
+
+ gst_tag_list_get_double (list, tag, &peak_val);
+
+ if (gst_tag_list_get_tag_size (list, gain_tag_name) > 0) {
+ gst_tag_list_get_double (list, gain_tag_name, &gain_val);
+ GST_DEBUG ("setting volume adjustment %g", gain_val);
+ gain_int = (gint16) (gain_val * 512.0);
+ } else
+ gain_int = 0;
+
+ /* copying mutagen: always write as 16 bits for sanity. */
+ peak_int = (short) (peak_val * G_MAXSHORT);
+ peak_bits = 16;
+ } else {
+ gst_tag_list_get_double (list, tag, &gain_val);
+ GST_DEBUG ("setting volume adjustment %g", gain_val);
+
+ gain_int = (gint16) (gain_val * 512.0);
+ peak_bits = 0;
+ peak_int = 0;
+
+ if (gst_tag_list_get_tag_size (list, peak_tag_name) != 0) {
+ GST_DEBUG
+ ("both gain and peak tags exist, not adding frame this time around");
+ return;
+ }
+ }
+
+ if (id3v2tag->major_version == 4) {
+ /* 2.4: Use RVA2 tag */
+ frame_id = "RVA2";
+ } else {
+ /* 2.3: Use XRVA tag - this is experimental, but useful in the real world.
+ This version only officially supports the 'RVAD' tag, but that appears
+ to not be widely implemented in reality. */
+ frame_id = "XRVA";
+ }
+
+ id3v2_frame_init (&frame, frame_id, 0);
+ id3v2_frame_write_bytes (&frame, (const guint8 *) identification,
+ strlen (identification) + 1);
+ id3v2_frame_write_uint8 (&frame, 0x01); /* Master volume */
+ id3v2_frame_write_uint16 (&frame, gain_int);
+ id3v2_frame_write_uint8 (&frame, peak_bits);
+ if (peak_bits)
+ id3v2_frame_write_uint16 (&frame, peak_int);
+
+ g_array_append_val (id3v2tag->frames, frame);
+}
+
+/* id3demux produces these for frames it cannot parse */
+#define GST_ID3_DEMUX_TAG_ID3V2_FRAME "private-id3v2-frame"
+
+static const struct
+{
+ const gchar *gst_tag;
+ const GstId3v2AddTagFunc func;
+ const gchar *data;
+} add_funcs[] = {
+ {
+ /* Simple text tags */
+ GST_TAG_ARTIST, add_text_tag, "TPE1"}, {
+ GST_TAG_TITLE, add_text_tag, "TIT2"}, {
+ GST_TAG_ALBUM, add_text_tag, "TALB"}, {
+ GST_TAG_COPYRIGHT, add_text_tag, "TCOP"}, {
+ GST_TAG_COMPOSER, add_text_tag, "TCOM"}, {
+ GST_TAG_GENRE, add_text_tag, "TCON"}, {
+
+ /* Private frames */
+ GST_ID3_DEMUX_TAG_ID3V2_FRAME, add_id3v2frame_tag, NULL}, {
+
+ /* Track and album numbers */
+ GST_TAG_TRACK_NUMBER, add_count_or_num_tag, "TRCK"}, {
+ GST_TAG_TRACK_COUNT, add_count_or_num_tag, "TRCK"}, {
+ GST_TAG_ALBUM_VOLUME_NUMBER, add_count_or_num_tag, "TPOS"}, {
+ GST_TAG_ALBUM_VOLUME_COUNT, add_count_or_num_tag, "TPOS"}, {
+
+ /* Comment tags */
+ GST_TAG_COMMENT, add_comment_tag, NULL}, {
+ GST_TAG_EXTENDED_COMMENT, add_comment_tag, NULL}, {
+
+ /* Images */
+ GST_TAG_IMAGE, add_image_tag, NULL}, {
+ GST_TAG_PREVIEW_IMAGE, add_image_tag, NULL}, {
+
+ /* Misc user-defined text tags for IDs (and UFID frame) */
+ GST_TAG_MUSICBRAINZ_ARTISTID, add_musicbrainz_tag, "\000"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMID, add_musicbrainz_tag, "\001"}, {
+ GST_TAG_MUSICBRAINZ_ALBUMARTISTID, add_musicbrainz_tag, "\002"}, {
+ GST_TAG_MUSICBRAINZ_TRMID, add_musicbrainz_tag, "\003"}, {
+ GST_TAG_CDDA_MUSICBRAINZ_DISCID, add_musicbrainz_tag, "\004"}, {
+ GST_TAG_CDDA_CDDB_DISCID, add_musicbrainz_tag, "\005"}, {
+ GST_TAG_MUSICBRAINZ_TRACKID, add_unique_file_id_tag, NULL}, {
+
+ /* Info about encoder */
+ GST_TAG_ENCODER, add_encoder_tag, NULL}, {
+ GST_TAG_ENCODER_VERSION, add_encoder_tag, NULL}, {
+
+ /* URIs */
+ GST_TAG_COPYRIGHT_URI, add_uri_tag, "WCOP"}, {
+ GST_TAG_LICENSE_URI, add_uri_tag, "WCOP"}, {
+
+ /* Up to here, all the frame ids and contents have been the same between
+ versions 2.3 and 2.4. The rest of them differ... */
+ /* Date (in ID3v2.3, this is a TYER tag. In v2.4, it's a TDRC tag */
+ GST_TAG_DATE, add_date_tag, NULL}, {
+
+ /* Replaygain data (not really supported in 2.3, we use an experimental
+ tag there) */
+ GST_TAG_TRACK_PEAK, add_relative_volume_tag, NULL}, {
+ GST_TAG_TRACK_GAIN, add_relative_volume_tag, NULL}, {
+ GST_TAG_ALBUM_PEAK, add_relative_volume_tag, NULL}, {
+ GST_TAG_ALBUM_GAIN, add_relative_volume_tag, NULL}, {
+
+ /* Sortable version of various tags. These are all v2.4 ONLY */
+ GST_TAG_ARTIST_SORTNAME, add_text_tag_v4, "TSOP"}, {
+ GST_TAG_ALBUM_SORTNAME, add_text_tag_v4, "TSOA"}, {
+ GST_TAG_TITLE_SORTNAME, add_text_tag_v4, "TSOT"}
+};
+
+static void
+foreach_add_tag (const GstTagList * list, const gchar * tag, gpointer userdata)
+{
+ GstId3v2Tag *id3v2tag = (GstId3v2Tag *) userdata;
+ guint num_tags, i;
+
+ num_tags = gst_tag_list_get_tag_size (list, tag);
+
+ GST_LOG ("Processing tag %s (num=%u)", tag, num_tags);
+
+ if (num_tags > 1 && gst_tag_is_fixed (tag)) {
+ GST_WARNING ("Multiple occurences of fixed tag '%s', ignoring some", tag);
+ num_tags = 1;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
+ if (strcmp (add_funcs[i].gst_tag, tag) == 0) {
+ add_funcs[i].func (id3v2tag, list, tag, num_tags, add_funcs[i].data);
+ break;
+ }
+ }
+
+ if (i == G_N_ELEMENTS (add_funcs)) {
+ GST_WARNING ("Unsupported tag '%s' - not written", tag);
+ }
+}
+
+GstBuffer *
+gst_id3mux_render_v2_tag (GstTagMux * mux, GstTagList * taglist, int version)
+{
+ GstId3v2Tag tag;
+ GstBuffer *buf;
+
+ if (!id3v2_tag_init (&tag, version)) {
+ GST_WARNING_OBJECT (mux, "Unsupported version %d", version);
+ return NULL;
+ }
+
+ /* Render the tag */
+ gst_tag_list_foreach (taglist, foreach_add_tag, &tag);
+
+#if 0
+ /* Do we want to add our own signature to the tag somewhere? */
+ {
+ gchar *tag_producer_str;
+
+ tag_producer_str = g_strdup_printf ("(GStreamer id3v2mux %s, using "
+ "taglib %u.%u)", VERSION, TAGLIB_MAJOR_VERSION, TAGLIB_MINOR_VERSION);
+ add_one_txxx_tag (id3v2tag, "tag_encoder", tag_producer_str);
+ g_free (tag_producer_str);
+ }
+#endif
+
+ /* Create buffer with tag */
+ buf = id3v2_tag_to_buffer (&tag);
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
+ GST_LOG_OBJECT (mux, "tag size = %d bytes", GST_BUFFER_SIZE (buf));
+
+ id3v2_tag_unset (&tag);
+
+ return buf;
+}
+
+#define ID3_V1_TAG_SIZE 128
+
+typedef void (*GstId3v1WriteFunc) (const GstTagList * list,
+ const gchar * gst_tag, guint8 * dst, int len);
+
+static void
+latin1_convert (const GstTagList * list, const gchar * tag,
+ guint8 * dst, int maxlen)
+{
+ gchar *str;
+ gsize len;
+ gchar *latin1;
+
+ if (!gst_tag_list_get_string (list, tag, &str))
+ return;
+
+ /* Convert to Latin-1 (ISO-8859-1), replacing unrepresentable characters
+ with '?' */
+ latin1 = g_convert_with_fallback (str, -1, "ISO-8859-1", "UTF-8", "?",
+ NULL, &len, NULL);
+
+ if (latin1) {
+ len = MIN (len, maxlen);
+ memcpy (dst, latin1, len);
+ g_free (latin1);
+ }
+
+ g_free (str);
+}
+
+static void
+date_v1_convert (const GstTagList * list, const gchar * tag,
+ guint8 * dst, int maxlen)
+{
+ GDate *date;
+
+ /* Only one date supported */
+ if (gst_tag_list_get_date_index (list, tag, 0, &date) && date != NULL) {
+ GDateYear year = g_date_get_year (date);
+ /* Check for plausible year */
+ if (year > 500 && year < 2100) {
+ gchar str[5];
+ g_snprintf (str, 5, "%.4u", year);
+ memcpy (dst, str, 4);
+ } else {
+ GST_WARNING ("invalid year %u, skipping", year);
+ }
+
+ g_date_free (date);
+ }
+}
+
+static void
+genre_v1_convert (const GstTagList * list, const gchar * tag,
+ guint8 * dst, int maxlen)
+{
+ gchar *str;
+ int genreidx = -1;
+ guint i, max;
+
+ /* We only support one genre */
+ if (!gst_tag_list_get_string_index (list, tag, 0, &str))
+ return;
+
+ max = gst_tag_id3_genre_count ();
+
+ for (i = 0; i < max; i++) {
+ const gchar *genre = gst_tag_id3_genre_get (i);
+ if (g_str_equal (str, genre)) {
+ genreidx = i;
+ break;
+ }
+ }
+
+ if (genreidx >= 0 && genreidx <= 127)
+ *dst = (guint8) genreidx;
+
+ g_free (str);
+}
+
+static void
+track_number_convert (const GstTagList * list, const gchar * tag,
+ guint8 * dst, int maxlen)
+{
+ guint tracknum;
+
+ /* We only support one track number */
+ if (!gst_tag_list_get_uint_index (list, tag, 0, &tracknum))
+ return;
+
+ if (tracknum <= 127)
+ *dst = (guint8) tracknum;
+}
+
+static const struct
+{
+ const gchar *gst_tag;
+ const gint offset;
+ const gint length;
+ const GstId3v1WriteFunc func;
+} v1_funcs[] = {
+ {
+ GST_TAG_TITLE, 3, 30, latin1_convert}, {
+ GST_TAG_ARTIST, 33, 30, latin1_convert}, {
+ GST_TAG_ALBUM, 63, 30, latin1_convert}, {
+ GST_TAG_DATE, 93, 4, date_v1_convert}, {
+ GST_TAG_COMMENT, 97, 28, latin1_convert}, {
+ /* Note: one-byte gap here */
+ GST_TAG_TRACK_NUMBER, 126, 1, track_number_convert}, {
+ GST_TAG_GENRE, 127, 1, genre_v1_convert}
+};
+
+GstBuffer *
+gst_id3mux_render_v1_tag (GstTagMux * mux, GstTagList * taglist)
+{
+ GstBuffer *buf = gst_buffer_new_and_alloc (ID3_V1_TAG_SIZE);
+ guint8 *data = GST_BUFFER_DATA (buf);
+ int i;
+
+ memset (data, 0, ID3_V1_TAG_SIZE);
+
+ data[0] = 'T';
+ data[1] = 'A';
+ data[2] = 'G';
+
+ for (i = 0; i < G_N_ELEMENTS (v1_funcs); i++) {
+ v1_funcs[i].func (taglist, v1_funcs[i].gst_tag, data + v1_funcs[i].offset,
+ v1_funcs[i].length);
+ }
+
+ gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
+ return buf;
+}
diff --git a/gst/flv/gstflvparse.h b/gst/id3tag/id3tag.h
index 203d30de..1fb59376 100644
--- a/gst/flv/gstflvparse.h
+++ b/gst/id3tag/id3tag.h
@@ -1,5 +1,5 @@
-/* GStreamer
- * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
+/* GStreamer ID3v2 tag writer
+ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -17,26 +17,16 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef __FLV_PARSE_H__
-#define __FLV_PARSE_H__
-
-#include "gstflvdemux.h"
+#include "gsttagmux.h"
G_BEGIN_DECLS
+#define ID3_VERSION_2_3 3
+#define ID3_VERSION_2_4 4
-GstFlowReturn gst_flv_parse_tag_script (GstFLVDemux * demux,
- GstBuffer *buffer);
-
-GstFlowReturn gst_flv_parse_tag_audio (GstFLVDemux * demux, GstBuffer *buffer);
-
-GstFlowReturn gst_flv_parse_tag_video (GstFLVDemux * demux, GstBuffer *buffer);
-
-GstFlowReturn gst_flv_parse_tag_type (GstFLVDemux * demux, GstBuffer *buffer);
-
-GstFlowReturn gst_flv_parse_header (GstFLVDemux * demux, GstBuffer *buffer);
-
-GstClockTime gst_flv_parse_tag_timestamp (GstFLVDemux *demux, GstBuffer *buffer, size_t *tag_data_size);
+GstBuffer * gst_id3mux_render_v2_tag (GstTagMux * mux, GstTagList * taglist,
+ int version);
+GstBuffer * gst_id3mux_render_v1_tag (GstTagMux * mux, GstTagList * taglist);
G_END_DECLS
-#endif /* __FLV_PARSE_H__ */
+
diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c
index 1efa28be..e0e28d0c 100644
--- a/gst/mpeg4videoparse/mpeg4videoparse.c
+++ b/gst/mpeg4videoparse/mpeg4videoparse.c
@@ -726,6 +726,10 @@ gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse)
if (parse->adapter) {
gst_adapter_clear (parse->adapter);
}
+ if (parse->config != NULL) {
+ gst_buffer_unref (parse->config);
+ parse->config = NULL;
+ }
parse->state = PARSE_NEED_START;
parse->have_config = FALSE;
@@ -760,6 +764,10 @@ gst_mpeg4vparse_dispose (GObject * object)
g_object_unref (parse->adapter);
parse->adapter = NULL;
}
+ if (parse->config != NULL) {
+ gst_buffer_unref (parse->config);
+ parse->config = NULL;
+ }
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
}
diff --git a/gst/mpegdemux/gstmpegdefs.h b/gst/mpegdemux/gstmpegdefs.h
index 7f38f4de..7ad1e25c 100644
--- a/gst/mpegdemux/gstmpegdefs.h
+++ b/gst/mpegdemux/gstmpegdefs.h
@@ -170,7 +170,11 @@
#define ST_PS_AUDIO_AC3 0x81
#define ST_PS_AUDIO_DTS 0x8a
#define ST_PS_AUDIO_LPCM 0x8b
+#define ST_HDV_PRIVATE_A0 0xa0
+#define ST_HDV_PRIVATE_A1 0xa1
#define ST_PS_DVD_SUBPICTURE 0xff
+/* Blu-ray PGS subpictures */
+#define ST_BD_PGS_SUBPICTURE 0x90
/* Un-official time-code stream */
#define ST_PS_TIMECODE 0xd2
diff --git a/gst/mpegdemux/gstmpegdemux.c b/gst/mpegdemux/gstmpegdemux.c
index 439bb563..ce1d0978 100644
--- a/gst/mpegdemux/gstmpegdemux.c
+++ b/gst/mpegdemux/gstmpegdemux.c
@@ -39,6 +39,7 @@
* Fluendo, S.L. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
+ * Jan Schmidt <thaytan@noraisin.net>
*/
#ifdef HAVE_CONFIG_H
@@ -56,6 +57,9 @@
#define SCAN_SCR_SZ 12
#define SCAN_PTS_SZ 80
+#define SEGMENT_THRESHOLD (300*GST_MSECOND)
+#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)
+
typedef enum
{
SCAN_SCR,
@@ -177,6 +181,13 @@ static GstStaticPadTemplate audio_template =
"audio/x-private1-ac3;" "audio/x-private1-dts;" "audio/ac3")
);
+static GstStaticPadTemplate subpicture_template =
+GST_STATIC_PAD_TEMPLATE ("subpicture_%02x",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ GST_STATIC_CAPS ("video/x-dvd-subpicture")
+ );
+
static GstStaticPadTemplate private_template =
GST_STATIC_PAD_TEMPLATE ("private_%d",
GST_PAD_SRC,
@@ -209,6 +220,10 @@ static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux,
static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux,
guint64 * pos, SCAN_MODE mode, guint64 * rts);
+static void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
+ GstClockTime new_time);
+static void gst_flups_demux_clear_times (GstFluPSDemux * demux);
+
static GstElementClass *parent_class = NULL;
/*static guint gst_flups_demux_signals[LAST_SIGNAL] = { 0 };*/
@@ -250,10 +265,14 @@ gst_flups_demux_base_init (GstFluPSDemuxClass * klass)
klass->sink_template = gst_static_pad_template_get (&sink_template);
klass->video_template = gst_static_pad_template_get (&video_template);
klass->audio_template = gst_static_pad_template_get (&audio_template);
+ klass->subpicture_template =
+ gst_static_pad_template_get (&subpicture_template);
klass->private_template = gst_static_pad_template_get (&private_template);
gst_element_class_add_pad_template (element_class, klass->video_template);
gst_element_class_add_pad_template (element_class, klass->audio_template);
+ gst_element_class_add_pad_template (element_class,
+ klass->subpicture_template);
gst_element_class_add_pad_template (element_class, klass->private_template);
gst_element_class_add_pad_template (element_class, klass->sink_template);
@@ -340,6 +359,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
gchar *name;
GstFluPSDemuxClass *klass = GST_FLUPS_DEMUX_GET_CLASS (demux);
GstCaps *caps;
+ GstClockTime threshold = SEGMENT_THRESHOLD;
name = NULL;
template = NULL;
@@ -368,6 +388,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
caps = gst_caps_new_simple ("video/mpeg",
"mpegversion", G_TYPE_INT, mpeg_version,
"systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
+ threshold = VIDEO_SEGMENT_THRESHOLD;
break;
}
case ST_AUDIO_MPEG1:
@@ -387,6 +408,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
template = klass->video_template;
name = g_strdup_printf ("video_%02x", id);
caps = gst_caps_new_simple ("video/x-h264", NULL);
+ threshold = VIDEO_SEGMENT_THRESHOLD;
break;
case ST_PS_AUDIO_AC3:
template = klass->audio_template;
@@ -404,6 +426,9 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
caps = gst_caps_new_simple ("audio/x-private1-lpcm", NULL);
break;
case ST_PS_DVD_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%02x", id);
+ caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
break;
case ST_GST_AUDIO_RAWA52:
template = klass->audio_template;
@@ -424,6 +449,7 @@ gst_flups_demux_create_stream (GstFluPSDemux * demux, gint id, gint stream_type)
stream->notlinked = FALSE;
stream->type = stream_type;
stream->pad = gst_pad_new_from_template (template, name);
+ stream->segment_thresh = threshold;
gst_pad_set_event_function (stream->pad,
GST_DEBUG_FUNCPTR (gst_flups_demux_src_event));
gst_pad_set_query_function (stream->pad,
@@ -559,6 +585,20 @@ gst_flups_demux_send_data (GstFluPSDemux * demux, GstFluPSStream * stream,
GST_TIME_ARGS (demux->src_segment.last_stop),
GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->current_scr)));
+ if (demux->src_segment.last_stop != GST_CLOCK_TIME_NONE) {
+ GstClockTime new_time = demux->base_time + demux->src_segment.last_stop;
+
+ if (stream->last_ts == GST_CLOCK_TIME_NONE || stream->last_ts < new_time) {
+#if 0
+ g_print ("last_ts update on pad %s to time %" GST_TIME_FORMAT "\n",
+ GST_PAD_NAME (stream->pad), GST_TIME_ARGS (cur_scr_time));
+#endif
+ stream->last_ts = new_time;
+ }
+
+ gst_flups_demux_send_segment_updates (demux, new_time);
+ }
+
/* Set the buffer discont flag, and clear discont state on the stream */
if (stream->discont) {
GST_DEBUG_OBJECT (demux, "marking discont buffer");
@@ -731,12 +771,76 @@ gst_flups_demux_flush (GstFluPSDemux * demux)
gst_adapter_clear (demux->adapter);
gst_adapter_clear (demux->rev_adapter);
gst_pes_filter_drain (&demux->filter);
+ gst_flups_demux_clear_times (demux);
demux->adapter_offset = G_MAXUINT64;
demux->current_scr = G_MAXUINT64;
demux->bytes_since_scr = 0;
}
static void
+gst_flups_demux_clear_times (GstFluPSDemux * demux)
+{
+ gint id;
+
+ /* Clear the last ts for all streams */
+ for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) {
+ GstFluPSStream *stream = demux->streams[id];
+
+ if (stream) {
+ stream->last_seg_start = stream->last_ts = GST_CLOCK_TIME_NONE;
+ }
+ }
+}
+
+static void
+gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
+ GstClockTime new_time)
+{
+ /* Advance all lagging streams by sending a segment update */
+ gint id;
+ GstEvent *event = NULL;
+
+ /* FIXME: Handle reverse playback */
+
+ if (new_time > demux->src_segment.stop)
+ return;
+
+ for (id = 0; id < GST_FLUPS_DEMUX_MAX_STREAMS; id++) {
+ GstFluPSStream *stream = demux->streams[id];
+
+ if (stream) {
+ if (stream->last_ts == GST_CLOCK_TIME_NONE ||
+ stream->last_ts < demux->src_segment.start)
+ stream->last_ts = demux->src_segment.start;
+ if (stream->last_ts + stream->segment_thresh < new_time) {
+#if 0
+ g_print ("Segment update to pad %s time %" GST_TIME_FORMAT " stop now %"
+ GST_TIME_FORMAT "\n", GST_PAD_NAME (stream->pad),
+ GST_TIME_ARGS (new_time), GST_TIME_ARGS (demux->src_segment.stop));
+#endif
+ GST_DEBUG_OBJECT (demux,
+ "Segment update to pad %s time %" GST_TIME_FORMAT,
+ GST_PAD_NAME (stream->pad), GST_TIME_ARGS (new_time));
+ if (event == NULL) {
+ event = gst_event_new_new_segment_full (TRUE,
+ demux->src_segment.rate, demux->src_segment.applied_rate,
+ GST_FORMAT_TIME, new_time,
+ demux->src_segment.stop,
+ demux->src_segment.time + (new_time - demux->src_segment.start));
+ }
+ gst_event_ref (event);
+ gst_pad_push_event (stream->pad, event);
+ stream->last_seg_start = stream->last_ts = new_time;
+ stream->need_segment = FALSE;
+ }
+ }
+ }
+
+ if (event)
+ gst_event_unref (event);
+}
+
+static void
gst_flups_demux_close_segment (GstFluPSDemux * demux)
{
gint id;
@@ -747,6 +851,10 @@ gst_flups_demux_close_segment (GstFluPSDemux * demux)
&demux->src_segment);
#endif
+ /* FIXME: Need to send a different segment-close to each pad where the
+ * last_seg_start != clock_time_none, as that indicates a sparse-stream
+ * event was sent there */
+
/* Close the current segment for a linear playback */
if (demux->src_segment.rate >= 0) {
/* for forward playback, we played from start to last_stop */
@@ -1306,7 +1414,7 @@ gst_flups_demux_reset_psm (GstFluPSDemux * demux)
FILL_TYPE (0x40, 0x7f, -1);
FILL_TYPE (0x80, 0x87, ST_PS_AUDIO_AC3);
FILL_TYPE (0x88, 0x9f, ST_PS_AUDIO_DTS);
- FILL_TYPE (0xa0, 0xbf, ST_PS_AUDIO_LPCM);
+ FILL_TYPE (0xa0, 0xaf, ST_PS_AUDIO_LPCM);
FILL_TYPE (0xbd, 0xbd, -1);
FILL_TYPE (0xc0, 0xdf, ST_AUDIO_MPEG1);
FILL_TYPE (0xe0, 0xef, ST_GST_VIDEO_MPEG1_OR_2);
@@ -1839,18 +1947,26 @@ gst_flups_demux_data_cb (GstPESFilter * filter, gboolean first,
}
if (G_LIKELY (stream_type == -1)) {
- /* new id */
+ /* new id is in the first byte */
id = data[offset++];
- /* Number of audio frames in this packet */
- nframes = data[offset++];
-
- GST_DEBUG_OBJECT (demux, "private type 0x%02x, %d frames", id,
- nframes);
-
- datalen -= 2;
+ datalen--;
/* and remap */
stream_type = demux->psm[id];
+
+ /* Now, if it's a subpicture stream - no more, otherwise
+ * take the first byte too, since it's the frame count in audio
+ * streams and our backwards compat convention is to strip it off */
+ if (stream_type != ST_PS_DVD_SUBPICTURE) {
+ /* Number of audio frames in this packet */
+ nframes = data[offset++];
+ datalen--;
+ GST_DEBUG_OBJECT (demux, "private type 0x%02x, %d frames", id,
+ nframes);
+ } else {
+ GST_DEBUG_OBJECT (demux, "private type 0x%02x, stream type %d", id,
+ stream_type);
+ }
}
}
if (stream_type == -1)
diff --git a/gst/mpegdemux/gstmpegdemux.h b/gst/mpegdemux/gstmpegdemux.h
index ef175f76..29b3d5e5 100644
--- a/gst/mpegdemux/gstmpegdemux.h
+++ b/gst/mpegdemux/gstmpegdemux.h
@@ -86,6 +86,10 @@ struct _GstFluPSStream
gint type;
gint size_bound;
+ GstClockTime segment_thresh;
+ GstClockTime last_seg_start;
+ GstClockTime last_ts;
+
gboolean discont;
gboolean notlinked;
gboolean need_segment;
@@ -149,6 +153,7 @@ struct _GstFluPSDemuxClass
GstPadTemplate *sink_template;
GstPadTemplate *video_template;
GstPadTemplate *audio_template;
+ GstPadTemplate *subpicture_template;
GstPadTemplate *private_template;
};
diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c
index 4464cdf8..ef0de2c8 100644
--- a/gst/mpegdemux/gstmpegtsdemux.c
+++ b/gst/mpegdemux/gstmpegtsdemux.c
@@ -34,9 +34,9 @@
*
* The Original Code is Fluendo MPEG Demuxer plugin.
*
- * The Initial Developer of the Original Code is Fluendo, S.L.
- * Portions created by Fluendo, S.L. are Copyright (C) 2005
- * Fluendo, S.L. All Rights Reserved.
+ * The Initial Developer of the Original Code is Fluendo, S.A.
+ * Portions created by Fluendo, S.L. are Copyright (C) 2005,2006,2007,2008,2009
+ * Fluendo, S.A. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*/
@@ -126,6 +126,13 @@ enum
PROP_M2TS
};
+#define GSTTIME_TO_BYTES(time) \
+ ((time != -1) ? gst_util_uint64_scale (MAX(0,(gint64) ((time))), \
+ demux->bitrate, GST_SECOND) : -1)
+#define BYTES_TO_GSTTIME(bytes) \
+ ((bytes != -1) ? (gst_util_uint64_scale (bytes, GST_SECOND, \
+ demux->bitrate)) : -1)
+
#define VIDEO_CAPS \
GST_STATIC_CAPS (\
"video/mpeg, " \
@@ -150,6 +157,10 @@ enum
"audio/x-dts" \
)
+/* Can also use the subpicture pads for text subtitles? */
+#define SUBPICTURE_CAPS \
+ GST_STATIC_CAPS ("subpicture/x-pgs; video/x-dvd-subpicture")
+
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@@ -168,6 +179,12 @@ GST_STATIC_PAD_TEMPLATE ("audio_%04x",
GST_PAD_SOMETIMES,
AUDIO_CAPS);
+static GstStaticPadTemplate subpicture_template =
+GST_STATIC_PAD_TEMPLATE ("subpicture_%04x",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
+ SUBPICTURE_CAPS);
+
static GstStaticPadTemplate private_template =
GST_STATIC_PAD_TEMPLATE ("private_%04x",
GST_PAD_SRC,
@@ -189,6 +206,7 @@ static void gst_mpegts_demux_get_property (GObject * object, guint prop_id,
static gboolean gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID);
static gboolean gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_mpegts_demux_sink_setcaps (GstPad * pad, GstCaps * caps);
@@ -242,10 +260,14 @@ gst_mpegts_demux_base_init (GstMpegTSDemuxClass * klass)
klass->sink_template = gst_static_pad_template_get (&sink_template);
klass->video_template = gst_static_pad_template_get (&video_template);
klass->audio_template = gst_static_pad_template_get (&audio_template);
+ klass->subpicture_template =
+ gst_static_pad_template_get (&subpicture_template);
klass->private_template = gst_static_pad_template_get (&private_template);
gst_element_class_add_pad_template (element_class, klass->video_template);
gst_element_class_add_pad_template (element_class, klass->audio_template);
+ gst_element_class_add_pad_template (element_class,
+ klass->subpicture_template);
gst_element_class_add_pad_template (element_class, klass->private_template);
gst_element_class_add_pad_template (element_class, klass->sink_template);
@@ -327,7 +349,12 @@ gst_mpegts_demux_init (GstMpegTSDemux * demux)
demux->m2ts_mode = FALSE;
demux->sync_lut = NULL;
demux->sync_lut_len = 0;
-
+ demux->bitrate = -1;
+ demux->num_packets = 0;
+ demux->pcr[0] = -1;
+ demux->pcr[1] = -1;
+ demux->cache_duration = GST_CLOCK_TIME_NONE;
+ demux->base_pts = GST_CLOCK_TIME_NONE;
#ifdef USE_LIBOIL
oil_init ();
#endif
@@ -369,8 +396,8 @@ gst_mpegts_demux_reset (GstMpegTSDemux * demux)
case PID_TYPE_ELEMENTARY:
gst_pes_filter_uninit (&stream->filter);
break;
- case PID_PROGRAM_ASSOCIATION_TABLE:
- case PID_CONDITIONAL_ACCESS_TABLE:
+ case PID_TYPE_PROGRAM_ASSOCIATION:
+ case PID_TYPE_CONDITIONAL_ACCESS:
case PID_TYPE_PROGRAM_MAP:
gst_section_filter_uninit (&stream->section_filter);
break;
@@ -607,6 +634,16 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
caps = gst_caps_new_simple ("private/teletext", NULL);
}
break;
+ case ST_HDV_PRIVATE_A0:
+ template = klass->private_template;
+ name = g_strdup_printf ("private_%04x", stream->PID);
+ caps = gst_caps_new_simple ("private/hdv-a0", NULL);
+ break;
+ case ST_HDV_PRIVATE_A1:
+ template = klass->private_template;
+ name = g_strdup_printf ("private_%04x", stream->PID);
+ caps = gst_caps_new_simple ("private/hdv-a1", NULL);
+ break;
case ST_PRIVATE_SECTIONS:
case ST_MHEG:
case ST_DSMCC:
@@ -652,6 +689,14 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
caps = gst_caps_new_simple ("audio/x-lpcm", NULL);
break;
case ST_PS_DVD_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%04x", stream->PID);
+ caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
+ break;
+ case ST_BD_PGS_SUBPICTURE:
+ template = klass->subpicture_template;
+ name = g_strdup_printf ("subpicture_%04x", stream->PID);
+ caps = gst_caps_new_simple ("subpicture/x-pgs", NULL);
break;
default:
break;
@@ -668,6 +713,8 @@ gst_mpegts_demux_fill_stream (GstMpegTSStream * stream, guint8 id,
gst_caps_unref (caps);
gst_pad_set_query_function (stream->pad,
GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_pad_query));
+ gst_pad_set_event_function (stream->pad,
+ GST_DEBUG_FUNCPTR (gst_mpegts_demux_src_event));
g_free (name);
return TRUE;
@@ -730,7 +777,7 @@ gst_mpegts_demux_send_new_segment (GstMpegTSDemux * demux,
}
base_PCR = PCR_stream->base_PCR;
- time = MPEGTIME_TO_GSTTIME (base_PCR);
+ demux->base_pts = time = MPEGTIME_TO_GSTTIME (base_PCR);
GST_DEBUG_OBJECT (demux, "segment PTS to (%" G_GUINT64_FORMAT ") time: %"
G_GUINT64_FORMAT, base_PCR, time);
@@ -828,7 +875,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
demux = stream->demux;
srcpad = stream->pad;
- GST_LOG_OBJECT (demux, "got data on PID 0x%04x", stream->PID);
+ GST_DEBUG_OBJECT (demux, "got data on PID 0x%04x", stream->PID);
if (first && filter->pts != -1) {
pts = filter->pts;
@@ -932,7 +979,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
pts = -1;
}
- GST_LOG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %"
+ GST_DEBUG_OBJECT (demux, "setting PTS to (%" G_GUINT64_FORMAT ") time: %"
GST_TIME_FORMAT " on buffer %p first buffer: %d base_time: %"
GST_TIME_FORMAT, pts, GST_TIME_ARGS (time), buffer, first,
GST_TIME_ARGS (stream->base_time));
@@ -967,8 +1014,8 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
goto unknown_type;
GST_DEBUG_OBJECT (demux,
- "New stream 0x%04x of type %d with caps %" GST_PTR_FORMAT, stream->PID,
- stream->stream_type, GST_PAD_CAPS (stream->pad));
+ "New stream 0x%04x of type 0x%02x with caps %" GST_PTR_FORMAT,
+ stream->PID, stream->stream_type, GST_PAD_CAPS (stream->pad));
srcpad = stream->pad;
@@ -981,7 +1028,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
gst_mpegts_demux_send_new_segment (demux, stream, pts);
}
- GST_DEBUG_OBJECT (demux, "pushing buffer");
+ GST_DEBUG_OBJECT (srcpad, "pushing buffer");
gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad));
ret = gst_pad_push (srcpad, buffer);
ret = gst_mpegts_demux_combine_flows (demux, stream, ret);
@@ -992,7 +1039,7 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
unknown_type:
{
GST_DEBUG_OBJECT (demux, "got unknown stream id 0x%02x, type 0x%02x",
- filter->id, filter->type);
+ filter->id, stream->stream_type);
gst_buffer_unref (buffer);
return gst_mpegts_demux_combine_flows (demux, stream, GST_FLOW_NOT_LINKED);
}
@@ -1184,16 +1231,16 @@ gst_mpegts_stream_parse_pmt (GstMpegTSStream * stream,
if (gst_mpegts_demux_calc_crc32 (data - 3, datalen) != 0)
goto wrong_crc;
- GST_DEBUG_OBJECT (demux, "PMT section_length: %d", datalen - 3);
+ GST_LOG_OBJECT (demux, "PMT section_length: %d", datalen - 3);
PMT = &stream->PMT;
/* check if version number changed */
version_number = (data[2] & 0x3e) >> 1;
- GST_DEBUG_OBJECT (demux, "PMT version_number: %d", version_number);
+ GST_LOG_OBJECT (demux, "PMT version_number: %d", version_number);
current_next_indicator = (data[2] & 0x01);
- GST_DEBUG_OBJECT (demux, "PMT current_next_indicator %d",
+ GST_LOG_OBJECT (demux, "PMT current_next_indicator %d",
current_next_indicator);
if (current_next_indicator == 0)
goto not_yet_applicable;
@@ -1559,7 +1606,7 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
if (length > 0) {
guint8 flags = *data++;
- GST_DEBUG_OBJECT (demux, "flags 0x%02x", flags);
+ GST_LOG_OBJECT (demux, "flags 0x%02x", flags);
/* discontinuity flag */
if (flags & 0x80) {
GST_DEBUG_OBJECT (demux, "discontinuity flag set");
@@ -1578,9 +1625,12 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
pcr_ext = (pcr2 & 0x01ff);
if (pcr_ext)
pcr = (pcr * 300 + pcr_ext % 300) / 300;
- GST_DEBUG_OBJECT (demux, "have PCR %" G_GUINT64_FORMAT " on PID 0x%04x "
- "and last pcr is %" G_GUINT64_FORMAT,
- pcr, stream->PID, stream->last_PCR);
+ GST_DEBUG_OBJECT (demux,
+ "have PCR %" G_GUINT64_FORMAT "(%" GST_TIME_FORMAT ") on PID 0x%04x "
+ "and last pcr is %" G_GUINT64_FORMAT " (%" GST_TIME_FORMAT ")", pcr,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pcr)), stream->PID,
+ stream->last_PCR,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (stream->last_PCR)));
/* pcr has been converted into units of 90Khz ticks
* so assume discont if last pcr was > 900000 (10 second) lower */
if (stream->last_PCR != -1 &&
@@ -1676,11 +1726,24 @@ gst_mpegts_demux_parse_adaptation_field (GstMpegTSStream * stream,
}
stream->last_PCR_difference = pcr - stream->last_PCR;
}
+
GST_DEBUG_OBJECT (demux,
"valid pcr: %d last PCR difference: %" G_GUINT64_FORMAT, valid_pcr,
stream->last_PCR_difference);
if (valid_pcr) {
-
+ GstMpegTSStream *PMT_stream = demux->streams[demux->current_PMT];
+
+ if (PMT_stream && PMT_stream->PMT.PCR_PID == stream->PID) {
+ if (demux->pcr[0] == -1) {
+ GST_DEBUG ("RECORDING pcr[0]:%" G_GUINT64_FORMAT, pcr);
+ demux->pcr[0] = pcr;
+ demux->num_packets = 0;
+ } /* Considering a difference of 1 sec ie 90000 ticks */
+ else if (demux->pcr[1] == -1 && ((pcr - demux->pcr[0]) >= 90000)) {
+ GST_DEBUG ("RECORDING pcr[1]:%" G_GUINT64_FORMAT, pcr);
+ demux->pcr[1] = pcr;
+ }
+ }
stream->last_PCR = pcr;
if (demux->clock && demux->clock_base != GST_CLOCK_TIME_NONE) {
@@ -1955,15 +2018,20 @@ gst_mpegts_demux_is_PMT (GstMpegTSDemux * demux, guint16 PID)
}
static FORCE_INLINE GstFlowReturn
-gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream)
+gst_mpegts_stream_pes_buffer_flush (GstMpegTSStream * stream, gboolean discard)
{
GstFlowReturn ret = GST_FLOW_OK;
if (stream->pes_buffer) {
- GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used;
- ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer);
- if (ret == GST_FLOW_LOST_SYNC)
+ if (discard) {
+ gst_buffer_unref (stream->pes_buffer);
stream->pes_buffer_in_sync = FALSE;
+ } else {
+ GST_BUFFER_SIZE (stream->pes_buffer) = stream->pes_buffer_used;
+ ret = gst_pes_filter_push (&stream->filter, stream->pes_buffer);
+ if (ret == GST_FLOW_LOST_SYNC)
+ stream->pes_buffer_in_sync = FALSE;
+ }
stream->pes_buffer = NULL;
}
return ret;
@@ -1985,7 +2053,7 @@ gst_mpegts_stream_pes_buffer_push (GstMpegTSStream * stream,
if (stream->pes_buffer_size < (MPEGTS_MAX_PES_BUFFER_SIZE >> 1))
stream->pes_buffer_size <<= 1;
- ret = gst_mpegts_stream_pes_buffer_flush (stream);
+ ret = gst_mpegts_stream_pes_buffer_flush (stream, FALSE);
if (ret == GST_FLOW_LOST_SYNC)
goto done;
}
@@ -2010,7 +2078,7 @@ done:
}
static FORCE_INLINE GstFlowReturn
-gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
+gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux, gboolean discard)
{
gint i;
GstFlowReturn ret = GST_FLOW_OK;
@@ -2018,7 +2086,7 @@ gst_mpegts_demux_pes_buffer_flush (GstMpegTSDemux * demux)
for (i = 0; i < MPEGTS_MAX_PID + 1; i++) {
GstMpegTSStream *stream = demux->streams[i];
if (stream && stream->pad) {
- gst_mpegts_stream_pes_buffer_flush (stream);
+ gst_mpegts_stream_pes_buffer_flush (stream, discard);
stream->pes_buffer_in_sync = FALSE;
}
}
@@ -2093,7 +2161,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
data += 3;
datalen -= 3;
- GST_DEBUG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u",
+ GST_LOG_OBJECT (demux, "afc 0x%x, pusi %d, PID 0x%04x datalen %u",
adaptation_field_control, payload_unit_start_indicator, PID, datalen);
ret = GST_FLOW_OK;
@@ -2115,13 +2183,12 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
data += consumed;
datalen -= consumed;
- GST_DEBUG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen);
+ GST_LOG_OBJECT (demux, "consumed: %u datalen: %u", consumed, datalen);
}
/* If this packet has a payload, handle it */
if (adaptation_field_control & 0x1) {
- GST_DEBUG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen,
- PID);
+ GST_LOG_OBJECT (demux, "Packet payload %d bytes, PID 0x%04x", datalen, PID);
/* For unknown streams, check if the PID is in the partial PIDs
* list as an elementary stream and override the type if so
@@ -2233,7 +2300,7 @@ gst_mpegts_demux_parse_stream (GstMpegTSDemux * demux, GstMpegTSStream * stream,
"bytes of %u bytes in the PES buffer",
PID, stream->pes_buffer_used, stream->pes_buffer_size);
/* Flush buffered PES data */
- gst_mpegts_stream_pes_buffer_flush (stream);
+ gst_mpegts_stream_pes_buffer_flush (stream, FALSE);
gst_pes_filter_drain (&stream->filter);
/* Resize the buffer to half if no overflow detected and
* had been used less than half of it */
@@ -2302,7 +2369,7 @@ static FORCE_INLINE GstFlowReturn
gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
const guint8 * data)
{
- GstFlowReturn ret;
+ GstFlowReturn ret = GST_FLOW_OK;
guint16 PID;
GstMpegTSStream *stream;
@@ -2312,6 +2379,10 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
/* get PID */
PID = ((data[0] & 0x1f) << 8) | data[1];
+ /* Skip NULL packets */
+ if (G_UNLIKELY (PID == 0x1fff))
+ goto beach;
+
/* get the stream. */
stream = gst_mpegts_demux_get_stream_for_PID (demux, PID);
@@ -2319,12 +2390,153 @@ gst_mpegts_demux_parse_transport_packet (GstMpegTSDemux * demux,
ret = gst_mpegts_demux_parse_stream (demux, stream, data,
MPEGTS_NORMAL_TS_PACKETSIZE - 1);
+ if (demux->pcr[1] != -1 && demux->bitrate == -1) {
+ guint64 bitrate;
+ GST_DEBUG_OBJECT (demux, "pcr[0]:%" G_GUINT64_FORMAT, demux->pcr[0]);
+ GST_DEBUG_OBJECT (demux, "pcr[1]:%" G_GUINT64_FORMAT, demux->pcr[1]);
+ GST_DEBUG_OBJECT (demux, "diff in time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0])));
+ GST_DEBUG_OBJECT (demux, "stream->last_PCR_difference: %" G_GUINT64_FORMAT
+ ", demux->num_packets %" G_GUINT64_FORMAT,
+ demux->pcr[1] - demux->pcr[0], demux->num_packets);
+ bitrate = gst_util_uint64_scale (GST_SECOND,
+ MPEGTS_NORMAL_TS_PACKETSIZE * demux->num_packets,
+ MPEGTIME_TO_GSTTIME (demux->pcr[1] - demux->pcr[0]));
+ /* somehow... I doubt a bitrate below one packet per second is valid */
+ if (bitrate > MPEGTS_NORMAL_TS_PACKETSIZE - 1) {
+ demux->bitrate = bitrate;
+ GST_DEBUG_OBJECT (demux, "bitrate is %" G_GINT64_FORMAT
+ " bytes per second", demux->bitrate);
+ } else {
+ GST_WARNING_OBJECT (demux, "Couldn't compute valid bitrate, recomputing");
+ demux->pcr[0] = demux->pcr[1] = -1;
+ demux->num_packets = -1;
+ }
+ }
+
+beach:
+ demux->num_packets++;
return ret;
/* ERRORS */
}
static gboolean
+gst_mpegts_demux_handle_seek_push (GstMpegTSDemux * demux, GstEvent * event)
+{
+ gboolean res = FALSE;
+ gdouble rate;
+ GstFormat format;
+ GstSeekFlags flags;
+ GstSeekType start_type, stop_type;
+ gint64 start, stop, bstart, bstop;
+ GstEvent *bevent;
+
+ gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
+ &stop_type, &stop);
+
+ GST_DEBUG_OBJECT (demux, "seek event, rate: %f start: %" GST_TIME_FORMAT
+ " stop: %" GST_TIME_FORMAT, rate, GST_TIME_ARGS (start),
+ GST_TIME_ARGS (stop));
+
+ if (format == GST_FORMAT_BYTES) {
+ GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format);
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (demux, "seek - trying directly upstream first");
+
+ /* first try original format seek */
+ res = gst_pad_push_event (demux->sinkpad, gst_event_ref (event));
+ if (res == TRUE)
+ goto beach;
+ GST_DEBUG_OBJECT (demux, "seek - no upstream");
+
+ if (format != GST_FORMAT_TIME) {
+ /* From here down, we only support time based seeks */
+ GST_DEBUG_OBJECT (demux, "seek not supported on format %d", format);
+ goto beach;
+ }
+
+ /* We need to convert to byte based seek and we need a scr_rate for that. */
+ if (demux->bitrate == -1) {
+ GST_DEBUG_OBJECT (demux, "seek not possible, no bitrate");
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (demux, "try with bitrate");
+
+ bstart = GSTTIME_TO_BYTES (start);
+ bstop = GSTTIME_TO_BYTES (stop);
+
+ GST_DEBUG_OBJECT (demux, "in bytes bstart %" G_GINT64_FORMAT " bstop %"
+ G_GINT64_FORMAT, bstart, bstop);
+ bevent = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type,
+ bstart, stop_type, bstop);
+
+ res = gst_pad_push_event (demux->sinkpad, bevent);
+
+beach:
+ gst_event_unref (event);
+ return res;
+}
+
+static gboolean
+gst_mpegts_demux_src_event (GstPad * pad, GstEvent * event)
+{
+ GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
+ gboolean res = FALSE;
+
+ GST_DEBUG_OBJECT (demux, "got event %s",
+ gst_event_type_get_name (GST_EVENT_TYPE (event)));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ res = gst_mpegts_demux_handle_seek_push (demux, event);
+ break;
+ default:
+ res = gst_pad_push_event (demux->sinkpad, event);
+ break;
+ }
+
+ gst_object_unref (demux);
+
+ return res;
+}
+
+static void
+gst_mpegts_demux_flush (GstMpegTSDemux * demux, gboolean discard)
+{
+ GstMpegTSStream *PCR_stream;
+ GstMpegTSStream *PMT_stream;
+
+ GST_DEBUG_OBJECT (demux, "flushing MPEG TS demuxer (discard %d)", discard);
+
+ /* Start by flushing internal buffers */
+ gst_mpegts_demux_pes_buffer_flush (demux, discard);
+
+ /* Clear adapter */
+ gst_adapter_clear (demux->adapter);
+
+ /* Try resetting the last_PCR value as we will have a discont */
+ if (demux->current_PMT == 0)
+ goto beach;
+
+ PMT_stream = demux->streams[demux->current_PMT];
+ if (PMT_stream == NULL)
+ goto beach;
+
+ PCR_stream = demux->streams[PMT_stream->PMT.PCR_PID];
+ if (PCR_stream == NULL)
+ goto beach;
+
+ PCR_stream->last_PCR = -1;
+
+beach:
+ return;
+}
+
+static gboolean
gst_mpegts_demux_send_event (GstMpegTSDemux * demux, GstEvent * event)
{
gint i;
@@ -2347,7 +2559,7 @@ static gboolean
gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
{
GstMpegTSDemux *demux = GST_MPEGTS_DEMUX (gst_pad_get_parent (pad));
- gboolean res;
+ gboolean res = FALSE;
GST_DEBUG_OBJECT (demux, "got event %s",
gst_event_type_get_name (GST_EVENT_TYPE (event)));
@@ -2358,11 +2570,11 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
break;
case GST_EVENT_FLUSH_STOP:
gst_adapter_clear (demux->adapter);
+ gst_mpegts_demux_flush (demux, TRUE);
res = gst_mpegts_demux_send_event (demux, event);
break;
case GST_EVENT_EOS:
- /* Flush buffered PES data */
- gst_mpegts_demux_pes_buffer_flush (demux);
+ gst_mpegts_demux_flush (demux, FALSE);
/* Send the EOS event on each stream */
if (!(res = gst_mpegts_demux_send_event (demux, event))) {
/* we have no streams */
@@ -2371,15 +2583,46 @@ gst_mpegts_demux_sink_event (GstPad * pad, GstEvent * event)
}
break;
case GST_EVENT_NEWSEGMENT:
- res = gst_mpegts_demux_send_event (demux, event);
+ {
+ gboolean update;
+ gdouble rate;
+ GstFormat format;
+ gint64 start, stop, time;
+
+ gst_event_parse_new_segment (event, &update, &rate, &format,
+ &start, &stop, &time);
+
+ gst_event_unref (event);
+ GST_INFO_OBJECT (demux, "received new segment: rate %g "
+ "format %d, start: %" G_GINT64_FORMAT ", stop: %" G_GINT64_FORMAT
+ ", time: %" G_GINT64_FORMAT, rate, format, start, stop, time);
+ if (format == GST_FORMAT_BYTES && demux->bitrate != -1) {
+ gint64 tstart = 0, tstop = 0, pos = 0;
+
+ if (demux->base_pts != GST_CLOCK_TIME_NONE) {
+ tstart = tstop = demux->base_pts;
+ }
+ tstart += BYTES_TO_GSTTIME (start);
+ tstop += BYTES_TO_GSTTIME (stop);
+ pos = BYTES_TO_GSTTIME (time);
+
+ event = gst_event_new_new_segment (update, rate,
+ GST_FORMAT_TIME, tstart, tstop, pos);
+ GST_DEBUG_OBJECT (demux, "pushing time newsegment from %"
+ GST_TIME_FORMAT " to %" GST_TIME_FORMAT " pos %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (tstart), GST_TIME_ARGS (tstop), GST_TIME_ARGS (pos));
+
+ res = gst_mpegts_demux_send_event (demux, event);
+ }
break;
+ }
default:
res = gst_mpegts_demux_send_event (demux, event);
break;
}
gst_object_unref (demux);
- return TRUE;
+ return res;
}
static gboolean
@@ -2415,8 +2658,7 @@ gst_mpegts_demux_provide_clock (GstElement * element)
"MpegTSClock", NULL);
demux->clock_base = GST_CLOCK_TIME_NONE;
}
-
- return demux->clock;
+ return gst_object_ref (demux->clock);
}
return NULL;
@@ -2455,21 +2697,54 @@ gst_mpegts_demux_src_pad_query (GstPad * pad, GstQuery * query)
case GST_QUERY_DURATION:
{
GstFormat format;
- gint64 duration;
+ GstPad *peer;
- gst_query_parse_duration (query, &format, &duration);
+ gst_query_parse_duration (query, &format, NULL);
- if (format == GST_FORMAT_BYTES) {
- res = FALSE;
- } else {
- res = gst_pad_query_default (pad, query);
+ /* Try query upstream first */
+ peer = gst_pad_get_peer (demux->sinkpad);
+ if (peer) {
+ res = gst_pad_query (peer, query);
+ /* Try doing something with that query if it failed */
+ if (!res && format == GST_FORMAT_TIME && demux->bitrate != -1) {
+ /* Try using cache first */
+ if (GST_CLOCK_TIME_IS_VALID (demux->cache_duration)) {
+ GST_LOG_OBJECT (demux, "replying duration query from cache %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (demux->cache_duration));
+ gst_query_set_duration (query, GST_FORMAT_TIME,
+ demux->cache_duration);
+ res = TRUE;
+ } else { /* Query upstream and approximate */
+ GstQuery *bquery = gst_query_new_duration (GST_FORMAT_BYTES);
+ gint64 duration = 0;
+
+ /* Query peer for duration in bytes */
+ res = gst_pad_query (peer, bquery);
+ if (res) {
+ /* Convert to time format */
+ gst_query_parse_duration (bquery, &format, &duration);
+ GST_DEBUG_OBJECT (demux, "query on peer pad reported bytes %"
+ G_GUINT64_FORMAT, duration);
+ demux->cache_duration = BYTES_TO_GSTTIME (duration);
+ GST_DEBUG_OBJECT (demux, "converted to time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->cache_duration));
+ gst_query_set_duration (query, GST_FORMAT_TIME,
+ demux->cache_duration);
+ }
+ gst_query_unref (bquery);
+ }
+ } else {
+ GST_WARNING_OBJECT (demux, "unsupported query format or no bitrate "
+ "yet to approximate duration from bytes");
+ }
+ gst_object_unref (peer);
}
-
break;
}
default:
res = gst_pad_query_default (pad, query);
}
+ gst_object_unref (demux);
return res;
}
@@ -2554,9 +2829,7 @@ gst_mpegts_demux_chain (GstPad * pad, GstBuffer * buffer)
guint sync_count;
if (GST_BUFFER_IS_DISCONT (buffer)) {
- /* Flush buffered PES data */
- gst_mpegts_demux_pes_buffer_flush (demux);
- gst_adapter_clear (demux->adapter);
+ gst_mpegts_demux_flush (demux, FALSE);
}
/* first push the new buffer into the adapter */
gst_adapter_push (demux->adapter, buffer);
diff --git a/gst/mpegdemux/gstmpegtsdemux.h b/gst/mpegdemux/gstmpegtsdemux.h
index 8a4ca3d2..fde68926 100644
--- a/gst/mpegdemux/gstmpegtsdemux.h
+++ b/gst/mpegdemux/gstmpegtsdemux.h
@@ -34,9 +34,9 @@
*
* The Original Code is Fluendo MPEG Demuxer plugin.
*
- * The Initial Developer of the Original Code is Fluendo, S.L.
- * Portions created by Fluendo, S.L. are Copyright (C) 2005
- * Fluendo, S.L. All Rights Reserved.
+ * The Initial Developer of the Original Code is Fluendo, S.A.
+ * Portions created by Fluendo, S.A. are Copyright (C) 2005,2006,2007,2008,2009
+ * Fluendo, S.A. All Rights Reserved.
*
* Contributor(s): Wim Taymans <wim@fluendo.com>
*/
@@ -205,6 +205,21 @@ struct _GstMpegTSDemux {
/* clocking */
GstClock * clock;
GstClockTime clock_base;
+
+ /* Additional information required for seeking.
+ * num_packets: Number of packets outputted
+ * bitrate: estimated bitrate (based on pcr and num_packets */
+ guint64 num_packets;
+ gint64 bitrate;
+
+ /* Two PCRs observations to calculate bitrate */
+ guint64 pcr[2];
+
+ /* Cached duration estimation */
+ GstClockTime cache_duration;
+
+ /* Cached base_PCR in GStreamer time. */
+ GstClockTime base_pts;
};
struct _GstMpegTSDemuxClass {
@@ -213,6 +228,7 @@ struct _GstMpegTSDemuxClass {
GstPadTemplate * sink_template;
GstPadTemplate * video_template;
GstPadTemplate * audio_template;
+ GstPadTemplate * subpicture_template;
GstPadTemplate * private_template;
};
diff --git a/gst/mpegdemux/gstpesfilter.c b/gst/mpegdemux/gstpesfilter.c
index 1295a193..b520c766 100644
--- a/gst/mpegdemux/gstpesfilter.c
+++ b/gst/mpegdemux/gstpesfilter.c
@@ -167,6 +167,9 @@ gst_pes_filter_parse (GstPESFilter * filter)
avail = MIN (avail, filter->length + 6);
}
+ if (avail < 7)
+ goto need_more_data;
+
/* read more data, either the whole packet if there is a length
* or whatever we have available if this in an unbounded packet. */
if (!(data = gst_adapter_peek (filter->adapter, avail)))
@@ -189,7 +192,8 @@ gst_pes_filter_parse (GstPESFilter * filter)
case ID_PROGRAM_STREAM_DIRECTORY:
case ID_DSMCC_STREAM:
case ID_ITU_TREC_H222_TYPE_E_STREAM:
- goto skip;
+ /* Push directly out */
+ goto push_out;
case ID_PADDING_STREAM:
GST_DEBUG ("skipping padding stream");
goto skip;
@@ -197,9 +201,6 @@ gst_pes_filter_parse (GstPESFilter * filter)
break;
}
- if (datalen < 1)
- goto need_more_data;
-
filter->pts = filter->dts = -1;
/* stuffing bits, first two bits are '10' for mpeg2 pes so this code is
@@ -404,6 +405,7 @@ gst_pes_filter_parse (GstPESFilter * filter)
goto lost_sync;
}
+push_out:
{
GstBuffer *out;
guint16 consumed;
@@ -563,14 +565,8 @@ gst_pes_filter_process (GstPESFilter * filter)
ret = GST_FLOW_OK;
} else {
GstBuffer *out;
- guint8 *data;
-
- data = gst_adapter_take (filter->adapter, avail);
- out = gst_buffer_new ();
- GST_BUFFER_DATA (out) = data;
- GST_BUFFER_SIZE (out) = avail;
- GST_BUFFER_MALLOCDATA (out) = data;
+ out = gst_adapter_take_buffer (filter->adapter, avail);
ret = gst_pes_filter_data_push (filter, filter->first, out);
filter->first = FALSE;
diff --git a/gst/mpegdemux/gstpesfilter.h b/gst/mpegdemux/gstpesfilter.h
index b35d8746..ccc8461d 100644
--- a/gst/mpegdemux/gstpesfilter.h
+++ b/gst/mpegdemux/gstpesfilter.h
@@ -84,8 +84,6 @@ struct _GstPESFilter {
gboolean unbounded_packet;
guint16 length;
- guint8 type;
-
gint64 pts;
gint64 dts;
};
diff --git a/gst/mpegdemux/mpegtspacketizer.c b/gst/mpegdemux/mpegtspacketizer.c
index 1abbf1fe..b986fa60 100644
--- a/gst/mpegdemux/mpegtspacketizer.c
+++ b/gst/mpegdemux/mpegtspacketizer.c
@@ -241,7 +241,8 @@ mpegts_packetizer_parse_section_header (MpegTSPacketizer * packetizer,
data = GST_BUFFER_DATA (section->buffer);
section->table_id = *data++;
- if ((data[0] & 0x80) == 0)
+ /* if table_id is 0 (pat) then ignore the subtable extension */
+ if ((data[0] & 0x80) == 0 || section->table_id == 0)
section->subtable_extension = 0;
else
section->subtable_extension = GST_READ_UINT16_BE (data + 2);
@@ -1844,6 +1845,22 @@ mpegts_packetizer_clear (MpegTSPacketizer * packetizer)
gst_adapter_clear (packetizer->adapter);
}
+void
+mpegts_packetizer_remove_stream (MpegTSPacketizer * packetizer, gint16 pid)
+{
+ MpegTSPacketizerStream *stream =
+ (MpegTSPacketizerStream *) g_hash_table_lookup (packetizer->streams,
+ GINT_TO_POINTER ((gint) pid));
+ if (stream) {
+ GST_INFO ("Removing stream for PID %d", pid);
+
+ g_hash_table_remove (packetizer->streams, GINT_TO_POINTER ((gint) pid));
+
+ g_object_unref (stream->section_adapter);
+ g_free (stream);
+ }
+}
+
MpegTSPacketizer *
mpegts_packetizer_new ()
{
diff --git a/gst/mpegdemux/mpegtspacketizer.h b/gst/mpegdemux/mpegtspacketizer.h
index c54228af..97e15cf2 100644
--- a/gst/mpegdemux/mpegtspacketizer.h
+++ b/gst/mpegdemux/mpegtspacketizer.h
@@ -116,6 +116,8 @@ gboolean mpegts_packetizer_next_packet (MpegTSPacketizer *packetizer,
MpegTSPacketizerPacket *packet);
void mpegts_packetizer_clear_packet (MpegTSPacketizer *packetizer,
MpegTSPacketizerPacket *packet);
+void mpegts_packetizer_remove_stream(MpegTSPacketizer *packetizer,
+ gint16 pid);
gboolean mpegts_packetizer_push_section (MpegTSPacketizer *packetzer,
MpegTSPacketizerPacket *packet, MpegTSPacketizerSection *section);
diff --git a/gst/mpegdemux/mpegtsparse.c b/gst/mpegdemux/mpegtsparse.c
index 3a2d647d..976935f2 100644
--- a/gst/mpegdemux/mpegtsparse.c
+++ b/gst/mpegdemux/mpegtsparse.c
@@ -266,12 +266,15 @@ mpegts_parse_init (MpegTSParse * parse, MpegTSParseClass * klass)
gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
parse->disposed = FALSE;
+ parse->need_sync_program_pads = FALSE;
parse->packetizer = mpegts_packetizer_new ();
parse->program_numbers = g_strdup ("");
parse->pads_to_add = NULL;
+ parse->pads_to_remove = NULL;
parse->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) mpegts_parse_free_program);
parse->psi_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
+ parse->pes_pids = g_hash_table_new (g_direct_hash, g_direct_equal);
mpegts_parse_reset (parse);
}
@@ -301,6 +304,7 @@ mpegts_parse_finalize (GObject * object)
}
g_hash_table_destroy (parse->programs);
g_hash_table_destroy (parse->psi_pids);
+ g_hash_table_destroy (parse->pes_pids);
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -348,7 +352,7 @@ mpegts_parse_add_program (MpegTSParse * parse,
program->pcr_pid = G_MAXUINT16;
program->streams = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) mpegts_parse_free_stream);
- program->patcount = 1;
+ program->patcount = 0;
program->selected = 0;
program->active = FALSE;
@@ -422,22 +426,30 @@ mpegts_parse_remove_program (MpegTSParse * parse, gint program_number)
}
static void
-mpegts_parse_sync_program_pads (MpegTSParse * parse,
- GList * to_add, GList * to_remove)
+mpegts_parse_sync_program_pads (MpegTSParse * parse)
{
GList *walk;
- for (walk = to_remove; walk; walk = walk->next)
+ GST_INFO_OBJECT (parse, "begin sync pads");
+ for (walk = parse->pads_to_remove; walk; walk = walk->next)
gst_element_remove_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
- for (walk = to_add; walk; walk = walk->next)
+ for (walk = parse->pads_to_add; walk; walk = walk->next)
gst_element_add_pad (GST_ELEMENT (parse), GST_PAD (walk->data));
- if (to_add)
- g_list_free (to_add);
+ if (parse->pads_to_add)
+ g_list_free (parse->pads_to_add);
+
+ if (parse->pads_to_remove)
+ g_list_free (parse->pads_to_remove);
+
+ GST_OBJECT_LOCK (parse);
+ parse->pads_to_remove = NULL;
+ parse->pads_to_add = NULL;
+ parse->need_sync_program_pads = FALSE;
+ GST_OBJECT_UNLOCK (parse);
- if (to_remove)
- g_list_free (to_remove);
+ GST_INFO_OBJECT (parse, "end sync pads");
}
@@ -493,9 +505,6 @@ static void
mpegts_parse_reset_selected_programs (MpegTSParse * parse,
gchar * program_numbers)
{
- GList *pads_to_add = NULL;
- GList *pads_to_remove = NULL;
-
GST_OBJECT_LOCK (parse);
if (parse->program_numbers)
g_free (parse->program_numbers);
@@ -526,13 +535,9 @@ mpegts_parse_reset_selected_programs (MpegTSParse * parse,
g_hash_table_foreach (parse->programs,
foreach_program_activate_or_deactivate, parse);
- pads_to_add = parse->pads_to_add;
- parse->pads_to_add = NULL;
- pads_to_remove = parse->pads_to_remove;
- parse->pads_to_remove = NULL;
+ if (parse->pads_to_remove || parse->pads_to_add)
+ parse->need_sync_program_pads = TRUE;
GST_OBJECT_UNLOCK (parse);
-
- mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove);
}
static void
@@ -804,6 +809,10 @@ mpegts_parse_is_psi (MpegTSParse * parse, MpegTSPacketizerPacket * packet)
if (g_hash_table_lookup (parse->psi_pids,
GINT_TO_POINTER ((gint) packet->pid)) != NULL)
retval = TRUE;
+ /* check is it is a pes pid */
+ if (g_hash_table_lookup (parse->pes_pids,
+ GINT_TO_POINTER ((gint) packet->pid)) != NULL)
+ return FALSE;
if (!retval) {
if (packet->payload_unit_start_indicator) {
table_id = *(packet->data);
@@ -850,8 +859,6 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
guint pid;
MpegTSParseProgram *program;
gint i;
- GList *pads_to_add = NULL;
- GList *pads_to_remove = NULL;
const GValue *programs;
gchar *dbg;
@@ -889,14 +896,12 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
g_hash_table_insert (parse->psi_pids,
GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
}
-
- program->patcount += 1;
} else {
g_hash_table_insert (parse->psi_pids,
GINT_TO_POINTER ((gint) pid), GINT_TO_POINTER (1));
program = mpegts_parse_add_program (parse, program_number, pid);
}
-
+ program->patcount += 1;
if (program->selected && !program->active)
parse->pads_to_add = g_list_append (parse->pads_to_add,
mpegts_parse_activate_program (parse, program));
@@ -937,18 +942,15 @@ mpegts_parse_apply_pat (MpegTSParse * parse, GstStructure * pat_info)
mpegts_parse_remove_program (parse, program_number);
g_hash_table_remove (parse->psi_pids, GINT_TO_POINTER ((gint) pid));
+ mpegts_packetizer_remove_stream (parse->packetizer, pid);
}
gst_structure_free (old_pat);
}
- pads_to_add = parse->pads_to_add;
- parse->pads_to_add = NULL;
- pads_to_remove = parse->pads_to_remove;
- parse->pads_to_remove = NULL;
GST_OBJECT_UNLOCK (parse);
- mpegts_parse_sync_program_pads (parse, pads_to_add, pads_to_remove);
+ mpegts_parse_sync_program_pads (parse);
}
static void
@@ -983,10 +985,13 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
gst_structure_get_uint (stream, "pid", &pid);
gst_structure_get_uint (stream, "stream-type", &stream_type);
mpegts_parse_program_remove_stream (parse, program, (guint16) pid);
+ g_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid));
}
/* remove pcr stream */
mpegts_parse_program_remove_stream (parse, program, program->pcr_pid);
+ g_hash_table_remove (parse->pes_pids,
+ GINT_TO_POINTER ((gint) program->pcr_pid));
gst_structure_free (program->pmt_info);
program->pmt_info = NULL;
@@ -1003,6 +1008,8 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
program->pmt_pid = pmt_pid;
program->pcr_pid = pcr_pid;
mpegts_parse_program_add_stream (parse, program, (guint16) pcr_pid, -1);
+ g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pcr_pid),
+ GINT_TO_POINTER (1));
for (i = 0; i < gst_value_list_get_size (new_streams); ++i) {
value = gst_value_list_get_value (new_streams, i);
@@ -1012,6 +1019,9 @@ mpegts_parse_apply_pmt (MpegTSParse * parse,
gst_structure_get_uint (stream, "stream-type", &stream_type);
mpegts_parse_program_add_stream (parse, program,
(guint16) pid, (guint8) stream_type);
+ g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid),
+ GINT_TO_POINTER ((gint) 1));
+
}
GST_OBJECT_UNLOCK (parse);
@@ -1226,6 +1236,9 @@ mpegts_parse_chain (GstPad * pad, GstBuffer * buf)
mpegts_packetizer_clear_packet (parse->packetizer, &packet);
}
+ if (parse->need_sync_program_pads)
+ mpegts_parse_sync_program_pads (parse);
+
gst_object_unref (parse);
return res;
}
diff --git a/gst/mpegdemux/mpegtsparse.h b/gst/mpegdemux/mpegtsparse.h
index 34a78634..36466b81 100644
--- a/gst/mpegdemux/mpegtsparse.h
+++ b/gst/mpegdemux/mpegtsparse.h
@@ -60,7 +60,9 @@ struct _MpegTSParse {
GstStructure *pat;
MpegTSPacketizer *packetizer;
GHashTable *psi_pids;
+ GHashTable *pes_pids;
gboolean disposed;
+ gboolean need_sync_program_pads;
};
struct _MpegTSParseClass {
diff --git a/gst/mpegvideoparse/mpegpacketiser.c b/gst/mpegvideoparse/mpegpacketiser.c
index 447c50ae..0312680e 100644
--- a/gst/mpegvideoparse/mpegpacketiser.c
+++ b/gst/mpegvideoparse/mpegpacketiser.c
@@ -498,6 +498,9 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
case MPEG_PACKET_EXT_SEQUENCE:
{
/* Parse a Sequence Extension */
+ guint8 profile_level;
+ gboolean low_delay;
+ guint8 chroma_format;
guint8 horiz_size_ext, vert_size_ext;
guint8 fps_n_ext, fps_d_ext;
@@ -505,8 +508,12 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
/* need at least 10 bytes, minus 4 for the start code 000001b5 */
return FALSE;
+ profile_level = ((data[0] << 4) & 0xf0) | ((data[1]) >> 4);
+ hdr->progressive = data[1] & 0x08;
+ chroma_format = (data[1] >> 2) & 0x03;
horiz_size_ext = ((data[1] << 1) & 0x02) | ((data[2] >> 7) & 0x01);
vert_size_ext = (data[2] >> 5) & 0x03;
+ low_delay = data[5] >> 7;
fps_n_ext = (data[5] >> 5) & 0x03;
fps_d_ext = data[5] & 0x1f;
diff --git a/gst/mpegvideoparse/mpegpacketiser.h b/gst/mpegvideoparse/mpegpacketiser.h
index 426b13aa..549ca621 100644
--- a/gst/mpegvideoparse/mpegpacketiser.h
+++ b/gst/mpegvideoparse/mpegpacketiser.h
@@ -76,6 +76,8 @@ struct MPEGSeqHdr
gint width, height;
/* Framerate */
gint fps_n, fps_d;
+
+ gboolean progressive;
};
struct MPEGPictureHdr
diff --git a/gst/mpegvideoparse/mpegvideoparse.c b/gst/mpegvideoparse/mpegvideoparse.c
index 3c930179..2a7f9153 100644
--- a/gst/mpegvideoparse/mpegvideoparse.c
+++ b/gst/mpegvideoparse/mpegvideoparse.c
@@ -261,6 +261,7 @@ mpegvideoparse_handle_sequence (MpegVideoParse * mpegvideoparse,
"height", G_TYPE_INT, new_hdr.height,
"framerate", GST_TYPE_FRACTION, new_hdr.fps_n, new_hdr.fps_d,
"pixel-aspect-ratio", GST_TYPE_FRACTION, new_hdr.par_w, new_hdr.par_h,
+ "interlaced", G_TYPE_BOOLEAN, !new_hdr.progressive,
"codec_data", GST_TYPE_BUFFER, seq_buf, NULL);
GST_DEBUG ("New mpegvideoparse caps: %" GST_PTR_FORMAT, caps);
diff --git a/gst/mxf/mxf.c b/gst/mxf/mxf.c
index c1a0a716..7469317c 100644
--- a/gst/mxf/mxf.c
+++ b/gst/mxf/mxf.c
@@ -71,7 +71,8 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "mxfdemux", GST_RANK_PRIMARY,
GST_TYPE_MXF_DEMUX) ||
- !gst_element_register (plugin, "mxfmux", GST_RANK_NONE, GST_TYPE_MXF_MUX))
+ !gst_element_register (plugin, "mxfmux", GST_RANK_PRIMARY,
+ GST_TYPE_MXF_MUX))
return FALSE;
return TRUE;
diff --git a/gst/mxf/mxfdemux.c b/gst/mxf/mxfdemux.c
index 6d7ca034..c33650b5 100644
--- a/gst/mxf/mxfdemux.c
+++ b/gst/mxf/mxfdemux.c
@@ -203,7 +203,7 @@ gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
{
GST_DEBUG_OBJECT (demux, "Resetting metadata");
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_writer_lock (&demux->metadata_lock);
demux->update_metadata = TRUE;
demux->metadata_resolved = FALSE;
@@ -217,7 +217,7 @@ gst_mxf_demux_reset_metadata (GstMXFDemux * demux)
}
demux->metadata = mxf_metadata_hash_table_new ();
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
}
static void
@@ -513,11 +513,14 @@ gst_mxf_demux_resolve_references (GstMXFDemux * demux)
GstStructure *structure;
GstTagList *taglist;
+ g_static_rw_lock_writer_lock (&demux->metadata_lock);
+
GST_DEBUG_OBJECT (demux, "Resolve metadata references");
demux->update_metadata = FALSE;
if (!demux->metadata) {
GST_ERROR_OBJECT (demux, "No metadata yet");
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
return GST_FLOW_ERROR;
}
#if GLIB_CHECK_VERSION (2, 16, 0)
@@ -565,6 +568,8 @@ gst_mxf_demux_resolve_references (GstMXFDemux * demux)
g_list_free (values);
#endif
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
+
return ret;
error:
@@ -573,6 +578,7 @@ error:
#endif
demux->metadata_resolved = FALSE;
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
return ret;
}
@@ -913,24 +919,29 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
gboolean first_run;
guint component_index;
GstFlowReturn ret;
+ GList *pads = NULL, *l;
+ g_static_rw_lock_writer_lock (&demux->metadata_lock);
GST_DEBUG_OBJECT (demux, "Updating tracks");
if ((ret = gst_mxf_demux_update_essence_tracks (demux)) != GST_FLOW_OK) {
- return ret;
+ goto error;
}
current_package = gst_mxf_demux_choose_package (demux);
if (!current_package) {
GST_ERROR_OBJECT (demux, "Unable to find current package");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto error;
} else if (!current_package->tracks) {
GST_ERROR_OBJECT (demux, "Current package has no (resolved) tracks");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto error;
} else if (!current_package->n_essence_tracks) {
GST_ERROR_OBJECT (demux, "Current package has no essence tracks");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto error;
}
first_run = (demux->src->len == 0);
@@ -977,10 +988,12 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
if (!track->parent.sequence) {
GST_WARNING_OBJECT (demux, "Track with no sequence");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
sequence = track->parent.sequence;
@@ -1021,20 +1034,24 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
if (track->parent.type && (track->parent.type & 0xf0) != 0x30) {
GST_DEBUG_OBJECT (demux, "No essence track");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (!source_package || track->parent.type == MXF_METADATA_TRACK_UNKNOWN
|| !source_track) {
GST_WARNING_OBJECT (demux,
"No source package or track type for track found");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
for (k = 0; k < demux->essence_tracks->len; k++) {
@@ -1050,44 +1067,54 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
if (!etrack) {
GST_WARNING_OBJECT (demux, "No essence track for this track found");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (track->edit_rate.n <= 0 || track->edit_rate.d <= 0 ||
source_track->edit_rate.n <= 0 || source_track->edit_rate.d <= 0) {
GST_WARNING_OBJECT (demux, "Track has an invalid edit rate");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (MXF_IS_METADATA_MATERIAL_PACKAGE (current_package) && !component) {
GST_WARNING_OBJECT (demux,
"Playing material package but found no component for track");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (!source_package->descriptor) {
GST_WARNING_OBJECT (demux, "Source package has no descriptors");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (!source_track->parent.descriptor) {
GST_WARNING_OBJECT (demux, "No descriptor found for track");
- if (!pad)
+ if (!pad) {
continue;
- else
- return GST_FLOW_ERROR;
+ } else {
+ ret = GST_FLOW_ERROR;
+ goto error;
+ }
}
if (!pad && first_run) {
@@ -1178,31 +1205,43 @@ gst_mxf_demux_update_tracks (GstMXFDemux * demux)
gst_pad_use_fixed_caps (GST_PAD_CAST (pad));
gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (demux), gst_object_ref (pad));
+ pads = g_list_prepend (pads, gst_object_ref (pad));
g_ptr_array_add (demux->src, pad);
pad->discont = TRUE;
}
}
- if (first_run)
- gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
-
if (demux->src->len > 0) {
for (i = 0; i < demux->src->len; i++) {
GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
if (!pad->material_track || !pad->material_package) {
GST_ERROR_OBJECT (demux, "Unable to update existing pad");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto error;
}
}
} else {
GST_ERROR_OBJECT (demux, "Couldn't create any streams");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto error;
}
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
+
+ for (l = pads; l; l = l->next)
+ gst_element_add_pad (GST_ELEMENT_CAST (demux), l->data);
+ g_list_free (pads);
+
+ if (first_run)
+ gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
+
return GST_FLOW_OK;
+
+error:
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
+ return ret;
}
static GstFlowReturn
@@ -1276,7 +1315,7 @@ gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key,
return GST_FLOW_OK;
}
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_writer_lock (&demux->metadata_lock);
demux->update_metadata = TRUE;
if (MXF_IS_METADATA_PREFACE (metadata)) {
@@ -1287,7 +1326,7 @@ gst_mxf_demux_handle_metadata (GstMXFDemux * demux, const MXFUL * key,
g_hash_table_replace (demux->metadata,
&MXF_METADATA_BASE (metadata)->instance_uid, metadata);
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
return ret;
}
@@ -1365,7 +1404,7 @@ gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux,
return GST_FLOW_OK;
}
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_writer_lock (&demux->metadata_lock);
demux->update_metadata = TRUE;
gst_mxf_demux_reset_linked_metadata (demux);
@@ -1373,7 +1412,7 @@ gst_mxf_demux_handle_descriptive_metadata (GstMXFDemux * demux,
g_hash_table_replace (demux->metadata, &MXF_METADATA_BASE (m)->instance_uid,
m);
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_writer_unlock (&demux->metadata_lock);
return ret;
}
@@ -2224,17 +2263,14 @@ next_try:
/* resolve references etc */
- g_mutex_lock (demux->metadata_lock);
if (gst_mxf_demux_resolve_references (demux) !=
GST_FLOW_OK || gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
demux->current_partition->parsed_metadata = TRUE;
demux->offset =
demux->run_in + demux->current_partition->partition.this_partition -
demux->current_partition->partition.prev_partition;
- g_mutex_unlock (demux->metadata_lock);
goto next_try;
}
- g_mutex_unlock (demux->metadata_lock);
out:
if (buffer)
@@ -2253,7 +2289,6 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key,
#endif
GstFlowReturn ret = GST_FLOW_OK;
- g_mutex_lock (demux->metadata_lock);
if (demux->update_metadata
&& demux->preface
&& (demux->offset >=
@@ -2265,16 +2300,13 @@ gst_mxf_demux_handle_klv_packet (GstMXFDemux * demux, const MXFUL * key,
demux->current_partition->parsed_metadata = TRUE;
if ((ret = gst_mxf_demux_resolve_references (demux)) != GST_FLOW_OK ||
(ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
- g_mutex_unlock (demux->metadata_lock);
goto beach;
}
} else if (demux->metadata_resolved && demux->requested_package_string) {
if ((ret = gst_mxf_demux_update_tracks (demux)) != GST_FLOW_OK) {
- g_mutex_unlock (demux->metadata_lock);
goto beach;
}
}
- g_mutex_unlock (demux->metadata_lock);
if (!mxf_is_mxf_packet (key)) {
GST_WARNING_OBJECT (demux,
@@ -3106,15 +3138,12 @@ gst_mxf_demux_seek_push (GstMXFDemux * demux, GstEvent * event)
guint64 new_offset = -1;
GstEvent *e;
- g_mutex_lock (demux->metadata_lock);
if (!demux->metadata_resolved || demux->update_metadata) {
if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
- g_mutex_unlock (demux->metadata_lock);
goto unresolved_metadata;
}
}
- g_mutex_unlock (demux->metadata_lock);
/* Do the actual seeking */
for (i = 0; i < demux->src->len; i++) {
@@ -3266,15 +3295,12 @@ gst_mxf_demux_seek_pull (GstMXFDemux * demux, GstEvent * event)
if (flush || seeksegment.last_stop != demux->segment.last_stop) {
guint64 new_offset = -1;
- g_mutex_lock (demux->metadata_lock);
if (!demux->metadata_resolved || demux->update_metadata) {
if (gst_mxf_demux_resolve_references (demux) != GST_FLOW_OK ||
gst_mxf_demux_update_tracks (demux) != GST_FLOW_OK) {
- g_mutex_unlock (demux->metadata_lock);
goto unresolved_metadata;
}
}
- g_mutex_unlock (demux->metadata_lock);
/* Do the actual seeking */
for (i = 0; i < demux->src->len; i++) {
@@ -3455,11 +3481,11 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
pos = mxfpad->last_stop;
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_reader_lock (&demux->metadata_lock);
if (format == GST_FORMAT_DEFAULT && pos != GST_CLOCK_TIME_NONE) {
if (!mxfpad->material_track || mxfpad->material_track->edit_rate.n == 0
|| mxfpad->material_track->edit_rate.d == 0) {
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
goto error;
}
@@ -3468,7 +3494,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
mxfpad->material_track->edit_rate.n,
mxfpad->material_track->edit_rate.d * GST_SECOND);
}
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
GST_DEBUG_OBJECT (pad,
"Returning position %" G_GINT64_FORMAT " in format %s", pos,
@@ -3487,9 +3513,9 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT)
goto error;
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_reader_lock (&demux->metadata_lock);
if (!mxfpad->material_track || !mxfpad->material_track->parent.sequence) {
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
goto error;
}
@@ -3500,7 +3526,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
if (duration != -1 && format == GST_FORMAT_TIME) {
if (mxfpad->material_track->edit_rate.n == 0 ||
mxfpad->material_track->edit_rate.d == 0) {
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
goto error;
}
@@ -3509,7 +3535,7 @@ gst_mxf_demux_src_query (GstPad * pad, GstQuery * query)
GST_SECOND * mxfpad->material_track->edit_rate.d,
mxfpad->material_track->edit_rate.n);
}
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
GST_DEBUG_OBJECT (pad,
"Returning duration %" G_GINT64_FORMAT " in format %s", duration,
@@ -3746,7 +3772,7 @@ gst_mxf_demux_query (GstElement * element, GstQuery * query)
if (demux->src->len == 0)
goto done;
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_reader_lock (&demux->metadata_lock);
for (i = 0; i < demux->src->len; i++) {
GstMXFDemuxPad *pad = g_ptr_array_index (demux->src, i);
gint64 pdur = -1;
@@ -3765,7 +3791,7 @@ gst_mxf_demux_query (GstElement * element, GstQuery * query)
pad->material_track->edit_rate.n);
duration = MAX (duration, pdur);
}
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
if (duration == -1) {
GST_DEBUG_OBJECT (demux, "No duration known (yet)");
@@ -3862,7 +3888,7 @@ gst_mxf_demux_get_property (GObject * object, guint prop_id,
case PROP_STRUCTURE:{
GstStructure *s;
- g_mutex_lock (demux->metadata_lock);
+ g_static_rw_lock_reader_lock (&demux->metadata_lock);
if (demux->preface)
s = mxf_metadata_base_to_structure (MXF_METADATA_BASE (demux->preface));
else
@@ -3873,7 +3899,7 @@ gst_mxf_demux_get_property (GObject * object, guint prop_id,
if (s)
gst_structure_free (s);
- g_mutex_unlock (demux->metadata_lock);
+ g_static_rw_lock_reader_unlock (&demux->metadata_lock);
break;
}
default:
@@ -3911,10 +3937,7 @@ gst_mxf_demux_finalize (GObject * object)
g_hash_table_destroy (demux->metadata);
- if (demux->metadata_lock) {
- g_mutex_free (demux->metadata_lock);
- demux->metadata_lock = NULL;
- }
+ g_static_rw_lock_free (&demux->metadata_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -3990,7 +4013,7 @@ gst_mxf_demux_init (GstMXFDemux * demux, GstMXFDemuxClass * g_class)
demux->max_drift = 500 * GST_MSECOND;
demux->adapter = gst_adapter_new ();
- demux->metadata_lock = g_mutex_new ();
+ g_static_rw_lock_init (&demux->metadata_lock);
demux->src = g_ptr_array_new ();
demux->essence_tracks =
diff --git a/gst/mxf/mxfdemux.h b/gst/mxf/mxfdemux.h
index c8439cf6..e8b90261 100644
--- a/gst/mxf/mxfdemux.h
+++ b/gst/mxf/mxfdemux.h
@@ -154,7 +154,7 @@ struct _GstMXFDemux
GArray *random_index_pack;
/* Metadata */
- GMutex *metadata_lock;
+ GStaticRWLock metadata_lock;
gboolean update_metadata;
gboolean pull_footer_metadata;
diff --git a/gst/mxf/mxfmetadata.c b/gst/mxf/mxfmetadata.c
index 2237bc60..7d1af0c1 100644
--- a/gst/mxf/mxfmetadata.c
+++ b/gst/mxf/mxfmetadata.c
@@ -4984,7 +4984,7 @@ gboolean
s = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_boolean (s, "interlaced", &interlaced) || !interlaced)
- self->frame_layout = 1;
+ self->frame_layout = 0;
else
self->frame_layout = 3;
diff --git a/gst/mxf/mxfmux.c b/gst/mxf/mxfmux.c
index 3ca60a4e..fdc1bc61 100644
--- a/gst/mxf/mxfmux.c
+++ b/gst/mxf/mxfmux.c
@@ -163,6 +163,8 @@ gst_mxf_mux_finalize (GObject * object)
if (mux->metadata) {
g_hash_table_destroy (mux->metadata);
mux->metadata = NULL;
+ g_list_free (mux->metadata_list);
+ mux->metadata_list = NULL;
}
gst_object_unref (mux->collect);
@@ -216,6 +218,8 @@ gst_mxf_mux_reset (GstMXFMux * mux)
if (mux->metadata) {
g_hash_table_destroy (mux->metadata);
mux->preface = NULL;
+ g_list_free (mux->metadata_list);
+ mux->metadata_list = NULL;
}
mux->metadata = mxf_metadata_hash_table_new ();
@@ -280,6 +284,7 @@ gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps)
gboolean ret = TRUE;
MXFUUID d_instance_uid = { {0,} };
MXFMetadataFileDescriptor *old_descriptor = cpad->descriptor;
+ GList *l;
GST_DEBUG_OBJECT (pad, "Setting caps %" GST_PTR_FORMAT, caps);
@@ -309,6 +314,19 @@ gst_mxf_mux_setcaps (GstPad * pad, GstCaps * caps)
memcpy (&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, &d_instance_uid,
16);
+ if (old_descriptor) {
+ for (l = mux->metadata_list; l; l = l->next) {
+ MXFMetadataBase *tmp = l->data;
+
+ if (mxf_uuid_is_equal (&d_instance_uid, &tmp->instance_uid)) {
+ l->data = cpad->descriptor;
+ break;
+ }
+ }
+ } else {
+ mux->metadata_list = g_list_prepend (mux->metadata_list, cpad->descriptor);
+ }
+
g_hash_table_replace (mux->metadata,
&MXF_METADATA_BASE (cpad->descriptor)->instance_uid, cpad->descriptor);
@@ -449,6 +467,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (mux->preface)->instance_uid, mux->preface);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, mux->preface);
mxf_timestamp_set_now (&mux->preface->last_modified_date);
mux->preface->version = 258;
@@ -505,6 +524,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (identification)->instance_uid, identification);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, identification);
mxf_uuid_init (&identification->this_generation_uid, NULL);
@@ -561,6 +581,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mxf_uuid_init (&MXF_METADATA_BASE (cstorage)->instance_uid, mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (cstorage)->instance_uid, cstorage);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, cstorage);
cstorage->n_packages = 2;
cstorage->packages = g_new0 (MXFMetadataGenericPackage *, 2);
@@ -576,6 +597,8 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (cstorage->packages[1])->instance_uid,
cstorage->packages[1]);
+ mux->metadata_list =
+ g_list_prepend (mux->metadata_list, cstorage->packages[1]);
p = (MXFMetadataSourcePackage *) cstorage->packages[1];
mxf_umid_init (&p->parent.package_uid);
@@ -601,6 +624,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mxf_uuid_init (&MXF_METADATA_BASE (d)->instance_uid, mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (d)->instance_uid, d);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, d);
}
/* Tracks */
@@ -621,6 +645,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (track)->instance_uid, track);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, track);
track->parent.track_id = n + 1;
track->parent.track_number =
@@ -637,6 +662,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
memcpy (&sequence->data_definition, &cpad->writer->data_definition,
16);
@@ -653,6 +679,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (clip)->instance_uid, clip);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
memcpy (&clip->parent.data_definition, &sequence->data_definition,
16);
@@ -687,6 +714,8 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (cstorage->packages[0])->instance_uid,
cstorage->packages[0]);
+ mux->metadata_list =
+ g_list_prepend (mux->metadata_list, cstorage->packages[0]);
p = (MXFMetadataMaterialPackage *) cstorage->packages[0];
mxf_umid_init (&p->package_uid);
@@ -724,6 +753,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (track)->instance_uid, track);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, track);
track->parent.track_id = n + 1;
track->parent.track_number = 0;
@@ -757,6 +787,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
memcpy (&sequence->data_definition, &cpad->writer->data_definition,
16);
@@ -772,6 +803,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (clip)->instance_uid, clip);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, clip);
memcpy (&clip->parent.data_definition, &sequence->data_definition,
16);
@@ -798,6 +830,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (track)->instance_uid, track);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, track);
track->parent.track_id = n + 1;
track->parent.track_number = 0;
@@ -811,6 +844,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (sequence)->instance_uid, sequence);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, sequence);
memcpy (&sequence->data_definition,
mxf_metadata_track_identifier_get
@@ -828,6 +862,7 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
mux->metadata);
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (component)->instance_uid, component);
+ mux->metadata_list = g_list_prepend (mux->metadata_list, component);
memcpy (&component->parent.data_definition,
&sequence->data_definition, 16);
@@ -884,6 +919,9 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
g_hash_table_insert (mux->metadata,
&MXF_METADATA_BASE (cstorage->essence_container_data[0])->instance_uid,
cstorage->essence_container_data[0]);
+ mux->metadata_list =
+ g_list_prepend (mux->metadata_list,
+ cstorage->essence_container_data[0]);
cstorage->essence_container_data[0]->linked_package =
MXF_METADATA_SOURCE_PACKAGE (cstorage->packages[1]);
@@ -891,6 +929,43 @@ gst_mxf_mux_create_metadata (GstMXFMux * mux)
cstorage->essence_container_data[0]->body_sid = 1;
}
+ /* Sort descriptors at the correct places */
+ {
+ GList *l;
+ GList *descriptors = NULL;
+
+ for (l = mux->metadata_list; l; l = l->next) {
+ MXFMetadataBase *m = l->data;
+
+ if (MXF_IS_METADATA_GENERIC_DESCRIPTOR (m)
+ && !MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m)) {
+ descriptors = l;
+ l->prev->next = NULL;
+ l->prev = NULL;
+ break;
+ }
+ }
+
+ g_assert (descriptors != NULL);
+
+ for (l = mux->metadata_list; l; l = l->next) {
+ MXFMetadataBase *m = l->data;
+ GList *s;
+
+ if (MXF_IS_METADATA_MULTIPLE_DESCRIPTOR (m) ||
+ MXF_IS_METADATA_SOURCE_PACKAGE (m)) {
+ s = l->prev;
+ l->prev = g_list_last (descriptors);
+ s->next = descriptors;
+ descriptors->prev = s;
+ l->prev->next = l;
+ break;
+ }
+ }
+ }
+
+ mux->metadata_list = g_list_reverse (mux->metadata_list);
+
return ret;
}
@@ -953,38 +1028,17 @@ gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buf;
GList *buffers = NULL;
-#if GLIB_CHECK_VERSION (2, 16, 0)
- GHashTableIter iter;
-#else
- GList *values;
-#endif
- MXFMetadataBase *m;
GList *l;
+ MXFMetadataBase *m;
guint64 header_byte_count = 0;
- buf =
- mxf_metadata_base_to_buffer (MXF_METADATA_BASE (mux->preface),
- &mux->primer);
- header_byte_count += GST_BUFFER_SIZE (buf);
- buffers = g_list_prepend (buffers, buf);
-
-#if GLIB_CHECK_VERSION (2, 16, 0)
- g_hash_table_iter_init (&iter, mux->metadata);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer) & m)) {
-#else
- values = g_hash_table_get_values (mux->metadata);
- for (l = values; l; l = l->next) {
+ for (l = mux->metadata_list; l; l = l->next) {
m = l->data;
-#endif
buf = mxf_metadata_base_to_buffer (m, &mux->primer);
header_byte_count += GST_BUFFER_SIZE (buf);
buffers = g_list_prepend (buffers, buf);
}
-#if !GLIB_CHECK_VERSION (2, 16, 0)
- g_list_free (values);
-#endif
-
buffers = g_list_reverse (buffers);
buf = mxf_primer_pack_to_buffer (&mux->primer);
header_byte_count += GST_BUFFER_SIZE (buf);
@@ -1006,7 +1060,7 @@ gst_mxf_mux_write_header_metadata (GstMXFMux * mux)
if ((ret = gst_mxf_mux_push (mux, buf)) != GST_FLOW_OK) {
GST_ERROR_OBJECT (mux, "Failed pushing buffer: %s",
gst_flow_get_name (ret));
- g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
+ g_list_foreach (l, (GFunc) gst_mini_object_unref, NULL);
g_list_free (buffers);
return ret;
}
@@ -1150,10 +1204,11 @@ gst_mxf_mux_handle_eos (GstMXFMux * mux)
best = cpad;
break;
}
- } else if (have_data && !l->next) {
+ }
+
+ if (have_data && !l->next) {
mux->last_gc_position++;
mux->last_gc_timestamp = next_gc_timestamp;
- have_data = FALSE;
best = NULL;
break;
}
diff --git a/gst/mxf/mxfmux.h b/gst/mxf/mxfmux.h
index c8fd0b09..94330c46 100644
--- a/gst/mxf/mxfmux.h
+++ b/gst/mxf/mxfmux.h
@@ -85,6 +85,7 @@ typedef struct _GstMXFMux {
MXFPrimerPack primer;
GHashTable *metadata;
+ GList *metadata_list;
MXFMetadataPreface *preface;
MXFFraction min_edit_rate;
diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c
index df6958e0..a5d8fe38 100644
--- a/gst/qtmux/atoms.c
+++ b/gst/qtmux/atoms.c
@@ -1855,13 +1855,11 @@ atom_stsd_copy_data (AtomSTSD * stsd, guint8 ** buffer, guint64 * size,
break;
default:
if (se->kind == VIDEO) {
- size +=
- sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *) walker->
- data, buffer, size, offset);
+ size += sample_entry_mp4v_copy_data ((SampleTableEntryMP4V *)
+ walker->data, buffer, size, offset);
} else if (se->kind == AUDIO) {
- size +=
- sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *) walker->
- data, buffer, size, offset);
+ size += sample_entry_mp4a_copy_data ((SampleTableEntryMP4A *)
+ walker->data, buffer, size, offset);
} else {
if (!atom_hint_sample_entry_copy_data (
(AtomHintSampleEntry *) walker->data, buffer, size, offset)) {
@@ -2547,6 +2545,7 @@ atom_moov_append_tag (AtomMOOV * moov, AtomInfo * tag)
{
AtomILST *ilst;
+ atom_moov_init_metatags (moov);
ilst = moov->udta->meta->ilst;
ilst->entries = g_list_append (ilst->entries, tag);
}
@@ -2563,7 +2562,6 @@ atom_moov_add_tag (AtomMOOV * moov, guint32 fourcc, guint32 flags,
atom_tag_data_alloc_data (tdata, size);
g_memmove (tdata->data, data, size);
- atom_moov_init_metatags (moov);
atom_moov_append_tag (moov,
build_atom_info_wrapper ((Atom *) tag, atom_tag_copy_data,
atom_tag_free));
diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c
index f3e85f5c..b0df9d71 100644
--- a/gst/qtmux/gstqtmux.c
+++ b/gst/qtmux/gstqtmux.c
@@ -1886,7 +1886,7 @@ gst_qt_mux_register (GstPlugin * plugin)
g_type_set_qdata (type, GST_QT_MUX_PARAMS_QDATA, (gpointer) params);
g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
- if (!gst_element_register (plugin, prop->name, GST_RANK_NONE, type))
+ if (!gst_element_register (plugin, prop->name, GST_RANK_PRIMARY, type))
return FALSE;
i++;
diff --git a/gst/qtmux/gstqtmuxmap.c b/gst/qtmux/gstqtmuxmap.c
index a4972661..11913670 100644
--- a/gst/qtmux/gstqtmuxmap.c
+++ b/gst/qtmux/gstqtmuxmap.c
@@ -174,7 +174,7 @@ GstQTMuxFormatProp gst_qt_mux_format_list[] = {
"3GPP",
"GstGPPMux",
GST_STATIC_CAPS ("video/quicktime, variant = (string) 3gpp"),
- GST_STATIC_CAPS (H263_CAPS "; " H264_CAPS),
+ GST_STATIC_CAPS (H263_CAPS "; " MPEG4V_CAPS "; " H264_CAPS),
GST_STATIC_CAPS (AMR_CAPS "; " MP3_CAPS "; " AAC_CAPS)
}
,
diff --git a/gst/rtpmanager/gstrtpbin-marshal.list b/gst/rtpmanager/gstrtpbin-marshal.list
index c4bc0bb2..ed73e43b 100644
--- a/gst/rtpmanager/gstrtpbin-marshal.list
+++ b/gst/rtpmanager/gstrtpbin-marshal.list
@@ -3,5 +3,6 @@ BOXED:UINT
BOXED:UINT,UINT
OBJECT:UINT
VOID:UINT,OBJECT
+VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT
diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
index 7d3b9823..19de4f1b 100644
--- a/gst/rtpmanager/gstrtpbin.c
+++ b/gst/rtpmanager/gstrtpbin.c
@@ -297,12 +297,17 @@ struct _GstRtpBinStream
/* the jitterbuffer of the SSRC */
GstElement *buffer;
+ gulong buffer_handlesync_sig;
+ gulong buffer_ptreq_sig;
+ gulong buffer_ntpstop_sig;
/* the PT demuxer of the SSRC */
GstElement *demux;
gulong demux_newpad_sig;
gulong demux_ptreq_sig;
gulong demux_pt_change_sig;
+ /* ghostpads from the ptdemuxer */
+ GSList *pads;
/* if we have calculated a valid unix_delta for this stream */
gboolean have_sync;
@@ -332,6 +337,7 @@ struct _GstRtpBinSession
/* the SSRC demuxer */
GstElement *demux;
gulong demux_newpad_sig;
+ gulong demux_padremoved_sig;
GMutex *lock;
@@ -343,12 +349,17 @@ struct _GstRtpBinSession
/* the pads of the session */
GstPad *recv_rtp_sink;
+ GstPad *recv_rtp_sink_ghost;
GstPad *recv_rtp_src;
GstPad *recv_rtcp_sink;
+ GstPad *recv_rtcp_sink_ghost;
GstPad *sync_src;
GstPad *send_rtp_sink;
+ GstPad *send_rtp_sink_ghost;
GstPad *send_rtp_src;
+ GstPad *send_rtp_src_ghost;
GstPad *send_rtcp_src;
+ GstPad *send_rtcp_src_ghost;
};
/* Manages the RTP streams that come from one client and should therefore be
@@ -389,9 +400,10 @@ find_session_by_pad (GstRtpBin * rtpbin, GstPad * pad)
for (walk = rtpbin->sessions; walk; walk = g_slist_next (walk)) {
GstRtpBinSession *sess = (GstRtpBinSession *) walk->data;
- if ((sess->recv_rtp_sink == pad) ||
- (sess->recv_rtcp_sink == pad) ||
- (sess->send_rtp_sink == pad) || (sess->send_rtcp_src == pad))
+ if ((sess->recv_rtp_sink_ghost == pad) ||
+ (sess->recv_rtcp_sink_ghost == pad) ||
+ (sess->send_rtp_sink_ghost == pad)
+ || (sess->send_rtcp_src_ghost == pad))
return sess;
}
return NULL;
@@ -467,6 +479,36 @@ on_npt_stop (GstElement * jbuf, GstRtpBinStream * stream)
stream->session->id, stream->ssrc);
}
+/* must be called with the SESSION lock */
+static GstRtpBinStream *
+find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
+{
+ GSList *walk;
+
+ for (walk = session->streams; walk; walk = g_slist_next (walk)) {
+ GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
+
+ if (stream->ssrc == ssrc)
+ return stream;
+ }
+ return NULL;
+}
+
+static void
+ssrc_demux_pad_removed (GstElement * element, guint ssrc, GstPad * pad,
+ GstRtpBinSession * session)
+{
+ GstRtpBinStream *stream = NULL;
+
+ GST_RTP_SESSION_LOCK (session);
+ if ((stream = find_stream_by_ssrc (session, ssrc)))
+ session->streams = g_slist_remove (session->streams, stream);
+ GST_RTP_SESSION_UNLOCK (session);
+
+ if (stream)
+ free_stream (stream);
+}
+
/* create a session with the given id. Must be called with RTP_BIN_LOCK */
static GstRtpBinSession *
create_session (GstRtpBin * rtpbin, gint id)
@@ -474,6 +516,7 @@ create_session (GstRtpBin * rtpbin, gint id)
GstRtpBinSession *sess;
GstElement *session, *demux;
gint i;
+ GstState target;
if (!(session = gst_element_factory_make ("gstrtpsession", NULL)))
goto no_session;
@@ -522,11 +565,16 @@ create_session (GstRtpBin * rtpbin, gint id)
g_signal_connect (sess->session, "on-sender-timeout",
(GCallback) on_sender_timeout, sess);
- /* FIXME, change state only to what's needed */
gst_bin_add (GST_BIN_CAST (rtpbin), session);
- gst_element_set_state (session, GST_STATE_PLAYING);
gst_bin_add (GST_BIN_CAST (rtpbin), demux);
- gst_element_set_state (demux, GST_STATE_PLAYING);
+
+ GST_OBJECT_LOCK (rtpbin);
+ target = GST_STATE_TARGET (rtpbin);
+ GST_OBJECT_UNLOCK (rtpbin);
+
+ /* change state only to what's needed */
+ gst_element_set_state (demux, target);
+ gst_element_set_state (session, target);
return sess;
@@ -545,16 +593,12 @@ no_demux:
}
static void
-free_session (GstRtpBinSession * sess)
+free_session (GstRtpBinSession * sess, GstRtpBin * bin)
{
- GstRtpBin *bin;
-
- bin = sess->bin;
-
GST_DEBUG_OBJECT (bin, "freeing session %p", sess);
- gst_element_set_state (sess->session, GST_STATE_NULL);
gst_element_set_state (sess->demux, GST_STATE_NULL);
+ gst_element_set_state (sess->session, GST_STATE_NULL);
if (sess->recv_rtp_sink != NULL) {
gst_element_release_request_pad (sess->session, sess->recv_rtp_sink);
@@ -588,27 +632,9 @@ free_session (GstRtpBinSession * sess)
g_mutex_free (sess->lock);
g_hash_table_destroy (sess->ptmap);
- bin->sessions = g_slist_remove (bin->sessions, sess);
-
g_free (sess);
}
-#if 0
-static GstRtpBinStream *
-find_stream_by_ssrc (GstRtpBinSession * session, guint32 ssrc)
-{
- GSList *walk;
-
- for (walk = session->streams; walk; walk = g_slist_next (walk)) {
- GstRtpBinStream *stream = (GstRtpBinStream *) walk->data;
-
- if (stream->ssrc == ssrc)
- return stream;
- }
- return NULL;
-}
-#endif
-
/* get the payload type caps for the specific payload @pt in @session */
static GstCaps *
get_pt_map (GstRtpBinSession * session, guint pt)
@@ -822,8 +848,9 @@ get_client (GstRtpBin * bin, guint8 len, guint8 * data, gboolean * created)
}
static void
-free_client (GstRtpBinClient * client)
+free_client (GstRtpBinClient * client, GstRtpBin * bin)
{
+ GST_DEBUG_OBJECT (bin, "freeing client %p", client);
g_slist_free (client->streams);
g_free (client->cname);
g_free (client);
@@ -1079,6 +1106,8 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
{
GstElement *buffer, *demux;
GstRtpBinStream *stream;
+ GstRtpBin *rtpbin;
+ GstState target;
if (!(buffer = gst_element_factory_make ("gstrtpjitterbuffer", NULL)))
goto no_jitterbuffer;
@@ -1086,9 +1115,11 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
if (!(demux = gst_element_factory_make ("gstrtpptdemux", NULL)))
goto no_demux;
+ rtpbin = session->bin;
+
stream = g_new0 (GstRtpBinStream, 1);
stream->ssrc = ssrc;
- stream->bin = session->bin;
+ stream->bin = rtpbin;
stream->session = session;
stream->buffer = buffer;
stream->demux = demux;
@@ -1097,22 +1128,29 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
session->streams = g_slist_prepend (session->streams, stream);
/* provide clock_rate to the jitterbuffer when needed */
- g_signal_connect (buffer, "request-pt-map",
+ stream->buffer_ptreq_sig = g_signal_connect (buffer, "request-pt-map",
(GCallback) pt_map_requested, session);
- g_signal_connect (buffer, "on-npt-stop", (GCallback) on_npt_stop, stream);
+ stream->buffer_ntpstop_sig = g_signal_connect (buffer, "on-npt-stop",
+ (GCallback) on_npt_stop, stream);
/* configure latency and packet lost */
- g_object_set (buffer, "latency", session->bin->latency, NULL);
- g_object_set (buffer, "do-lost", session->bin->do_lost, NULL);
+ g_object_set (buffer, "latency", rtpbin->latency, NULL);
+ g_object_set (buffer, "do-lost", rtpbin->do_lost, NULL);
- gst_bin_add (GST_BIN_CAST (session->bin), buffer);
- gst_element_set_state (buffer, GST_STATE_PLAYING);
- gst_bin_add (GST_BIN_CAST (session->bin), demux);
- gst_element_set_state (demux, GST_STATE_PLAYING);
+ gst_bin_add (GST_BIN_CAST (rtpbin), demux);
+ gst_bin_add (GST_BIN_CAST (rtpbin), buffer);
/* link stuff */
gst_element_link (buffer, demux);
+ GST_OBJECT_LOCK (rtpbin);
+ target = GST_STATE_TARGET (rtpbin);
+ GST_OBJECT_UNLOCK (rtpbin);
+
+ /* from sink to source */
+ gst_element_set_state (demux, target);
+ gst_element_set_state (buffer, target);
+
return stream;
/* ERRORS */
@@ -1133,16 +1171,29 @@ static void
free_stream (GstRtpBinStream * stream)
{
GstRtpBinSession *session;
+ GSList *walk;
session = stream->session;
- gst_element_set_state (stream->buffer, GST_STATE_NULL);
+ g_signal_handler_disconnect (stream->demux, stream->demux_newpad_sig);
+ g_signal_handler_disconnect (stream->demux, stream->demux_ptreq_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_handlesync_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_ptreq_sig);
+ g_signal_handler_disconnect (stream->buffer, stream->buffer_ntpstop_sig);
+
gst_element_set_state (stream->demux, GST_STATE_NULL);
+ gst_element_set_state (stream->buffer, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (session->bin), stream->buffer);
gst_bin_remove (GST_BIN_CAST (session->bin), stream->demux);
- session->streams = g_slist_remove (session->streams, stream);
+ for (walk = stream->pads; walk; walk = g_slist_next (walk)) {
+ GstPad *gpad = GST_PAD_CAST (walk->data);
+
+ gst_pad_set_active (gpad, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (session->bin), gpad);
+ }
+ g_slist_free (stream->pads);
g_free (stream);
}
@@ -1481,11 +1532,11 @@ gst_rtp_bin_dispose (GObject * object)
rtpbin = GST_RTP_BIN (object);
GST_DEBUG_OBJECT (object, "freeing sessions");
- g_slist_foreach (rtpbin->sessions, (GFunc) free_session, NULL);
+ g_slist_foreach (rtpbin->sessions, (GFunc) free_session, rtpbin);
g_slist_free (rtpbin->sessions);
rtpbin->sessions = NULL;
GST_DEBUG_OBJECT (object, "freeing clients");
- g_slist_foreach (rtpbin->clients, (GFunc) free_client, NULL);
+ g_slist_foreach (rtpbin->clients, (GFunc) free_client, rtpbin);
g_slist_free (rtpbin->clients);
rtpbin->clients = NULL;
@@ -1556,6 +1607,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type,
if (type < 0 || type > 8)
return;
+ GST_RTP_BIN_LOCK (bin);
+
GST_OBJECT_LOCK (bin);
g_free (bin->sdes[type]);
bin->sdes[type] = g_strdup (data);
@@ -1564,6 +1617,8 @@ gst_rtp_bin_set_sdes_string (GstRtpBin * bin, GstRTCPSDESType type,
for (item = bin->sessions; item; item = g_slist_next (item))
g_object_set (item->data, name, bin->sdes[type], NULL);
GST_OBJECT_UNLOCK (bin);
+
+ GST_RTP_BIN_UNLOCK (bin);
}
static gchar *
@@ -1836,6 +1891,8 @@ new_payload_found (GstElement * element, guint pt, GstPad * pad,
gst_pad_set_active (gpad, TRUE);
gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), gpad);
+ stream->pads = g_slist_prepend (stream->pads, gpad);
+
GST_RTP_BIN_SHUTDOWN_UNLOCK (rtpbin);
return;
@@ -1947,7 +2004,7 @@ new_ssrc_pad_found (GstElement * element, guint ssrc, GstPad * pad,
/* connect to the RTCP sync signal from the jitterbuffer */
GST_DEBUG_OBJECT (rtpbin, "connecting sync signal");
- g_signal_connect (stream->buffer,
+ stream->buffer_handlesync_sig = g_signal_connect (stream->buffer,
"handle-sync", (GCallback) gst_rtp_bin_handle_sync, stream);
/* connect to the new-pad signal of the payload demuxer, this will expose the
@@ -1986,7 +2043,7 @@ no_stream:
static GstPad *
create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result, *sinkdpad;
+ GstPad *sinkdpad;
guint sessid;
GstRtpBinSession *session;
GstPadLinkReturn lres;
@@ -2008,8 +2065,8 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
}
/* check if pad was requested */
- if (session->recv_rtp_sink != NULL)
- goto existed;
+ if (session->recv_rtp_sink_ghost != NULL)
+ return session->recv_rtp_sink_ghost;
GST_DEBUG_OBJECT (rtpbin, "getting RTP sink pad");
/* get recv_rtp pad and store */
@@ -2039,14 +2096,16 @@ create_recv_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
/* connect to the new-ssrc-pad signal of the SSRC demuxer */
session->demux_newpad_sig = g_signal_connect (session->demux,
"new-ssrc-pad", (GCallback) new_ssrc_pad_found, session);
+ session->demux_padremoved_sig = g_signal_connect (session->demux,
+ "removed-ssrc-pad", (GCallback) ssrc_demux_pad_removed, session);
GST_DEBUG_OBJECT (rtpbin, "ghosting session sink pad");
- result =
+ session->recv_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->recv_rtp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->recv_rtp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->recv_rtp_sink_ghost);
- return result;
+ return session->recv_rtp_sink_ghost;
/* ERRORS */
no_name:
@@ -2059,12 +2118,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: recv_rtp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad");
@@ -2078,10 +2131,31 @@ link_failed:
}
static void
-remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_recv_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->demux_newpad_sig) {
+ g_signal_handler_disconnect (session->demux, session->demux_newpad_sig);
+ session->demux_newpad_sig = 0;
+ }
+ if (session->demux_padremoved_sig) {
+ g_signal_handler_disconnect (session->demux, session->demux_padremoved_sig);
+ session->demux_padremoved_sig = 0;
+ }
+ if (session->recv_rtp_src) {
+ gst_object_unref (session->recv_rtp_src);
+ session->recv_rtp_src = NULL;
+ }
+ if (session->recv_rtp_sink) {
+ gst_element_release_request_pad (session->session, session->recv_rtp_sink);
+ gst_object_unref (session->recv_rtp_sink);
+ session->recv_rtp_sink = NULL;
+ }
+ if (session->recv_rtp_sink_ghost) {
+ gst_pad_set_active (session->recv_rtp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtp_sink_ghost);
+ session->recv_rtp_sink_ghost = NULL;
+ }
}
/* Create a pad for receiving RTCP for the session in @name. Must be called with
@@ -2091,7 +2165,6 @@ static GstPad *
create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
const gchar * name)
{
- GstPad *result;
guint sessid;
GstRtpBinSession *session;
GstPad *sinkdpad;
@@ -2114,8 +2187,8 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
}
/* check if pad was requested */
- if (session->recv_rtcp_sink != NULL)
- goto existed;
+ if (session->recv_rtcp_sink_ghost != NULL)
+ return session->recv_rtcp_sink_ghost;
/* get recv_rtp pad and store */
GST_DEBUG_OBJECT (rtpbin, "getting RTCP sink pad");
@@ -2137,12 +2210,13 @@ create_recv_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ,
if (lres != GST_PAD_LINK_OK)
goto link_failed;
- result =
+ session->recv_rtcp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->recv_rtcp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->recv_rtcp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtcp_sink_ghost);
- return result;
+ return session->recv_rtcp_sink_ghost;
/* ERRORS */
no_name:
@@ -2155,12 +2229,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: recv_rtcp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad");
@@ -2174,10 +2242,24 @@ link_failed:
}
static void
-remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->recv_rtcp_sink_ghost) {
+ gst_pad_set_active (session->recv_rtcp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->recv_rtcp_sink_ghost);
+ session->recv_rtcp_sink_ghost = NULL;
+ }
+ if (session->sync_src) {
+ /* releasing the request pad should also unref the sync pad */
+ gst_object_unref (session->sync_src);
+ session->sync_src = NULL;
+ }
+ if (session->recv_rtcp_sink) {
+ gst_element_release_request_pad (session->session, session->recv_rtcp_sink);
+ gst_object_unref (session->recv_rtcp_sink);
+ session->recv_rtcp_sink = NULL;
+ }
}
/* Create a pad for sending RTP for the session in @name. Must be called with
@@ -2186,7 +2268,6 @@ remove_recv_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
static GstPad *
create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result, *srcghost;
gchar *gname;
guint sessid;
GstRtpBinSession *session;
@@ -2206,8 +2287,8 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
}
/* check if pad was requested */
- if (session->send_rtp_sink != NULL)
- goto existed;
+ if (session->send_rtp_sink_ghost != NULL)
+ return session->send_rtp_sink_ghost;
/* get send_rtp pad and store */
session->send_rtp_sink =
@@ -2215,10 +2296,10 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
if (session->send_rtp_sink == NULL)
goto pad_failed;
- result =
+ session->send_rtp_sink_ghost =
gst_ghost_pad_new_from_template (name, session->send_rtp_sink, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->send_rtp_sink_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_sink_ghost);
/* get srcpad */
session->send_rtp_src =
@@ -2230,13 +2311,13 @@ create_send_rtp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
klass = GST_ELEMENT_GET_CLASS (rtpbin);
gname = g_strdup_printf ("send_rtp_src_%d", sessid);
templ = gst_element_class_get_pad_template (klass, "send_rtp_src_%d");
- srcghost =
+ session->send_rtp_src_ghost =
gst_ghost_pad_new_from_template (gname, session->send_rtp_src, templ);
- gst_pad_set_active (srcghost, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), srcghost);
+ gst_pad_set_active (session->send_rtp_src_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtp_src_ghost);
g_free (gname);
- return result;
+ return session->send_rtp_sink_ghost;
/* ERRORS */
no_name:
@@ -2249,12 +2330,6 @@ create_error:
/* create_session already warned */
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: send_rtp pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get session pad for session %d", sessid);
@@ -2269,10 +2344,30 @@ no_srcpad:
}
static void
-remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->send_rtp_src_ghost) {
+ gst_pad_set_active (session->send_rtp_src_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtp_src_ghost);
+ session->send_rtp_src_ghost = NULL;
+ }
+ if (session->send_rtp_src) {
+ gst_object_unref (session->send_rtp_src);
+ session->send_rtp_src = NULL;
+ }
+ if (session->send_rtp_sink) {
+ gst_element_release_request_pad (GST_ELEMENT_CAST (session->session),
+ session->send_rtp_sink);
+ gst_object_unref (session->send_rtp_sink);
+ session->send_rtp_sink = NULL;
+ }
+ if (session->send_rtp_sink_ghost) {
+ gst_pad_set_active (session->send_rtp_sink_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtp_sink_ghost);
+ session->send_rtp_sink_ghost = NULL;
+ }
}
/* Create a pad for sending RTCP for the session in @name. Must be called with
@@ -2281,7 +2376,6 @@ remove_send_rtp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
static GstPad *
create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
{
- GstPad *result;
guint sessid;
GstRtpBinSession *session;
@@ -2295,8 +2389,8 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
goto no_session;
/* check if pad was requested */
- if (session->send_rtcp_src != NULL)
- goto existed;
+ if (session->send_rtcp_src_ghost != NULL)
+ return session->send_rtcp_src_ghost;
/* get rtcp_src pad and store */
session->send_rtcp_src =
@@ -2304,12 +2398,12 @@ create_rtcp (GstRtpBin * rtpbin, GstPadTemplate * templ, const gchar * name)
if (session->send_rtcp_src == NULL)
goto pad_failed;
- result =
+ session->send_rtcp_src_ghost =
gst_ghost_pad_new_from_template (name, session->send_rtcp_src, templ);
- gst_pad_set_active (result, TRUE);
- gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), result);
+ gst_pad_set_active (session->send_rtcp_src_ghost, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpbin), session->send_rtcp_src_ghost);
- return result;
+ return session->send_rtcp_src_ghost;
/* ERRORS */
no_name:
@@ -2322,12 +2416,6 @@ no_session:
g_warning ("gstrtpbin: session with id %d does not exist", sessid);
return NULL;
}
-existed:
- {
- g_warning ("gstrtpbin: send_rtcp_src pad already requested for session %d",
- sessid);
- return NULL;
- }
pad_failed:
{
g_warning ("gstrtpbin: failed to get rtcp pad for session %d", sessid);
@@ -2336,10 +2424,19 @@ pad_failed:
}
static void
-remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session, GstPad * pad)
+remove_rtcp (GstRtpBin * rtpbin, GstRtpBinSession * session)
{
- g_warning ("gstrtpbin: releasing pad %s:%s is not implemented",
- GST_DEBUG_PAD_NAME (pad));
+ if (session->send_rtcp_src_ghost) {
+ gst_pad_set_active (session->send_rtcp_src_ghost, FALSE);
+ gst_element_remove_pad (GST_ELEMENT_CAST (rtpbin),
+ session->send_rtcp_src_ghost);
+ session->send_rtcp_src_ghost = NULL;
+ }
+ if (session->send_rtcp_src) {
+ gst_element_release_request_pad (session->session, session->send_rtcp_src);
+ gst_object_unref (session->send_rtcp_src);
+ session->send_rtcp_src = NULL;
+ }
}
/* If the requested name is NULL we should create a name with
@@ -2403,7 +2500,7 @@ gst_rtp_bin_request_new_pad (GstElement * element,
pad_name = g_strdup (name);
}
- GST_DEBUG ("Trying to request a pad with name %s", pad_name);
+ GST_DEBUG_OBJECT (rtpbin, "Trying to request a pad with name %s", pad_name);
/* figure out the template */
if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
@@ -2440,32 +2537,39 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
{
GstRtpBinSession *session;
GstRtpBin *rtpbin;
- GstPad *target = NULL;
g_return_if_fail (GST_IS_GHOST_PAD (pad));
g_return_if_fail (GST_IS_RTP_BIN (element));
rtpbin = GST_RTP_BIN (element);
- target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
- g_return_if_fail (target);
-
GST_RTP_BIN_LOCK (rtpbin);
- if (!(session = find_session_by_pad (rtpbin, target)))
+ GST_DEBUG_OBJECT (rtpbin, "Trying to release pad %s:%s",
+ GST_DEBUG_PAD_NAME (pad));
+
+ if (!(session = find_session_by_pad (rtpbin, pad)))
goto unknown_pad;
- if (session->recv_rtp_sink == target) {
- remove_recv_rtp (rtpbin, session, pad);
- } else if (session->recv_rtcp_sink == target) {
- remove_recv_rtcp (rtpbin, session, pad);
- } else if (session->send_rtp_sink == target) {
- remove_send_rtp (rtpbin, session, pad);
- } else if (session->send_rtcp_src == target) {
- remove_rtcp (rtpbin, session, pad);
+ if (session->recv_rtp_sink_ghost == pad) {
+ remove_recv_rtp (rtpbin, session);
+ } else if (session->recv_rtcp_sink_ghost == pad) {
+ remove_recv_rtcp (rtpbin, session);
+ } else if (session->send_rtp_sink_ghost == pad) {
+ remove_send_rtp (rtpbin, session);
+ } else if (session->send_rtcp_src_ghost == pad) {
+ remove_rtcp (rtpbin, session);
}
- GST_RTP_BIN_UNLOCK (rtpbin);
- gst_object_unref (target);
+ /* no more request pads, free the complete session */
+ if (session->recv_rtp_sink_ghost == NULL
+ && session->recv_rtcp_sink_ghost == NULL
+ && session->send_rtp_sink_ghost == NULL
+ && session->send_rtcp_src_ghost == NULL) {
+ GST_DEBUG_OBJECT (rtpbin, "no more pads for session %p", session);
+ rtpbin->sessions = g_slist_remove (rtpbin->sessions, session);
+ free_session (session, rtpbin);
+ }
+ GST_RTP_BIN_UNLOCK (rtpbin);
return;
@@ -2473,7 +2577,6 @@ gst_rtp_bin_release_pad (GstElement * element, GstPad * pad)
unknown_pad:
{
GST_RTP_BIN_UNLOCK (rtpbin);
- gst_object_unref (target);
g_warning ("gstrtpbin: %s:%s is not one of our request pads",
GST_DEBUG_PAD_NAME (pad));
return;
diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
index 035d82a8..c33fdfc6 100644
--- a/gst/rtpmanager/gstrtpsession.c
+++ b/gst/rtpmanager/gstrtpsession.c
@@ -323,63 +323,6 @@ on_ssrc_active (RTPSession * session, RTPSource * src, GstRtpSession * sess)
src->ssrc);
}
-static GstStructure *
-source_get_sdes_structure (RTPSource * src)
-{
- GstStructure *result;
- GValue val = { 0 };
- gchar *str;
-
- result = gst_structure_empty_new ("GstRTPSessionSDES");
-
- gst_structure_set (result, "ssrc", G_TYPE_UINT, src->ssrc, NULL);
-
- g_value_init (&val, G_TYPE_STRING);
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "cname", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NAME);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "name", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_EMAIL);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "email", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PHONE);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "phone", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_LOC);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "location", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_TOOL);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "tool", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_NOTE);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "note", &val);
- }
- str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_PRIV);
- if (str) {
- g_value_take_string (&val, str);
- gst_structure_set_value (result, "priv", &val);
- }
- g_value_unset (&val);
-
- return result;
-}
-
static void
on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
@@ -388,8 +331,9 @@ on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
/* convert the new SDES info into a message */
RTP_SESSION_LOCK (session);
- s = source_get_sdes_structure (src);
+ g_object_get (src, "sdes", &s, NULL);
RTP_SESSION_UNLOCK (session);
+
m = gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (sess), s);
gst_element_post_message (GST_ELEMENT_CAST (sess), m);
diff --git a/gst/rtpmanager/gstrtpssrcdemux.c b/gst/rtpmanager/gstrtpssrcdemux.c
index 64394c45..6a305d8e 100644
--- a/gst/rtpmanager/gstrtpssrcdemux.c
+++ b/gst/rtpmanager/gstrtpssrcdemux.c
@@ -97,6 +97,8 @@ static GstElementDetails gst_rtp_ssrc_demux_details = {
enum
{
SIGNAL_NEW_SSRC_PAD,
+ SIGNAL_REMOVED_SSRC_PAD,
+ SIGNAL_CLEAR_SSRC,
LAST_SIGNAL
};
@@ -112,6 +114,9 @@ static void gst_rtp_ssrc_demux_finalize (GObject * object);
static GstStateChangeReturn gst_rtp_ssrc_demux_change_state (GstElement *
element, GstStateChange transition);
+static void gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux,
+ guint32 ssrc);
+
/* sinkpad stuff */
static GstFlowReturn gst_rtp_ssrc_demux_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event);
@@ -245,9 +250,11 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
{
GObjectClass *gobject_klass;
GstElementClass *gstelement_klass;
+ GstRtpSsrcDemuxClass *gstrtpssrcdemux_klass;
gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass;
+ gstrtpssrcdemux_klass = (GstRtpSsrcDemuxClass *) klass;
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_dispose);
gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_finalize);
@@ -267,8 +274,38 @@ gst_rtp_ssrc_demux_class_init (GstRtpSsrcDemuxClass * klass)
NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
+ /**
+ * GstRtpSsrcDemux::removed-ssrc-pad:
+ * @demux: the object which received the signal
+ * @ssrc: the SSRC of the pad
+ * @pad: the removed pad.
+ *
+ * Emited when a SSRC pad has been removed.
+ */
+ gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD] =
+ g_signal_new ("removed-ssrc-pad",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, removed_ssrc_pad),
+ NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_OBJECT,
+ G_TYPE_NONE, 2, G_TYPE_UINT, GST_TYPE_PAD);
+
+ /**
+ * GstRtpSsrcDemux::clear-ssrc:
+ * @demux: the object which received the signal
+ * @ssrc: the SSRC of the pad
+ *
+ * Action signal to remove the pad for SSRC.
+ */
+ gst_rtp_ssrc_demux_signals[SIGNAL_CLEAR_SSRC] =
+ g_signal_new ("clear-ssrc",
+ G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GstRtpSsrcDemuxClass, clear_ssrc),
+ NULL, NULL, gst_rtp_bin_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
+
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_change_state);
+ gstrtpssrcdemux_klass->clear_ssrc =
+ GST_DEBUG_FUNCPTR (gst_rtp_ssrc_demux_clear_ssrc);
GST_DEBUG_CATEGORY_INIT (gst_rtp_ssrc_demux_debug,
"rtpssrcdemux", 0, "RTP SSRC demuxer");
@@ -342,6 +379,43 @@ gst_rtp_ssrc_demux_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static void
+gst_rtp_ssrc_demux_clear_ssrc (GstRtpSsrcDemux * demux, guint32 ssrc)
+{
+ GstRtpSsrcDemuxPad *dpad;
+
+ GST_PAD_LOCK (demux);
+ dpad = find_demux_pad_for_ssrc (demux, ssrc);
+ if (dpad != NULL)
+ goto unknown_pad;
+
+ GST_DEBUG_OBJECT (demux, "clearing pad for SSRC %08x", ssrc);
+
+ demux->srcpads = g_slist_remove (demux->srcpads, dpad);
+ GST_PAD_UNLOCK (demux);
+
+ gst_pad_set_active (dpad->rtp_pad, FALSE);
+ gst_pad_set_active (dpad->rtcp_pad, FALSE);
+
+ g_signal_emit (G_OBJECT (demux),
+ gst_rtp_ssrc_demux_signals[SIGNAL_REMOVED_SSRC_PAD], 0, ssrc,
+ dpad->rtp_pad);
+
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtp_pad);
+ gst_element_remove_pad (GST_ELEMENT_CAST (demux), dpad->rtcp_pad);
+
+ g_free (dpad);
+
+ return;
+
+ /* ERRORS */
+unknown_pad:
+ {
+ g_warning ("unknown SSRC %08x", ssrc);
+ return;
+ }
+}
+
static gboolean
gst_rtp_ssrc_demux_sink_event (GstPad * pad, GstEvent * event)
{
@@ -483,7 +557,7 @@ gst_rtp_ssrc_demux_rtcp_chain (GstPad * pad, GstBuffer * buf)
NULL);
break;
default:
- goto invalid_rtcp;
+ goto unexpected_rtcp;
}
GST_DEBUG_OBJECT (demux, "received RTCP of SSRC %08x", ssrc);
@@ -511,6 +585,12 @@ invalid_rtcp:
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
+unexpected_rtcp:
+ {
+ GST_DEBUG_OBJECT (demux, "dropping unexpected RTCP packet");
+ gst_buffer_unref (buf);
+ return GST_FLOW_OK;
+ }
create_failed:
{
GST_ELEMENT_ERROR (demux, STREAM, DECODE, (NULL),
diff --git a/gst/rtpmanager/gstrtpssrcdemux.h b/gst/rtpmanager/gstrtpssrcdemux.h
index d89472af..d5a13caf 100644
--- a/gst/rtpmanager/gstrtpssrcdemux.h
+++ b/gst/rtpmanager/gstrtpssrcdemux.h
@@ -50,7 +50,11 @@ struct _GstRtpSsrcDemuxClass
GstElementClass parent_class;
/* signals */
- void (*new_ssrc_pad) (GstElement *element, guint32 ssrc, GstPad *pad);
+ void (*new_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+ void (*removed_ssrc_pad) (GstRtpSsrcDemux *demux, guint32 ssrc, GstPad *pad);
+
+ /* actions */
+ void (*clear_ssrc) (GstRtpSsrcDemux *demux, guint32 ssrc);
};
GType gst_rtp_ssrc_demux_get_type (void);
diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c
index a40d974f..355526ee 100644
--- a/gst/rtpmanager/rtpsource.c
+++ b/gst/rtpmanager/rtpsource.c
@@ -188,12 +188,51 @@ rtp_source_finalize (GObject * object)
G_OBJECT_CLASS (rtp_source_parent_class)->finalize (object);
}
+#define MAX_ADDRESS 64
+static void
+make_address_string (GstNetAddress * addr, gchar * dest, gulong n)
+{
+ switch (gst_netaddress_get_net_type (addr)) {
+ case GST_NET_TYPE_IP4:
+ {
+ guint32 address;
+ guint16 port;
+
+ gst_netaddress_get_ip4_address (addr, &address, &port);
+
+ g_snprintf (dest, n, "%d.%d.%d.%d:%d", (address >> 24) & 0xff,
+ (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff,
+ g_ntohs (port));
+ break;
+ }
+ case GST_NET_TYPE_IP6:
+ {
+ guint8 address[16];
+ guint16 port;
+
+ gst_netaddress_get_ip6_address (addr, address, &port);
+
+ g_snprintf (dest, n, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%d",
+ (address[0] << 8) | address[1], (address[2] << 8) | address[3],
+ (address[4] << 8) | address[5], (address[6] << 8) | address[7],
+ (address[8] << 8) | address[9], (address[10] << 8) | address[11],
+ (address[12] << 8) | address[13], (address[14] << 8) | address[15],
+ g_ntohs (port));
+ break;
+ }
+ default:
+ dest[0] = 0;
+ break;
+ }
+}
+
static GstStructure *
rtp_source_create_stats (RTPSource * src)
{
GstStructure *s;
gboolean is_sender = src->is_sender;
gboolean internal = src->internal;
+ gchar address_str[MAX_ADDRESS];
/* common data for all types of sources */
s = gst_structure_new ("application/x-rtp-source-stats",
@@ -204,6 +243,16 @@ rtp_source_create_stats (RTPSource * src)
"is-csrc", G_TYPE_BOOLEAN, src->is_csrc,
"is-sender", G_TYPE_BOOLEAN, is_sender, NULL);
+ /* add address and port */
+ if (src->have_rtp_from) {
+ make_address_string (&src->rtp_from, address_str, sizeof (address_str));
+ gst_structure_set (s, "rtp-from", G_TYPE_STRING, address_str, NULL);
+ }
+ if (src->have_rtcp_from) {
+ make_address_string (&src->rtcp_from, address_str, sizeof (address_str));
+ gst_structure_set (s, "rtcp-from", G_TYPE_STRING, address_str, NULL);
+ }
+
if (internal) {
/* our internal source */
if (is_sender) {
diff --git a/gst/sdp/gstsdpdemux.c b/gst/sdp/gstsdpdemux.c
index be34a22a..4deac870 100644
--- a/gst/sdp/gstsdpdemux.c
+++ b/gst/sdp/gstsdpdemux.c
@@ -51,6 +51,22 @@
#include <unistd.h>
#endif
+#ifdef G_OS_WIN32
+#ifdef _MSC_VER
+#include <Winsock2.h>
+#endif
+/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
+ * * minwg32 headers check WINVER before allowing the use of these */
+#ifndef WINVER
+#define WINVER 0x0501
+#endif
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#endif
+
#include <stdlib.h>
#include <string.h>
#include <locale.h>
@@ -348,6 +364,39 @@ gst_sdp_demux_stream_free (GstSDPDemux * demux, GstSDPStream * stream)
g_free (stream);
}
+static gboolean
+is_multicast_address (const gchar * host_name)
+{
+ struct addrinfo hints;
+ struct addrinfo *ai;
+ struct addrinfo *res;
+ gboolean ret = FALSE;
+ int err;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_DGRAM;
+
+ g_return_val_if_fail (host_name, FALSE);
+
+ if ((err = getaddrinfo (host_name, NULL, &hints, &res)) < 0)
+ return FALSE;
+
+ for (ai = res; !ret && ai; ai = ai->ai_next) {
+ if (ai->ai_family == AF_INET)
+ ret =
+ IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->
+ sin_addr.s_addr));
+ else
+ ret =
+ IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->
+ ai_addr)->sin6_addr);
+ }
+
+ freeaddrinfo (res);
+
+ return ret;
+}
+
static GstSDPStream *
gst_sdp_demux_create_stream (GstSDPDemux * demux, GstSDPMessage * sdp, gint idx)
{
@@ -395,6 +444,7 @@ gst_sdp_demux_create_stream (GstSDPDemux * demux, GstSDPMessage * sdp, gint idx)
stream->destination = conn->address;
stream->ttl = conn->ttl;
+ stream->multicast = is_multicast_address (stream->destination);
stream->rtp_port = gst_sdp_media_get_port (media);
if ((rtcp = gst_sdp_media_get_attribute_val (media, "rtcp"))) {
@@ -885,18 +935,24 @@ start_session_failure:
static gboolean
gst_sdp_demux_stream_configure_udp (GstSDPDemux * demux, GstSDPStream * stream)
{
- gchar *uri, *name;
+ gchar *uri, *name, *destination;
GstPad *pad;
GST_DEBUG_OBJECT (demux, "creating UDP sources for multicast");
+ /* if the destination is not a multicast address, we just want to listen on
+ * our local ports */
+ if (!stream->multicast)
+ destination = "0.0.0.0";
+ else
+ destination = stream->destination;
+
/* creating UDP source */
if (stream->rtp_port != -1) {
- GST_DEBUG_OBJECT (demux, "receiving RTP from %s:%d", stream->destination,
+ GST_DEBUG_OBJECT (demux, "receiving RTP from %s:%d", destination,
stream->rtp_port);
- uri = g_strdup_printf ("udp://%s:%d", stream->destination,
- stream->rtp_port);
+ uri = g_strdup_printf ("udp://%s:%d", destination, stream->rtp_port);
stream->udpsrc[0] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
g_free (uri);
if (stream->udpsrc[0] == NULL)
@@ -933,10 +989,9 @@ gst_sdp_demux_stream_configure_udp (GstSDPDemux * demux, GstSDPStream * stream)
/* creating another UDP source */
if (stream->rtcp_port != -1) {
- GST_DEBUG_OBJECT (demux, "receiving RTCP from %s:%d", stream->destination,
+ GST_DEBUG_OBJECT (demux, "receiving RTCP from %s:%d", destination,
stream->rtcp_port);
- uri =
- g_strdup_printf ("udp://%s:%d", stream->destination, stream->rtcp_port);
+ uri = g_strdup_printf ("udp://%s:%d", destination, stream->rtcp_port);
stream->udpsrc[1] = gst_element_make_from_uri (GST_URI_SRC, uri, NULL);
g_free (uri);
if (stream->udpsrc[1] == NULL)
@@ -988,6 +1043,13 @@ gst_sdp_demux_stream_configure_udp_sink (GstSDPDemux * demux,
if (stream->udpsink == NULL)
goto no_sink_element;
+ /* we clear all destinations because we don't really know where to send the
+ * RTCP to and we want to avoid sending it to our own ports.
+ * FIXME when we get an RTCP packet from the sender, we could look at its
+ * source port and address and try to send RTCP there. */
+ if (!stream->multicast)
+ g_signal_emit_by_name (stream->udpsink, "clear");
+
/* no sync needed */
g_object_set (G_OBJECT (stream->udpsink), "sync", FALSE, NULL);
/* no async state changes needed */
diff --git a/gst/sdp/gstsdpdemux.h b/gst/sdp/gstsdpdemux.h
index 0ae60742..32a53293 100644
--- a/gst/sdp/gstsdpdemux.h
+++ b/gst/sdp/gstsdpdemux.h
@@ -68,6 +68,7 @@ struct _GstSDPStream {
gchar *destination;
guint ttl;
+ gboolean multicast;
/* our udp sink back to the server */
GstElement *udpsink;
diff --git a/gst/y4m/Makefile.am b/gst/y4m/Makefile.am
deleted file mode 100644
index 4415e9e2..00000000
--- a/gst/y4m/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-
-plugin_LTLIBRARIES = libgsty4menc.la
-
-libgsty4menc_la_SOURCES = gsty4mencode.c
-libgsty4menc_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
-libgsty4menc_la_LIBADD = $(GST_LIBS)
-libgsty4menc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgsty4menc_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = gsty4mencode.h
diff --git a/gst/y4m/gsty4mencode.c b/gst/y4m/gsty4mencode.c
deleted file mode 100644
index dc218643..00000000
--- a/gst/y4m/gsty4mencode.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2006> Mark Nauwelaerts <mnauw@users.sourceforge.net>
- *
- * 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-y4menc
- *
- * <refsect2>
- * <para>
- * Creates a YU4MPEG2 raw video stream as defined by the mjpegtools project.
- * </para>
- * <title>Example launch line</title>
- * <para>
- * (write everything in one line, without the backslash characters)
- * <programlisting>
- * gst-launch-0.10 videotestsrc num-buffers=250 \
- * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \
- * ! y4menc ! filesink location=test.yuv
- * </programlisting>
- * </para>
- * </refsect2>
- *
- */
-
-/* see mjpegtools/yuv4mpeg.h for yuv4mpeg format */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <string.h>
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include "gsty4mencode.h"
-
-static const GstElementDetails y4mencode_details =
-GST_ELEMENT_DETAILS ("YUV4MPEG video encoder",
- "Codec/Encoder/Video",
- "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
- "Wim Taymans <wim.taymans@chello.be>");
-
-
-/* Filter signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum
-{
- ARG_0
-};
-
-static GstStaticPadTemplate y4mencode_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-yuv4mpeg, " "y4mversion = (int) 2")
- );
-
-static GstStaticPadTemplate y4mencode_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420 }"))
- );
-
-
-static void gst_y4m_encode_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_y4m_encode_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-
-static void gst_y4m_encode_reset (GstY4mEncode * filter);
-
-static gboolean gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps);
-static GstFlowReturn gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf);
-static GstStateChangeReturn gst_y4m_encode_change_state (GstElement * element,
- GstStateChange transition);
-
-GST_BOILERPLATE (GstY4mEncode, gst_y4m_encode, GstElement, GST_TYPE_ELEMENT);
-
-
-static void
-gst_y4m_encode_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 (&y4mencode_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&y4mencode_sink_factory));
- gst_element_class_set_details (element_class, &y4mencode_details);
-}
-
-static void
-gst_y4m_encode_class_init (GstY4mEncodeClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_y4m_encode_change_state);
-
- gobject_class->set_property = gst_y4m_encode_set_property;
- gobject_class->get_property = gst_y4m_encode_get_property;
-}
-
-static void
-gst_y4m_encode_init (GstY4mEncode * filter, GstY4mEncodeClass * klass)
-{
- filter->sinkpad =
- gst_pad_new_from_static_template (&y4mencode_sink_factory, "sink");
- gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
- gst_pad_set_chain_function (filter->sinkpad,
- GST_DEBUG_FUNCPTR (gst_y4m_encode_chain));
- gst_pad_set_setcaps_function (filter->sinkpad,
- GST_DEBUG_FUNCPTR (gst_y4m_encode_setcaps));
-
- filter->srcpad =
- gst_pad_new_from_static_template (&y4mencode_src_factory, "src");
- gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
- gst_pad_use_fixed_caps (filter->srcpad);
-
- /* init properties */
- gst_y4m_encode_reset (filter);
-}
-
-static void
-gst_y4m_encode_reset (GstY4mEncode * filter)
-{
- filter->width = filter->height = -1;
- filter->fps_num = filter->fps_den = 1;
- filter->par_num = filter->par_den = 1;
-}
-
-static gboolean
-gst_y4m_encode_setcaps (GstPad * pad, GstCaps * vscaps)
-{
- GstY4mEncode *filter;
- GstStructure *structure;
- gboolean res;
- gint w, h;
- const GValue *fps, *par;
-
- filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad));
-
- structure = gst_caps_get_structure (vscaps, 0);
-
- res = gst_structure_get_int (structure, "width", &w);
- res &= gst_structure_get_int (structure, "height", &h);
- res &= ((fps = gst_structure_get_value (structure, "framerate")) != NULL);
-
- if (!res || w <= 0 || h <= 0 || !GST_VALUE_HOLDS_FRACTION (fps))
- return FALSE;
-
- /* optional par info */
- par = gst_structure_get_value (structure, "pixel-aspect-ratio");
-
- filter->width = w;
- filter->height = h;
- filter->fps_num = gst_value_get_fraction_numerator (fps);
- filter->fps_den = gst_value_get_fraction_denominator (fps);
- if ((par != NULL) && GST_VALUE_HOLDS_FRACTION (par)) {
- filter->par_num = gst_value_get_fraction_numerator (par);
- filter->par_den = gst_value_get_fraction_denominator (par);
- } else { /* indicates unknown */
- filter->par_num = 0;
- filter->par_den = 0;
- }
-
- /* the template caps will do for the src pad, should always accept */
- return gst_pad_set_caps (filter->srcpad,
- gst_static_pad_template_get_caps (&y4mencode_src_factory));
-}
-
-static inline GstBuffer *
-gst_y4m_encode_get_stream_header (GstY4mEncode * filter)
-{
- gpointer header;
- GstBuffer *buf;
-
- header = g_strdup_printf ("YUV4MPEG2 W%d H%d I? F%d:%d A%d:%d\n",
- filter->width, filter->height,
- filter->fps_num, filter->fps_den, filter->par_num, filter->par_den);
-
- buf = gst_buffer_new ();
- gst_buffer_set_data (buf, header, strlen (header));
- /* so it gets free'd when needed */
- GST_BUFFER_MALLOCDATA (buf) = header;
-
- return buf;
-}
-
-static inline GstBuffer *
-gst_y4m_encode_get_frame_header (GstY4mEncode * filter)
-{
- gpointer header;
- GstBuffer *buf;
-
- header = g_strdup_printf ("FRAME\n");
-
- buf = gst_buffer_new ();
- gst_buffer_set_data (buf, header, strlen (header));
- /* so it gets free'd when needed */
- GST_BUFFER_MALLOCDATA (buf) = header;
-
- return buf;
-}
-
-static GstFlowReturn
-gst_y4m_encode_chain (GstPad * pad, GstBuffer * buf)
-{
- GstY4mEncode *filter = GST_Y4M_ENCODE (GST_PAD_PARENT (pad));
- GstBuffer *outbuf;
-
- /* check we got some decent info from caps */
- if (filter->width < 0) {
- GST_ELEMENT_ERROR ("filter", CORE, NEGOTIATION, (NULL),
- ("format wasn't negotiated before chain function"));
- gst_buffer_unref (buf);
- return GST_FLOW_NOT_NEGOTIATED;
- }
-
- if (G_UNLIKELY (!filter->header)) {
- outbuf = gst_y4m_encode_get_stream_header (filter);
- filter->header = TRUE;
- outbuf = gst_buffer_join (outbuf, gst_y4m_encode_get_frame_header (filter));
- } else {
- outbuf = gst_y4m_encode_get_frame_header (filter);
- }
- /* join with data */
- outbuf = gst_buffer_join (outbuf, buf);
- /* decorate */
- gst_buffer_make_metadata_writable (outbuf);
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (filter->srcpad));
- /* strip to avoid sink dropping on time-base, decorate and send */
- GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
- return gst_pad_push (filter->srcpad, outbuf);
-}
-
-static void
-gst_y4m_encode_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstY4mEncode *filter;
-
- g_return_if_fail (GST_IS_Y4M_ENCODE (object));
- filter = GST_Y4M_ENCODE (object);
-
- switch (prop_id) {
- default:
- break;
- }
-}
-
-static void
-gst_y4m_encode_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstY4mEncode *filter;
-
- g_return_if_fail (GST_IS_Y4M_ENCODE (object));
- filter = GST_Y4M_ENCODE (object);
-
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstStateChangeReturn
-gst_y4m_encode_change_state (GstElement * element, GstStateChange transition)
-{
- GstY4mEncode *filter = GST_Y4M_ENCODE (element);
- GstStateChangeReturn ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- break;
- default:
- break;
- }
-
- ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
- (element, transition), GST_STATE_CHANGE_SUCCESS);
- if (ret != GST_STATE_CHANGE_SUCCESS)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_y4m_encode_reset (filter);
- break;
- default:
- break;
- }
-
- return GST_STATE_CHANGE_SUCCESS;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- return gst_element_register (plugin, "y4menc", GST_RANK_NONE,
- GST_TYPE_Y4M_ENCODE);
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "y4menc",
- "Encodes a YUV frame into the yuv4mpeg format (mjpegtools)",
- plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/y4m/gsty4mencode.h b/gst/y4m/gsty4mencode.h
deleted file mode 100644
index 1ca8105a..00000000
--- a/gst/y4m/gsty4mencode.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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_Y4MENCODE_H__
-#define __GST_Y4MENCODE_H__
-
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_Y4M_ENCODE \
- (gst_y4m_encode_get_type())
-#define GST_Y4M_ENCODE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncode))
-#define GST_Y4M_ENCODE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass))
-#define GST_Y4M_ENCODE_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_Y4M_ENCODE, GstY4mEncodeClass))
-#define GST_IS_Y4M_ENCODE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_Y4M_ENCODE))
-#define GST_IS_Y4M_ENCODE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_Y4M_ENCODE))
-
-typedef struct _GstY4mEncode GstY4mEncode;
-typedef struct _GstY4mEncodeClass GstY4mEncodeClass;
-
-struct _GstY4mEncode {
- GstElement element;
-
- GstPad *sinkpad,*srcpad;
-
- /* caps information */
- gint width, height;
- gint fps_num, fps_den;
- gint par_num, par_den;
-
- /* state information */
- gboolean header;
-};
-
-struct _GstY4mEncodeClass {
- GstElementClass parent_class;
-};
-
-GType gst_y4m_encode_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_Y4MENCODE_H__ */
diff --git a/gst/y4m/y4menc.vcproj b/gst/y4m/y4menc.vcproj
deleted file mode 100644
index 7251140e..00000000
--- a/gst/y4m/y4menc.vcproj
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="y4mencode"
- ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678E5}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="../../win32/Debug"
- IntermediateDirectory="../../win32/Debug"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;y4mencode_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
- MinimalRebuild="TRUE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="3"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
- OutputFile="$(OutDir)/gsty4mencode.dll"
- LinkIncremental="2"
- AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
- ModuleDefinitionFile=""
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile="$(OutDir)/y4mencode.pdb"
- SubSystem="2"
- OptimizeReferences="2"
- ImportLibrary="$(OutDir)/gsty4mencode.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="../../win32/Release"
- IntermediateDirectory="../../win32/Release"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
- PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;y4mencode_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
- RuntimeLibrary="2"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
- OutputFile="$(OutDir)/gsty4mencode.dll"
- LinkIncremental="1"
- AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
- ModuleDefinitionFile=""
- GenerateDebugInformation="TRUE"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- ImportLibrary="$(OutDir)/gsty4mencode.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"
- CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
- <File
- RelativePath=".\gsty4mencode.c">
- </File>
- </Filter>
- <Filter
- Name="Header Files"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
- <File
- RelativePath=".\gsty4mencode.h">
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>