summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/chart/.gitignore7
-rw-r--r--gst/chart/Makefile.am4
-rw-r--r--gst/chart/gstchart.c456
-rw-r--r--gst/deinterlace/.gitignore7
-rw-r--r--gst/deinterlace/Makefile.am9
-rw-r--r--gst/deinterlace/gstdeinterlace.c390
-rw-r--r--gst/deinterlace/gstdeinterlace.h76
-rw-r--r--gst/flx/Makefile.am9
-rw-r--r--gst/flx/flx_color.c94
-rw-r--r--gst/flx/flx_color.h43
-rw-r--r--gst/flx/flx_fmt.h136
-rw-r--r--gst/flx/gstflxdec.c644
-rw-r--r--gst/flx/gstflxdec.h79
-rw-r--r--gst/mpeg1sys/.gitignore7
-rw-r--r--gst/mpeg1sys/Makefile.am13
-rw-r--r--gst/mpeg1sys/buffer.c482
-rw-r--r--gst/mpeg1sys/buffer.h141
-rw-r--r--gst/mpeg1sys/gstmpeg1systemencode.c572
-rw-r--r--gst/mpeg1sys/gstmpeg1systemencode.h110
-rw-r--r--gst/mpeg1sys/main.h140
-rw-r--r--gst/mpeg1sys/systems.c290
-rw-r--r--gst/mpeg2sub/.gitignore7
-rw-r--r--gst/mpeg2sub/Makefile.am18
-rw-r--r--gst/mpeg2sub/Notes.txt324
-rw-r--r--gst/mpeg2sub/gstmpeg2subt.c443
-rw-r--r--gst/mpeg2sub/gstmpeg2subt.h82
-rw-r--r--gst/mpegaudioparse/Makefile.am16
-rw-r--r--gst/mpegaudioparse/README12
-rw-r--r--gst/mpegaudioparse/gstmp3types.c77
-rw-r--r--gst/mpegaudioparse/gstmpegaudioparse.c506
-rw-r--r--gst/mpegaudioparse/gstmpegaudioparse.h71
-rw-r--r--gst/passthrough/.gitignore7
-rw-r--r--gst/passthrough/Makefile.am10
-rw-r--r--gst/passthrough/filter.func18
-rw-r--r--gst/passthrough/gstpassthrough.c351
-rw-r--r--gst/passthrough/gstpassthrough.h103
-rw-r--r--gst/playondemand/Makefile.am10
-rw-r--r--gst/playondemand/filter.func120
-rw-r--r--gst/playondemand/gstplayondemand.c448
-rw-r--r--gst/playondemand/gstplayondemand.h112
-rw-r--r--gst/rtjpeg/.gitignore7
-rw-r--r--gst/rtjpeg/Makefile.am8
-rw-r--r--gst/rtjpeg/README12
-rw-r--r--gst/rtjpeg/RTjpeg.c3434
-rw-r--r--gst/rtjpeg/RTjpeg.h53
-rw-r--r--gst/rtjpeg/gstrtjpeg.c62
-rw-r--r--gst/rtjpeg/gstrtjpegdec.c114
-rw-r--r--gst/rtjpeg/gstrtjpegdec.h71
-rw-r--r--gst/rtjpeg/gstrtjpegenc.c112
-rw-r--r--gst/rtjpeg/gstrtjpegenc.h72
-rw-r--r--gst/smooth/.gitignore7
-rw-r--r--gst/smooth/Makefile.am8
-rw-r--r--gst/smooth/gstsmooth.c362
-rw-r--r--gst/smooth/gstsmooth.h75
-rw-r--r--gst/spectrum/.gitignore7
-rw-r--r--gst/spectrum/Makefile.am10
-rw-r--r--gst/spectrum/README5
-rw-r--r--gst/spectrum/fix_fft.c452
-rw-r--r--gst/spectrum/gstspectrum.c242
-rw-r--r--gst/spectrum/gstspectrum.h67
-rw-r--r--gst/speed/Makefile.am8
-rw-r--r--gst/speed/filter.func66
-rw-r--r--gst/speed/gstspeed.c347
-rw-r--r--gst/speed/gstspeed.h106
-rw-r--r--gst/stereo/.gitignore7
-rw-r--r--gst/stereo/Makefile.am10
-rw-r--r--gst/stereo/README3
-rw-r--r--gst/stereo/gststereo.c226
-rw-r--r--gst/stereo/gststereo.h68
69 files changed, 12465 insertions, 0 deletions
diff --git a/gst/chart/.gitignore b/gst/chart/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/chart/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/chart/Makefile.am b/gst/chart/Makefile.am
new file mode 100644
index 00000000..c85c60af
--- /dev/null
+++ b/gst/chart/Makefile.am
@@ -0,0 +1,4 @@
+filterdir = $(libdir)/gst
+filter_LTLIBRARIES = libchart.la
+libchart_la_SOURCES = gstchart.c
+libchart_la_CFLAGS = $(GST_CFLAGS)
diff --git a/gst/chart/gstchart.c b/gst/chart/gstchart.c
new file mode 100644
index 00000000..1ec25970
--- /dev/null
+++ b/gst/chart/gstchart.c
@@ -0,0 +1,456 @@
+/* gstchart.c: implementation of chart drawing element
+ * Copyright (C) <2001> Richard Boulton <richard@tartarus.org>
+ *
+ * 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 <config.h>
+#include <gst/gst.h>
+
+#define GST_TYPE_CHART (gst_chart_get_type())
+#define GST_CHART(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CHART,GstChart))
+#define GST_CHART_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CHART,GstChart))
+#define GST_IS_CHART(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CHART))
+#define GST_IS_CHART_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CHART))
+
+typedef struct _GstChart GstChart;
+typedef struct _GstChartClass GstChartClass;
+
+struct _GstChart {
+ GstElement element;
+
+ /* pads */
+ GstPad *sinkpad,*srcpad;
+ GstBufferPool *peerpool;
+
+ // the timestamp of the next frame
+ guint64 next_time;
+
+ // video state
+ gint bpp;
+ gint depth;
+ gint width;
+ gint height;
+
+ gint samplerate;
+ gint framerate; // desired frame rate
+ gint samples_between_frames; // number of samples between start of successive frames
+ gint samples_since_last_frame; // number of samples between start of successive frames
+};
+
+struct _GstChartClass {
+ GstElementClass parent_class;
+};
+
+GType gst_chart_get_type(void);
+
+
+/* elementfactory information */
+static GstElementDetails gst_chart_details = {
+ "chart drawer",
+ "Filter/Visualization",
+ "Takes frames of data and outputs video frames of a chart of data",
+ VERSION,
+ "Richard Boulton <richard@tartarus.org>",
+ "(C) 2001",
+};
+
+/* signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ /* FILL ME */
+};
+
+static GstPadTemplate*
+src_template_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template) {
+ template = gst_padtemplate_new (
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ gst_caps_new (
+ "chartsrc",
+ "video/raw",
+ /*gst_props_new (
+ "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')),
+ "bpp", GST_PROPS_INT (32),
+ "depth", GST_PROPS_INT (32),
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "red_mask", GST_PROPS_INT (0xff0000),
+ "green_mask", GST_PROPS_INT (0xff00),
+ "blue_mask", GST_PROPS_INT (0xff),
+ "width", GST_PROPS_INT_RANGE (16, 4096),
+ "height", GST_PROPS_INT_RANGE (16, 4096),
+ NULL),*/
+ gst_props_new (
+ "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')),
+ "bpp", GST_PROPS_INT (16),
+ "depth", GST_PROPS_INT (16),
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "red_mask", GST_PROPS_INT (0xf800),
+ "green_mask", GST_PROPS_INT (0x07e0),
+ "blue_mask", GST_PROPS_INT (0x001f),
+ "width", GST_PROPS_INT_RANGE (16, 4096),
+ "height", GST_PROPS_INT_RANGE (16, 4096),
+ NULL)
+ ),
+ NULL);
+ }
+ return template;
+}
+
+static GstPadTemplate*
+sink_template_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template) {
+ template = gst_padtemplate_new (
+ "sink", /* the name of the pads */
+ GST_PAD_SINK, /* type of the pad */
+ GST_PAD_ALWAYS, /* ALWAYS/SOMETIMES */
+ gst_caps_new (
+ "chartsink", /* the name of the caps */
+ "audio/raw", /* the mime type of the caps */
+ gst_props_new (
+ /* Properties follow: */
+ "format", GST_PROPS_STRING ("int"),
+ "law", GST_PROPS_INT (0),
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "signed", GST_PROPS_BOOLEAN (TRUE),
+ "width", GST_PROPS_INT (16),
+ "depth", GST_PROPS_INT (16),
+ "rate", GST_PROPS_INT_RANGE (8000, 96000),
+ "channels", GST_PROPS_INT (1),
+ NULL)
+ ),
+ NULL);
+ }
+
+ return template;
+}
+
+
+
+
+static void gst_chart_class_init (GstChartClass *klass);
+static void gst_chart_init (GstChart *chart);
+
+static void gst_chart_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_chart_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static void gst_chart_chain (GstPad *pad, GstBuffer *buf);
+
+static GstElementClass *parent_class = NULL;
+
+static void gst_chart_newsinkcaps (GstPad *pad, GstCaps *caps);
+static void gst_chart_newsrccaps (GstPad *pad, GstCaps *caps);
+
+GType
+gst_chart_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof(GstChartClass), NULL, NULL, (GClassInitFunc)gst_chart_class_init,
+ NULL,
+ NULL,
+ sizeof(GstChart),
+ 0,
+ (GInstanceInitFunc)gst_chart_init,
+ };
+ type = g_type_register_static(GST_TYPE_ELEMENT, "GstChart", &info, 0);
+ }
+ return type;
+}
+
+static void
+gst_chart_class_init(GstChartClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_chart_set_property;
+ gobject_class->get_property = gst_chart_get_property;
+}
+
+static void
+gst_chart_init (GstChart *chart)
+{
+ /* create the sink and src pads */
+ chart->sinkpad = gst_pad_new_from_template (sink_template_factory (), "sink");
+ chart->srcpad = gst_pad_new_from_template (src_template_factory (), "src");
+ gst_element_add_pad (GST_ELEMENT (chart), chart->sinkpad);
+ gst_element_add_pad (GST_ELEMENT (chart), chart->srcpad);
+
+ gst_pad_set_chain_function (chart->sinkpad, gst_chart_chain);
+ gst_pad_set_newcaps_function (chart->sinkpad, gst_chart_newsinkcaps);
+ gst_pad_set_newcaps_function (chart->srcpad, gst_chart_newsrccaps);
+
+
+ chart->next_time = 0;
+ chart->peerpool = NULL;
+
+ // reset the initial video state
+ chart->bpp = 16;
+ chart->depth = 16;
+ chart->width = -1;
+ chart->height = -1;
+
+ chart->samplerate = -1;
+ chart->framerate = 25; // desired frame rate
+ chart->samples_between_frames = 0; // number of samples between start of successive frames
+ chart->samples_since_last_frame = 0;
+}
+
+static void
+gst_chart_newsinkcaps (GstPad *pad, GstCaps *caps)
+{
+ GstChart *chart;
+ chart = GST_CHART (gst_pad_get_parent (pad));
+
+ chart->samplerate = gst_caps_get_int (caps, "rate");
+ chart->samples_between_frames = chart->samplerate / chart->framerate;
+
+ GST_DEBUG (0, "CHART: new sink caps: rate %d\n",
+ chart->samplerate);
+ //gst_chart_sync_parms (chart);
+}
+
+static void
+gst_chart_newsrccaps (GstPad *pad, GstCaps *caps)
+{
+ GstChart *chart;
+ chart = GST_CHART (gst_pad_get_parent (pad));
+
+ chart->bpp = gst_caps_get_int (caps, "bpp");
+ chart->depth = gst_caps_get_int (caps, "depth");
+ chart->width = gst_caps_get_int (caps, "width");
+ chart->height = gst_caps_get_int (caps, "height");
+
+ GST_DEBUG (0, "CHART: new src caps: bpp %d, depth %d, width %d, height %d\n",
+ chart->bpp, chart->depth, chart->width, chart->height);
+ //gst_chart_sync_parms (chart);
+}
+
+static void
+gst_chart_free (GstChart *chart)
+{
+ g_free (chart);
+}
+
+static void
+draw_chart_16bpp(guchar * output, gint width, gint height,
+ gint16 * src_data, gint src_size)
+{
+ gint i;
+ guint16 *colstart;
+ gint16 * in;
+
+ GST_DEBUG (0, "CHART: drawing frame to %p, width = %d, height = %d, src_data = %p, src_size = %d\n",
+ output, width, height, src_data, src_size);
+
+ for (colstart = (guint16 *)output, in = (gint16 *)src_data, i = 0;
+ i < width;
+ colstart++, in++, i++) {
+ guint16 * pos = colstart;
+ gint h1;
+
+ h1 = (((gint)(*in)) * height / (1 << 16)) + height / 2;
+ if (h1 >= height) h1 = height;
+
+ if (h1 < height / 2) {
+ while (pos < colstart + h1 * width) {
+ *pos = 0x0000;
+ pos += width;
+ }
+ while (pos < colstart + height / 2 * width) {
+ *pos = 0x07e0;
+ pos += width;
+ }
+ while (pos < colstart + height * width) {
+ *pos = 0x0000;
+ pos += width;
+ }
+ } else {
+ while (pos < colstart + height / 2 * width) {
+ *pos = 0x0000;
+ pos += width;
+ }
+ while (pos < colstart + h1 * width) {
+ *pos = 0x07e0;
+ pos += width;
+ }
+ while (pos < colstart + height * width) {
+ *pos = 0x0000;
+ pos += width;
+ }
+ }
+ }
+}
+
+static void
+gst_chart_chain (GstPad *pad, GstBuffer *bufin)
+{
+ GstChart *chart;
+ GstBuffer *bufout;
+ guint32 samples_in;
+ guint32 sizeout;
+ gint16 *datain;
+ guchar *dataout;
+
+ g_return_if_fail (bufin != NULL);
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD(pad));
+ g_return_if_fail (GST_IS_CHART(GST_OBJECT_PARENT(pad)));
+ chart = GST_CHART(GST_OBJECT_PARENT (pad));
+ g_return_if_fail (chart != NULL);
+
+ GST_DEBUG (0, "CHART: chainfunc called\n");
+
+ samples_in = GST_BUFFER_SIZE (bufin) / sizeof(gint16);
+ datain = (gint16 *) (GST_BUFFER_DATA (bufin));
+ GST_DEBUG (0, "input buffer has %d samples\n", samples_in);
+ if (chart->next_time <= GST_BUFFER_TIMESTAMP (bufin)) {
+ chart->next_time = GST_BUFFER_TIMESTAMP (bufin);
+ GST_DEBUG (0, "in: %lld\n", GST_BUFFER_TIMESTAMP (bufin));
+ }
+
+ chart->samples_since_last_frame += samples_in;
+ if (chart->samples_between_frames <= chart->samples_since_last_frame) {
+ chart->samples_since_last_frame = 0;
+
+ // Check if we need to renegotiate size.
+ if (chart->width == -1 || chart->height == -1) {
+ chart->width = 256;
+ chart->height = 128;
+ GST_DEBUG (0, "making new pad\n");
+ gst_pad_set_caps (chart->srcpad,
+ gst_caps_new (
+ "chartsrc",
+ "video/raw",
+ gst_props_new (
+ "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')),
+ "bpp", GST_PROPS_INT (chart->bpp),
+ "depth", GST_PROPS_INT (chart->depth),
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "red_mask", GST_PROPS_INT (0xf800),
+ "green_mask", GST_PROPS_INT (0x07e0),
+ "blue_mask", GST_PROPS_INT (0x001f),
+ "width", GST_PROPS_INT (chart->width),
+ "height", GST_PROPS_INT (chart->height),
+ NULL)));
+ }
+
+ // get data to draw into buffer
+ if (samples_in >= chart->width) {
+ // make a new buffer for the output
+ bufout = gst_buffer_new ();
+ sizeout = chart->bpp / 8 * chart->width * chart->height;
+ dataout = g_malloc (sizeout);
+ GST_BUFFER_SIZE(bufout) = sizeout;
+ GST_BUFFER_DATA(bufout) = dataout;
+ GST_DEBUG (0, "CHART: made new buffer: size %d, width %d, height %d\n",
+ sizeout, chart->width, chart->height);
+
+ // take data and draw to new buffer
+ // FIXME: call different routines for different properties
+ draw_chart_16bpp(dataout, chart->width, chart->height, (gint16 *)datain, samples_in);
+
+ // set timestamp
+ GST_BUFFER_TIMESTAMP (bufout) = chart->next_time;
+
+ GST_DEBUG (0, "CHART: outputting buffer\n");
+ // output buffer
+ GST_BUFFER_FLAG_SET (bufout, GST_BUFFER_READONLY);
+ gst_pad_push (chart->srcpad, bufout);
+ }
+ } else {
+ GST_DEBUG (0, "CHART: skipping buffer\n");
+ }
+
+ gst_buffer_unref(bufin);
+ GST_DEBUG (0, "CHART: exiting chainfunc\n");
+}
+
+static void
+gst_chart_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstChart *chart;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_CHART (object));
+ chart = GST_CHART (object);
+
+ switch (prop_id) {
+ default:
+ break;
+ }
+}
+
+static void
+gst_chart_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstChart *chart;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_CHART (object));
+ chart = GST_CHART (object);
+
+ switch (prop_id) {
+ default:
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the chart element */
+ factory = gst_elementfactory_new("chart",GST_TYPE_CHART,
+ &gst_chart_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, src_template_factory ());
+ gst_elementfactory_add_padtemplate (factory, sink_template_factory ());
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "chart",
+ plugin_init
+};
diff --git a/gst/deinterlace/.gitignore b/gst/deinterlace/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/deinterlace/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/deinterlace/Makefile.am b/gst/deinterlace/Makefile.am
new file mode 100644
index 00000000..eafa47d5
--- /dev/null
+++ b/gst/deinterlace/Makefile.am
@@ -0,0 +1,9 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstdeinterlace.la
+
+libgstdeinterlace_la_SOURCES = gstdeinterlace.c
+libgstdeinterlace_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstdeinterlace.h
+
diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c
new file mode 100644
index 00000000..99a70c84
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlace.c
@@ -0,0 +1,390 @@
+/* Gnome-Streamer
+ * 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.
+ */
+/* based on the Area Based Deinterlacer (for RGB frames) */
+/* (a VirtualDub filter) from Gunnar Thalin <guth@home.se> */
+
+#include <string.h>
+#include <gst/gst.h>
+#include "gstdeinterlace.h"
+
+static GstElementDetails deinterlace_details = {
+ "DeInterlace",
+ "Filter/Effect",
+ "Deinterlace video",
+ VERSION,
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2001",
+};
+
+
+/* Filter signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_DI_ONLY,
+ ARG_BLEND,
+ ARG_THRESHOLD,
+ ARG_EDGE_DETECT,
+};
+
+GST_PADTEMPLATE_FACTORY (deinterlace_src_factory,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "deinterlace_src",
+ "video/raw",
+ "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
+ )
+)
+
+GST_PADTEMPLATE_FACTORY (deinterlace_sink_factory,
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "deinterlace_src",
+ "video/raw",
+ "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
+ )
+)
+
+static GType gst_deinterlace_get_type (void);
+
+static void gst_deinterlace_class_init (GstDeInterlaceClass *klass);
+static void gst_deinterlace_init (GstDeInterlace *filter);
+
+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 void gst_deinterlace_chain (GstPad *pad, GstBuffer *buf);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
+
+static GstPadNegotiateReturn
+deinterlace_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstDeInterlace* filter = GST_DEINTERLACE (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->sinkpad,caps);
+}
+
+static GstPadNegotiateReturn
+deinterlace_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstDeInterlace* filter = GST_DEINTERLACE (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->srcpad,caps);
+}
+
+static GType
+gst_deinterlace_get_type(void) {
+ static GType deinterlace_type = 0;
+
+ if (!deinterlace_type) {
+ static const GTypeInfo deinterlace_info = {
+ sizeof(GstDeInterlaceClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_deinterlace_class_init,
+ NULL,
+ NULL,
+ sizeof(GstDeInterlace),
+ 0,
+ (GInstanceInitFunc)gst_deinterlace_init,
+ };
+ deinterlace_type = g_type_register_static(GST_TYPE_ELEMENT, "GstDeInterlace", &deinterlace_info, 0);
+ }
+ return deinterlace_type;
+}
+
+static void
+gst_deinterlace_class_init (GstDeInterlaceClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DI_ONLY,
+ g_param_spec_boolean("di_area_only","di_area_only","di_area_only",
+ TRUE,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BLEND,
+ g_param_spec_boolean("blend","blend","blend",
+ TRUE,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_THRESHOLD,
+ g_param_spec_int("threshold","threshold","threshold",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_EDGE_DETECT,
+ g_param_spec_int("edge_detect","edge_detect","edge_detect",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+
+ gobject_class->set_property = gst_deinterlace_set_property;
+ gobject_class->get_property = gst_deinterlace_get_property;
+}
+
+static void
+gst_deinterlace_newcaps (GstPad *pad, GstCaps *caps)
+{
+ GstDeInterlace *filter;
+
+ filter = GST_DEINTERLACE(gst_pad_get_parent (pad));
+
+ filter->width = gst_caps_get_int (caps, "width");
+ filter->height = gst_caps_get_int (caps, "height");
+
+ if (filter->picsize != (filter->width*filter->height)) {
+ if (filter->src)
+ g_free(filter->src);
+ filter->picsize = filter->width*filter->height;
+ filter->src = g_malloc(filter->picsize);
+ }
+}
+
+static void
+gst_deinterlace_init (GstDeInterlace *filter)
+{
+ filter->sinkpad = gst_pad_new_from_template(deinterlace_sink_factory (),"sink");
+ gst_pad_set_negotiate_function(filter->sinkpad,deinterlace_negotiate_sink);
+ gst_pad_set_chain_function(filter->sinkpad,gst_deinterlace_chain);
+ gst_pad_set_newcaps_function(filter->sinkpad,gst_deinterlace_newcaps);
+ gst_element_add_pad(GST_ELEMENT(filter),filter->sinkpad);
+
+ filter->srcpad = gst_pad_new_from_template(deinterlace_src_factory (),"src");
+ gst_pad_set_negotiate_function(filter->srcpad,deinterlace_negotiate_src);
+ gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
+
+ filter->show_deinterlaced_area_only = FALSE;
+ filter->blend = FALSE;
+ //filter->threshold_blend = 0;
+ filter->threshold = 50;
+ filter->edge_detect = 25;
+
+ filter->src = NULL;
+ filter->picsize = 0;
+}
+
+static void
+gst_deinterlace_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstDeInterlace *filter;
+ gint y0, y1, y2, y3;
+ guchar *psrc1, *psrc2, *psrc3, *pdst1, *yuvptr, *src;
+ gint iInterlaceValue0, iInterlaceValue1, iInterlaceValue2;
+ gint x, y;
+ gint y_line;
+ guchar *y_dst, *y_src;
+ gboolean bBlend;
+ gint iThreshold;
+ gint iEdgeDetect;
+ gint width, height;
+ gboolean bShowDeinterlacedAreaOnly;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ filter = GST_DEINTERLACE (gst_pad_get_parent (pad));
+
+ bBlend = filter->blend;
+ iThreshold = filter->threshold;
+ iEdgeDetect = filter->edge_detect;
+ width = filter->width;
+ height = filter->height;
+ src = filter->src;
+ yuvptr = GST_BUFFER_DATA (buf);
+ bShowDeinterlacedAreaOnly = filter->show_deinterlaced_area_only;
+
+ memcpy(filter->src, yuvptr, filter->picsize);
+
+ y_dst = yuvptr; // dst y pointer
+ // we should not change u,v because one u, v value stands for
+ // 2 pixels per 2 lines = 4 pixel and we don't want to change
+ // the color of
+
+ y_line = width;
+ y_src = src;
+
+ iThreshold = iThreshold * iThreshold * 4;
+ // We don't want an integer overflow in the interlace calculation.
+ if (iEdgeDetect > 180)
+ iEdgeDetect = 180;
+ iEdgeDetect = iEdgeDetect * iEdgeDetect;
+
+ y1 = 0; // Avoid compiler warning. The value is not used.
+ for (x = 0; x < width; x++) {
+ psrc3 = y_src + x;
+ y3 = *psrc3;
+ psrc2 = psrc3 + y_line;
+ y2 = *psrc2;
+ pdst1 = y_dst + x;
+ iInterlaceValue1 = iInterlaceValue2 = 0;
+ for (y = 0; y <= height; y++) {
+ psrc1 = psrc2;
+ psrc2 = psrc3;
+ psrc3 = psrc3 + y_line;
+ y0 = y1;
+ y1 = y2;
+ y2 = y3;
+ if (y < height - 1) {
+ y3 = *psrc3;
+ } else {
+ y3 = y1;
+ }
+
+ iInterlaceValue0 = iInterlaceValue1;
+ iInterlaceValue1 = iInterlaceValue2;
+
+ if (y < height)
+ iInterlaceValue2 = ((y1 - y2) * (y3 - y2) -
+ ((iEdgeDetect * (y1 - y3) * (y1 - y3)) >> 12))*10;
+ else
+ iInterlaceValue2 = 0;
+
+ if (y > 0) {
+ if (iInterlaceValue0 + 2 * iInterlaceValue1 + iInterlaceValue2 > iThreshold) {
+ 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;
+ //*pdst1 = 0; // FIXME this is for adjusting an initial iThreshold
+ } else { // even interpolate the even line (upper + lower)/2
+ *pdst1 = (unsigned char)((y0 + y2) >> 1);
+ //*pdst1 = 0; // FIXME this is for adjusting an initial iThreshold
+ }
+ }
+ } 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
+ // threshhold was to low?? (or shows that everything is ok :-)
+ *pdst1 = 0; // blank the point and so the interlac area
+ } else {
+ *pdst1 = *psrc1;
+ }
+ }
+ pdst1 = pdst1 + y_line;
+ }
+ }
+ }
+
+ gst_pad_push (filter->srcpad, buf);
+}
+
+static void
+gst_deinterlace_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstDeInterlace *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_DEINTERLACE(object));
+
+ filter = GST_DEINTERLACE(object);
+
+ switch (prop_id)
+ {
+ case ARG_DI_ONLY:
+ filter->show_deinterlaced_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:
+ break;
+ }
+}
+
+static void
+gst_deinterlace_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstDeInterlace *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_DEINTERLACE(object));
+
+ filter = GST_DEINTERLACE(object);
+
+ switch (prop_id) {
+ case ARG_DI_ONLY:
+ g_value_set_boolean (value, filter->show_deinterlaced_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;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("deinterlace",GST_TYPE_DEINTERLACE,
+ &deinterlace_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory,
+ GST_PADTEMPLATE_GET (deinterlace_src_factory));
+ gst_elementfactory_add_padtemplate (factory,
+ GST_PADTEMPLATE_GET (deinterlace_sink_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "deinterlace",
+ plugin_init
+};
diff --git a/gst/deinterlace/gstdeinterlace.h b/gst/deinterlace/gstdeinterlace.h
new file mode 100644
index 00000000..c46c3af6
--- /dev/null
+++ b/gst/deinterlace/gstdeinterlace.h
@@ -0,0 +1,76 @@
+/* Gnome-Streamer
+ * 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_DEINTERLACE_H__
+#define __GST_DEINTERLACE_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+// #include <gst/meta/audioraw.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#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_ULAW,GstDeInterlace))
+#define GST_IS_DEINTERLACE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLACE))
+#define GST_IS_DEINTERLACE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLACE))
+
+typedef struct _GstDeInterlace GstDeInterlace;
+typedef struct _GstDeInterlaceClass GstDeInterlaceClass;
+
+struct _GstDeInterlace {
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ gint width, height;
+
+ gboolean show_deinterlaced_area_only;
+ gboolean blend;
+ gint threshold_blend; // here we start blending
+ gint threshold; // here we start interpolating TODO FIXME
+ gint edge_detect;
+
+ gint picsize;
+ guchar *src;
+
+};
+
+struct _GstDeInterlaceClass {
+ GstElementClass parent_class;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_STEREO_H__ */
diff --git a/gst/flx/Makefile.am b/gst/flx/Makefile.am
new file mode 100644
index 00000000..79a6fba7
--- /dev/null
+++ b/gst/flx/Makefile.am
@@ -0,0 +1,9 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstflxdec.la
+
+libgstflxdec_la_SOURCES = gstflxdec.c flx_color.c
+libgstflxdec_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = flx_fmt.h flx_color.h gstflxdec.h
+
diff --git a/gst/flx/flx_color.c b/gst/flx/flx_color.c
new file mode 100644
index 00000000..c61052d0
--- /dev/null
+++ b/gst/flx/flx_color.c
@@ -0,0 +1,94 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+
+
+#include "flx_color.h"
+
+FlxColorSpaceConverter *
+flx_colorspace_converter_new(gint width, gint height)
+{
+ FlxColorSpaceConverter *new = g_malloc(sizeof(FlxColorSpaceConverter));
+
+ new->width = width;
+ new->height = height;
+
+ memset(new->palvec, 0, sizeof(new->palvec));
+ return new;
+}
+
+void
+flx_colorspace_converter_destroy(FlxColorSpaceConverter *flxpal)
+{
+ g_return_if_fail(flxpal != NULL);
+
+ g_free(flxpal);
+}
+
+void
+flx_colorspace_convert(FlxColorSpaceConverter *flxpal, guchar *src, guchar *dest)
+{
+ guint size, col;
+
+ g_return_if_fail(flxpal != NULL);
+ g_return_if_fail(src != dest);
+
+
+ size = flxpal->width * flxpal->height;
+
+ while(size--) {
+ col = (*src++ * 3);
+ *dest++ = flxpal->palvec[col+2];
+ *dest++ = flxpal->palvec[col+1];
+ *dest++ = flxpal->palvec[col];
+ *dest++ = 0;
+ }
+
+}
+
+
+void
+flx_set_palette_vector(FlxColorSpaceConverter *flxpal, guint start, guint num, guchar *newpal)
+{
+ guint grab;
+
+ g_return_if_fail(flxpal != NULL);
+ g_return_if_fail(start < 0x100);
+
+ grab = ((start + num) > 0x100 ? 0x100 - start : num);
+
+ memcpy(&flxpal->palvec[start * 3], newpal, grab*3);
+
+}
+
+void
+flx_set_color(FlxColorSpaceConverter *flxpal, guint colr, guint red, guint green, guint blue)
+{
+
+ g_return_if_fail(flxpal != NULL);
+ g_return_if_fail(colr < 0x100);
+
+ flxpal->palvec[(colr * 3)] = red;
+ flxpal->palvec[(colr * 3) + 1] = green;
+ flxpal->palvec[(colr * 3) + 2] = blue;
+}
+
+
diff --git a/gst/flx/flx_color.h b/gst/flx/flx_color.h
new file mode 100644
index 00000000..5676c878
--- /dev/null
+++ b/gst/flx/flx_color.h
@@ -0,0 +1,43 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+typedef enum {
+ FLX_COLORSPACE_RGB8,
+ FLX_COLORSPACE_RGB32,
+} FlxColorSpaceType;
+
+
+typedef struct _FlxColorSpaceConverter FlxColorSpaceConverter;
+
+struct _FlxColorSpaceConverter {
+ guint width;
+ guint height;
+ guchar palvec[768];
+};
+
+
+void flx_colorspace_converter_destroy(FlxColorSpaceConverter *flxpal);
+void flx_colorspace_convert(FlxColorSpaceConverter *flxpal, guchar *src, guchar *dest);
+FlxColorSpaceConverter * flx_colorspace_converter_new(gint width, gint height);
+
+void flx_set_palette_vector(FlxColorSpaceConverter *flxpal, guint start, guint num,
+ guchar *newpal);
+void flx_set_color(FlxColorSpaceConverter *flxpal, guint colr, guint red, guint green,
+ guint blue);
+
diff --git a/gst/flx/flx_fmt.h b/gst/flx/flx_fmt.h
new file mode 100644
index 00000000..5323de63
--- /dev/null
+++ b/gst/flx/flx_fmt.h
@@ -0,0 +1,136 @@
+/* Gnome-Streamer
+ * 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_FLX_FMT__H__
+#define __GST_FLX_FMT_H__
+
+#include <gst/gst.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+enum Flx_TypeChunk
+{
+ /* frame chunks */
+ FLX_PREFIX_TYPE = 0xf100,
+ FLX_SCRIPT_CHUNK = 0xf1e0,
+ FLX_FRAME_TYPE = 0xf1fa,
+ FLX_SEGMENT_TABLE = 0xf1fb,
+ FLX_HUFFMAN_TABLE = 0xf1fc,
+
+ /* sub chunks */
+ FLX_CEL_DATA = 3,
+ FLX_COLOR256 = 4,
+ FLX_SS2 = 7,
+ FLX_COLOR64 = 11,
+ FLX_LC = 12,
+ FLX_BLACK = 13,
+ FLX_BRUN = 15,
+ FLX_COPY = 16,
+ FLX_MINI = 18,
+ FLX_DTA_RUN = 25,
+ FLX_DTA_COPY = 26,
+ FLX_DTA_LC = 27,
+ FLX_LABEL = 31,
+ FLX_BMP_MASK = 32,
+ FLX_MLEV_MASK = 33,
+ FLX_SEGMENT = 34,
+ FLX_KEY_IMAGE = 35,
+ FLX_KEY_PAL = 36,
+ FLX_REGION = 37,
+ FLX_WAVE = 38,
+ FLX_USERSTRING = 39,
+ FLX_RGN_MASK = 40,
+
+};
+
+enum Flx_MagicHdr
+{
+ FLX_MAGICHDR_FLI = 0xaf11,
+ FLX_MAGICHDR_FLC = 0xaf12,
+ FLX_MAGICHDR_FLX = 0xaf44,
+ FLX_MAGICHDR_HUFFBWT = 0xaf30,
+};
+
+
+
+typedef struct _FlxHeader
+{
+ guint32 size;
+ guint16 type;
+ guint16 frames;
+ guint16 width,height,depth,flags;
+ guint32 speed;
+ guint16 reserved1;
+ /* FLC */
+ guint32 created,creator,updated,updater;
+ guint16 aspect_dx, aspect_dy;
+ /* EGI */
+ guint16 ext_flags,keyframes,totalframes;
+ guint32 req_memory;
+ guint16 max_regions,transp_num;
+ guchar reserved2[24];
+ /* FLC */
+ guint32 oframe1,oframe2;
+ guchar reserved3[40];
+} FlxHeader;
+#define FlxHeaderSize 128
+
+typedef struct _FlxFrameChunk
+{
+ guint32 size;
+ guint16 id;
+} FlxFrameChunk;
+#define FlxFrameChunkSize 6
+
+typedef struct _FlxPrefixChunk
+{
+ guint16 chunks;
+ guchar reserved[8];
+} FlxPrefixChunk;
+
+typedef struct _FlxSegmentTable
+{
+ guint16 segments;
+} FlxSegmentTable;
+
+typedef struct _FlxHuffmanTable
+{
+ guint16 codelength;
+ guint16 numcodes;
+ guchar reserved[6];
+} FlxHuffmanTable;
+
+typedef struct _FlxFrameType
+{
+ guint16 chunks;
+ guint16 delay;
+ guchar reserved[6];
+} FlxFrameType;
+#define FlxFrameTypeSize 10
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_FLX_FMT_H__ */
diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
new file mode 100644
index 00000000..d6052bb6
--- /dev/null
+++ b/gst/flx/gstflxdec.c
@@ -0,0 +1,644 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <string.h>
+
+#include "flx_fmt.h"
+#include "gstflxdec.h"
+
+static GstCaps* flxdec_typefind(GstBuffer *buf, gpointer private);
+
+/* flx element information */
+static GstElementDetails flxdec_details = {
+ "FLX Decoder",
+ "flxdec",
+ "FLX decoder",
+ VERSION,
+ "Sepp Wijnands <mrrazz@garbage-coderz.net>"
+ "(C) 2001",
+};
+
+static GstTypeDefinition flxdec_definition = {
+ "flxdec_video/fli",
+ "video/fli",
+ ".flc .fli",
+ flxdec_typefind,
+};
+
+/* Flx signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0
+};
+
+/* input */
+GST_PADTEMPLATE_FACTORY (sink_factory,
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "flxdec_sink",
+ "video/fli",
+ NULL
+ )
+)
+
+/* output */
+GST_PADTEMPLATE_FACTORY (src_video_factory,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "src_video",
+ "video/raw",
+ "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')),
+ "bpp", GST_PROPS_INT (32),
+ "depth", GST_PROPS_INT (32),
+ "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN),
+ "red_mask", GST_PROPS_INT (0x00ff0000),
+ "green_mask", GST_PROPS_INT (0x0000ff00),
+ "blue_mask", GST_PROPS_INT (0x000000ff),
+ "width", GST_PROPS_INT_RANGE(320, 1280),
+ "height", GST_PROPS_INT_RANGE(200, 1024)
+ )
+)
+
+
+static void gst_flxdec_class_init (GstFlxDecClass *klass);
+static void gst_flxdec_init (GstFlxDec *flxdec);
+
+static void gst_flxdec_loop (GstElement *element);
+
+static void gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+
+static void flx_decode_color(GstFlxDec *, guchar *, guchar *);
+static void flx_decode_brun(GstFlxDec *, guchar *, guchar *);
+static void flx_decode_delta_fli(GstFlxDec *, guchar *, guchar *);
+static void flx_decode_delta_flc(GstFlxDec *, guchar *, guchar *);
+
+#define rndalign(off) ((off) + ((off) % 2))
+
+static GstElementClass *parent_class = NULL;
+
+static GstCaps*
+flxdec_typefind (GstBuffer *buf, gpointer private)
+{
+ guchar *data = GST_BUFFER_DATA(buf);
+ GstCaps *new;
+
+ // check magic
+ if ((data[4] == 0x11 || data[4] == 0x12
+ || data[4] == 0x30 || data[4] == 0x44) && data[5] == 0xaf) {
+ // check the frame type of the first frame
+ if ((data[132] == 0x00 || data[132] == 0xfa) && data[133] == 0xf1) {
+ g_print("GstFlxDec: found supported flx format\n");
+ new = gst_caps_new("flxdec_typefind","video/fli", NULL);
+ return new;
+ }
+ }
+
+ return NULL;
+}
+
+
+GType
+gst_flxdec_get_type(void)
+{
+ static GType flxdec_type = 0;
+
+ if (!flxdec_type) {
+ static const GTypeInfo flxdec_info = {
+ sizeof(GstFlxDecClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_flxdec_class_init,
+ NULL,
+ NULL,
+ sizeof(GstFlxDec),
+ 0,
+ (GInstanceInitFunc)gst_flxdec_init,
+ };
+ flxdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstFlxDec", &flxdec_info, 0);
+ }
+ return flxdec_type;
+}
+
+static void
+gst_flxdec_class_init (GstFlxDecClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = NULL;
+ gobject_class->get_property = NULL;
+
+}
+
+
+
+static void
+gst_flxdec_init(GstFlxDec *flxdec)
+{
+ flxdec->sinkpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (sink_factory), "sink");
+ gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->sinkpad);
+ gst_element_set_loop_function(GST_ELEMENT(flxdec),gst_flxdec_loop);
+
+ flxdec->srcpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (src_video_factory), "src");
+ gst_element_add_pad(GST_ELEMENT(flxdec),flxdec->srcpad);
+
+ flxdec->buf = NULL;
+ flxdec->offset = 0;
+ flxdec->new_buf = TRUE;
+
+}
+
+static void
+flx_decode_chunks (GstFlxDec *flxdec , gulong count, gchar *data, gchar *dest)
+{
+ FlxFrameChunk *hdr;
+
+ g_return_if_fail(data != NULL);
+
+ while (count--) {
+ hdr = (FlxFrameChunk *) data;
+ data += FlxFrameChunkSize;
+
+ switch(hdr->id)
+ {
+ case FLX_COLOR64:
+ case FLX_COLOR256:
+ flx_decode_color(flxdec, data, dest);
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_BRUN:
+ flx_decode_brun(flxdec, data, dest);
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_LC:
+ flx_decode_delta_fli(flxdec, data, dest);
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_SS2:
+ flx_decode_delta_flc(flxdec, data, dest);
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_BLACK:
+ memset(dest, 0, flxdec->size);
+ break;
+
+ case FLX_MINI:
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+
+ default:
+ g_print("GstFlxDec: Unimplented chunk type: 0x%02x size: %d\n",
+ hdr->id, hdr->size);
+ g_print("GstFlxDec: Skipping...\n");
+ data += rndalign(hdr->size) - FlxFrameChunkSize;
+ break;
+ }
+ }
+}
+
+
+static void
+flx_decode_color(GstFlxDec *flxdec, guchar *data, guchar *dest)
+{
+ guint packs, count, indx;
+
+ g_return_if_fail(flxdec != NULL);
+
+ packs = (data[0] + (data[1] << 8));
+
+ data += 2;
+ indx = 0;
+
+ g_print("GstFlxDec: cmap packs: %d\n", packs);
+ while (packs--) {
+ /* color map index + skip count */
+ indx += *data++;
+
+ /* number of rgb triplets */
+ count = *data++ & 0xff;
+ if (count == 0)
+ count = 256;
+
+ g_print("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
+ flx_set_palette_vector(flxdec->converter, indx, count, data);
+
+ data += (count * 3);
+ }
+}
+
+static void
+flx_decode_brun(GstFlxDec *flxdec, guchar *data, guchar *dest)
+{
+ gulong count, lines, row;
+ guchar x;
+
+ g_return_if_fail(flxdec != NULL);
+
+ lines = flxdec->hdr.height;
+ while(lines--) {
+ /* packet count.
+ * should not be used anymore, since the flc format can
+ * contain more then 255 RLE packets. we use the frame
+ * width instead.
+ */
+ data++;
+
+ row = flxdec->hdr.width;
+ while(row) {
+ count = *data++;
+
+ if (count > 0x7f) {
+ /* literal run */
+ count = 0x100 - count;
+ row -= count;
+
+ while(count--)
+ *dest++ = *data++;
+
+ } else {
+ /* replicate run */
+ row -= count;
+ x = *data++;
+
+ while(count--)
+ *dest++ = x;
+ }
+ }
+ }
+}
+
+static void
+flx_decode_delta_fli(GstFlxDec *flxdec, guchar *data, guchar *dest)
+{
+ gulong count, packets, lines, start_line, start_l;
+ guchar *start_p, x;
+
+ g_return_if_fail(flxdec != NULL);
+ g_return_if_fail(flxdec->delta != NULL);
+
+
+ /* use last frame for delta */
+ memcpy(dest, GST_BUFFER_DATA(flxdec->delta),
+ GST_BUFFER_SIZE(flxdec->delta));
+
+ start_line = (data[0] + (data[1] << 8));
+ lines = (data[2] + (data[3] << 8));
+ data += 4;
+
+ /* start position of delta */
+ dest += (flxdec->hdr.width * start_line);
+ start_p = dest;
+ start_l = lines;
+
+ while(lines--) {
+ /* packet count */
+ packets = *data++;
+
+ dest = start_p + (flxdec->hdr.width * (start_l - lines));
+
+ while(packets--) {
+ /* skip count */
+ dest += *data++;
+
+ /* RLE count */
+ count = *data++;
+
+ if (count > 0x7f) {
+ /* literal run */
+ count = 0x100 - count;
+ x = *data++;
+
+ while (count--)
+ *dest++ = x;
+
+ } else {
+ /* replicate run */
+ while (count--)
+ *dest++ = *data++;
+ }
+ }
+ }
+}
+
+static void
+flx_decode_delta_flc(GstFlxDec *flxdec, guchar *data, guchar *dest)
+{
+ gulong count, lines, start_l, opcode;
+ guchar *start_p;
+
+ g_return_if_fail(flxdec != NULL);
+ g_return_if_fail(flxdec->delta != NULL);
+
+
+ /* use last frame for delta */
+ memcpy(dest, GST_BUFFER_DATA(flxdec->delta),
+ GST_BUFFER_SIZE(flxdec->delta));
+
+ lines = (data[0] + (data[1] << 8));
+ data += 2;
+
+ start_p = dest;
+ start_l = lines;
+
+ while(lines--) {
+ dest = start_p + (flxdec->hdr.width * (start_l - lines));
+
+ /* process opcode(s) */
+ while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
+ data += 2;
+ if ((opcode & 0xc000) == 0xc000) {
+ /* skip count */
+ start_l += (0x10000 - opcode);
+ dest += flxdec->hdr.width * (0x10000 - opcode);
+ } else {
+ /* last pixel */
+ dest += flxdec->hdr.width;
+ *dest++ = (opcode & 0xff);
+ }
+ }
+ data += 2;
+
+ /* last opcode is the packet count */
+ while(opcode--) {
+ /* skip count */
+ dest += *data++;
+
+ /* RLE count */
+ count = *data++;
+
+ if (count > 0x7f) {
+ /* replicate word run */
+ count = 0x100 - count;
+ while (count--) {
+ *dest++ = data[0];
+ *dest++ = data[1];
+ }
+ data += 2;
+ } else {
+ /* literal word run */
+ while (count--) {
+ *dest++ = *data++;
+ *dest++ = *data++;
+ }
+ }
+ }
+ }
+}
+
+static GstBuffer*
+flx_get_data(GstFlxDec *flxdec, gulong size)
+{
+ GstBuffer *retbuf;
+
+ g_return_val_if_fail (flxdec != NULL, NULL);
+
+ if (flxdec->new_buf) {
+ retbuf = gst_pad_pullregion(flxdec->sinkpad,
+ GST_REGION_OFFSET_LEN, 0, size);
+ flxdec->new_buf = FALSE;
+ flxdec->offset = size;
+ } else {
+ retbuf = gst_pad_pullregion(flxdec->sinkpad, GST_REGION_OFFSET_LEN,
+ flxdec->offset, size);
+ flxdec->offset += size;
+ }
+
+ return retbuf;
+}
+
+
+static void
+gst_flxdec_loop (GstElement *element)
+{
+ GstBuffer *buf;
+ GstBuffer *databuf;
+ guchar *data, *chunk;
+
+ GstFlxDec *flxdec;
+ FlxHeader *flxh;
+ FlxFrameChunk *flxfh;
+
+ g_return_if_fail (element != NULL);
+ g_return_if_fail (GST_IS_FLXDEC(element));
+
+ GST_DEBUG (0, "entering loop function\n");
+
+ flxdec = GST_FLXDEC(element);
+
+ databuf = flx_get_data(flxdec, FlxHeaderSize);
+
+ g_return_if_fail (databuf != NULL);
+
+ data = GST_BUFFER_DATA(databuf);
+
+ memcpy((char *) &flxdec->hdr, data, sizeof(FlxHeader));
+
+ gst_buffer_unref (databuf);
+
+ flxh = &flxdec->hdr;
+
+ // check header
+ if (flxh->type != FLX_MAGICHDR_FLI &&
+ flxh->type != FLX_MAGICHDR_FLC &&
+ flxh->type != FLX_MAGICHDR_FLX)
+ return;
+
+
+ g_print("GstFlxDec: size : %d\n", flxh->size);
+ g_print("GstFlxDec: frames : %d\n", flxh->frames);
+ g_print("GstFlxDec: width : %d\n", flxh->width);
+ g_print("GstFlxDec: height : %d\n", flxh->height);
+ g_print("GstFlxDec: depth : %d\n", flxh->depth);
+ g_print("GstFlxDec: speed : %d\n", flxh->speed);
+
+ gst_pad_set_caps (flxdec->srcpad,
+ gst_caps_new (
+ "src_video",
+ "video/raw",
+ gst_props_new (
+ "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R', 'G', 'B', ' ')),
+ "bpp", GST_PROPS_INT (32),
+ "depth", GST_PROPS_INT (32),
+ "endianness", GST_PROPS_INT (G_LITTLE_ENDIAN),
+ "red_mask", GST_PROPS_INT (0x00ff0000),
+ "green_mask", GST_PROPS_INT (0x0000ff00),
+ "blue_mask", GST_PROPS_INT (0x000000ff),
+ "width", GST_PROPS_INT (flxh->width),
+ "height", GST_PROPS_INT (flxh->height),
+ NULL)));
+
+ if (flxh->depth <= 8)
+ flxdec->converter = flx_colorspace_converter_new(flxh->width, flxh->height);
+
+ if (flxh->type == FLX_MAGICHDR_FLC ||
+ flxh->type == FLX_MAGICHDR_FLX) {
+ g_print("GstFlxDec: (FLC) aspect_dx : %d\n",
+ flxh->aspect_dx);
+ g_print("GstFlxDec: (FLC) aspect_dy : %d\n",
+ flxh->aspect_dy);
+ g_print("GstFlxDec: (FLC) oframe1 : 0x%08x\n",
+ flxh->oframe1);
+ g_print("GstFlxDec: (FLC) oframe2 : 0x%08x\n",
+ flxh->oframe2);
+ }
+
+
+ flxdec->size = (flxh->width * flxh->height);
+
+ // create delta and output frame
+ flxdec->frame = gst_buffer_new();
+ flxdec->delta = gst_buffer_new();
+ GST_BUFFER_DATA(flxdec->frame) = g_malloc(flxdec->size);
+ GST_BUFFER_SIZE(flxdec->frame) = flxdec->size;
+ GST_BUFFER_DATA(flxdec->delta) = g_malloc(flxdec->size);
+ GST_BUFFER_SIZE(flxdec->delta) = flxdec->size;
+
+ do
+ {
+
+ databuf = flx_get_data(flxdec, FlxFrameChunkSize);
+
+ flxfh = (FlxFrameChunk *) GST_BUFFER_DATA(databuf);
+
+ switch(flxfh->id)
+ {
+ case FLX_FRAME_TYPE:
+ buf = flx_get_data(flxdec, flxfh->size-FlxFrameChunkSize);
+
+ chunk = GST_BUFFER_DATA(buf);
+
+ if (((FlxFrameType *)chunk)->chunks == 0)
+ break;
+
+ // create 32 bits output frame
+ flxdec->out = gst_buffer_new();
+ GST_BUFFER_DATA(flxdec->out) = g_malloc(flxdec->size * 4);
+ GST_BUFFER_SIZE(flxdec->out) = flxdec->size * 4;
+
+
+ // decode chunks
+ flx_decode_chunks(flxdec,
+ ((FlxFrameType *)chunk)->chunks,
+ GST_BUFFER_DATA(buf) + FlxFrameTypeSize,
+ GST_BUFFER_DATA(flxdec->frame));
+
+ // destroy input buffer
+ gst_buffer_unref(buf);
+
+ // save copy of the current frame for possible delta.
+ memcpy(GST_BUFFER_DATA(flxdec->delta),
+ GST_BUFFER_DATA(flxdec->frame),
+ GST_BUFFER_SIZE(flxdec->delta));
+
+ // convert current frame.
+ flx_colorspace_convert(flxdec->converter,
+ GST_BUFFER_DATA(flxdec->frame),
+ GST_BUFFER_DATA(flxdec->out));
+
+ //GST_BUFFER_FLAG_SET(flxdec->out, GST_BUFFER_FLUSH);
+ gst_pad_push(flxdec->srcpad, flxdec->out);
+
+ break;
+ }
+
+ // destroy header buffer
+ gst_buffer_unref(databuf);
+
+ }
+ while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
+
+}
+
+static void
+gst_flxdec_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstFlxDec *flxdec;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_FLXDEC(object));
+ flxdec = GST_FLXDEC(object);
+
+ switch (prop_id) {
+ default:
+ break;
+ }
+}
+
+static void
+gst_flxdec_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstFlxDec *flxdec;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_FLXDEC(object));
+ flxdec = GST_FLXDEC(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+ GstTypeFactory *type;
+
+ factory = gst_elementfactory_new("flxdec", GST_TYPE_FLXDEC, &flxdec_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ type = gst_typefactory_new (&flxdec_definition);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "flxdec",
+ plugin_init
+};
diff --git a/gst/flx/gstflxdec.h b/gst/flx/gstflxdec.h
new file mode 100644
index 00000000..cc4c94db
--- /dev/null
+++ b/gst/flx/gstflxdec.h
@@ -0,0 +1,79 @@
+/* Gnome-Streamer
+ * 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_FLX_DECODER_H__
+#define __GST_FLX_DECODER_H__
+
+#include <gst/gst.h>
+
+#include "flx_color.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Definition of structure storing data for this element. */
+typedef struct _GstFlxDec GstFlxDec;
+struct _GstFlxDec {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gboolean active, new_meta, new_buf;
+
+ GstBuffer *buf, *out, *delta, *frame;
+ gulong offset, size;
+
+ FlxColorSpaceConverter *converter;
+
+ FlxHeader hdr;
+};
+
+/* Standard definition defining a class for this element. */
+typedef struct _GstFlxDecClass GstFlxDecClass;
+struct _GstFlxDecClass {
+ GstElementClass parent_class;
+};
+
+/* Standard macros for defining types for this element. */
+#define GST_TYPE_FLXDEC \
+ (gst_flxdec_get_type())
+#define GST_FLXDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLXDEC,GstFlxDec))
+#define GST_FLXDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLXDEC,GstFlxDec))
+#define GST_IS_FLXDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLXDEC))
+#define GST_IS_FLXDEC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLXDEC))
+
+#define FLXDEC_BUFSIZE(buf, offset) \
+ ((GST_BUFFER_OFFSET(buf) + GST_BUFFER_SIZE(buf)) - offset)
+
+/* Standard function returning type information. */
+GType gst_flxdec_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_FLX_DECODER_H__ */
diff --git a/gst/mpeg1sys/.gitignore b/gst/mpeg1sys/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/mpeg1sys/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/mpeg1sys/Makefile.am b/gst/mpeg1sys/Makefile.am
new file mode 100644
index 00000000..5e28e2be
--- /dev/null
+++ b/gst/mpeg1sys/Makefile.am
@@ -0,0 +1,13 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstmpeg1systemencode.la
+
+libgstmpeg1systemencode_la_SOURCES = gstmpeg1systemencode.c \
+ buffer.c \
+ systems.c
+
+noinst_HEADERS = gstmpeg1systemencode.h \
+ main.h \
+ buffer.h
+
+libsystem_encode_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GST_CFLAGS)
diff --git a/gst/mpeg1sys/buffer.c b/gst/mpeg1sys/buffer.c
new file mode 100644
index 00000000..933b76e6
--- /dev/null
+++ b/gst/mpeg1sys/buffer.c
@@ -0,0 +1,482 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <string.h>
+
+/*#define DEBUG_ENABLED */
+#include <gst/gst.h>
+#include <libs/getbits/gstgetbits.h>
+
+#include "buffer.h"
+
+#define SEQUENCE_HEADER 0x000001b3
+#define SEQUENCE_END 0x000001b7
+#define PICTURE_START 0x00000100
+#define GROUP_START 0x000001b8
+#define SYNCWORD_START 0x000001
+
+#define AUDIO_SYNCWORD 0xfff
+
+#define CLOCKS 90000.0
+
+#define DEBUG(a, b...) g_print (##b)
+
+/* This must match decoder and encoder tables */
+static double picture_rates [16] =
+{
+ 0.0,
+ 24000.0/1001.,
+ 24.0,
+ 25.0,
+ 30000.0/1001.,
+ 30.0,
+ 50.0,
+ 60000.0/1001.,
+ 60.0,
+
+ 1,
+ 5,
+ 10,
+ 12,
+ 15,
+ 0,
+ 0
+};
+
+static double ratio [16] = { 0., 1., 0.6735, 0.7031, 0.7615, 0.8055,
+ 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575,
+ 1.2015, 0.};
+
+static char picture_types [4][3] =
+ { "I", "P", "B", "D" };
+
+static int bitrate_index[2][3][16] =
+{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, },
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, },
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } },
+ { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } },
+};
+
+static long frequency[9] =
+{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
+
+static double dfrequency[9] =
+{44.1, 48, 32, 22.05, 24, 16, 11.025, 12, 8};
+
+static unsigned int samples [4] = {192, 384, 1152, 1152};
+
+static char mode [4][15] =
+ { "stereo", "joint stereo", "dual channel", "single channel" };
+static char copyright [2][20] =
+ { "no copyright","copyright protected" };
+static char original [2][10] =
+ { "copy","original" };
+static char emphasis [4][20] =
+ { "none", "50/15 microseconds", "reserved", "CCITT J.17" };
+
+static void mpeg1mux_buffer_update_video_info(Mpeg1MuxBuffer *mb);
+static void mpeg1mux_buffer_update_audio_info(Mpeg1MuxBuffer *mb);
+
+Mpeg1MuxBuffer *mpeg1mux_buffer_new(guchar type, guchar id) {
+ Mpeg1MuxBuffer *new = g_malloc(sizeof(Mpeg1MuxBuffer));
+
+ new->buffer = NULL;
+ new->length = 0;
+ new->base = 0;
+ new->buffer_type = type;
+ new->stream_id = id;
+ new->scan_pos = 0;
+ new->new_frame = TRUE;
+ new->current_start = 0;
+ new->timecode_list = NULL;
+ new->queued_list = NULL;
+ new->next_frame_time = 0;
+
+ return new;
+}
+
+void mpeg1mux_buffer_queue(Mpeg1MuxBuffer *mb, GstBuffer *buf) {
+
+ if (mb->buffer == NULL) {
+ mb->buffer = g_malloc(GST_BUFFER_SIZE(buf));
+ mb->length = GST_BUFFER_SIZE(buf);
+ memcpy(mb->buffer, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
+ }
+ else {
+ mb->buffer = g_realloc(mb->buffer, mb->length + GST_BUFFER_SIZE(buf));
+ memcpy(mb->buffer+mb->length, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
+ mb->length += GST_BUFFER_SIZE(buf);
+ }
+
+ GST_DEBUG (0,"queuing buffer %lu\n", mb->length);
+ if (mb->buffer_type == BUFFER_TYPE_VIDEO) {
+ mpeg1mux_buffer_update_video_info(mb);
+ }
+ else {
+ mpeg1mux_buffer_update_audio_info(mb);
+ }
+}
+
+gulong mpeg1mux_buffer_update_queued(Mpeg1MuxBuffer *mb, guint64 scr) {
+ GList *queued_list;
+ Mpeg1MuxTimecode *tc;
+ gulong total_queued = 0;
+
+ GST_DEBUG (0,"queued in buffer on SCR=%llu\n", scr);
+ queued_list = g_list_first(mb->queued_list);
+
+ while (queued_list) {
+ tc = (Mpeg1MuxTimecode *) queued_list->data;
+ if (tc->DTS < scr) {
+ /* this buffer should be sent out */
+ mb->queued_list = g_list_remove(mb->queued_list, tc);
+ queued_list = g_list_first(mb->queued_list);
+ }
+ else {
+ GST_DEBUG (0,"queued in buffer %ld, %llu\n", tc->original_length, tc->DTS);
+ total_queued += tc->original_length;
+ queued_list = g_list_next(queued_list);
+ }
+ }
+ GST_DEBUG (0,"queued in buffer %lu\n", total_queued);
+
+ return total_queued;
+}
+
+void mpeg1mux_buffer_shrink(Mpeg1MuxBuffer *mb, gulong size) {
+ GList *timecode_list;
+ Mpeg1MuxTimecode *tc;
+ gulong consumed = 0;
+ gulong count;
+
+ GST_DEBUG (0,"shrinking buffer %lu\n", size);
+
+ g_assert(mb->length >= size);
+
+ memcpy(mb->buffer, mb->buffer+size, mb->length-size);
+ mb->buffer = g_realloc(mb->buffer, mb->length-size);
+
+ mb->length -= size;
+ mb->scan_pos -= size;
+ mb->current_start -= size;
+
+ timecode_list = g_list_first(mb->timecode_list);
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+
+ if (tc->length > size) {
+ tc->length -= size;
+ mb->new_frame = FALSE;
+ }
+ else {
+ consumed += tc->length;
+ while (size >= consumed) {
+ GST_DEBUG (0,"removing timecode: %llu %llu %lu %lu\n", tc->DTS, tc->PTS, tc->length, consumed);
+ mb->timecode_list = g_list_remove_link(mb->timecode_list, timecode_list);
+ mb->queued_list = g_list_append(mb->queued_list, tc);
+ timecode_list = g_list_first(mb->timecode_list);
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+ consumed += tc->length;
+ GST_DEBUG (0,"next timecode: %llu %llu %lu %lu\n", tc->DTS, tc->PTS, tc->length, consumed);
+ }
+ mb->new_frame = TRUE;
+ GST_DEBUG (0,"leftover frame size from %lu to %lu \n", tc->length, consumed-size);
+ tc->length = consumed - size;
+ }
+
+ if (mb->buffer_type == BUFFER_TYPE_VIDEO) {
+ mb->info.video.DTS = tc->DTS;
+ mb->info.video.PTS = tc->PTS;
+ mb->next_frame_time = tc->DTS;
+ }
+ else {
+ mb->info.audio.PTS = tc->PTS;
+ mb->next_frame_time = tc->PTS;
+ }
+ GST_DEBUG (0,"next frame time timecode: %llu %lu\n", mb->next_frame_time, tc->length);
+
+ /* check buffer consistency */
+ timecode_list = g_list_first(mb->timecode_list);
+ count = 0;
+
+ while (timecode_list) {
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+ count += tc->length;
+
+ timecode_list = g_list_next(timecode_list);
+ }
+
+ if (count != mb->current_start) g_print("********** error %lu != %lu\n", count, mb->current_start);
+
+ mb->base += size;
+}
+
+static void mpeg1mux_buffer_update_video_info(Mpeg1MuxBuffer *mb) {
+ gboolean have_sync = FALSE;
+ guchar *data = mb->buffer;
+ gulong offset = mb->scan_pos;
+ guint sync_zeros = 0;
+ gulong id=0;
+ guint temporal_reference, temp;
+ gst_getbits_t gb;
+
+
+ GST_DEBUG (0,"mpeg1mux::update_video_info %lu %lu\n", mb->base, mb->scan_pos);
+ if (mb->base == 0 && mb->scan_pos == 0) {
+ if ((SYNCWORD_START<<8)+*(mb->buffer+3) == SEQUENCE_HEADER) {
+
+ gst_getbits_init(&gb, NULL, NULL);
+ gst_getbits_newbuf(&gb, data+4, mb->length);
+ mb->info.video.horizontal_size = gst_getbits12(&gb);
+ mb->info.video.vertical_size = gst_getbits12(&gb);
+ mb->info.video.aspect_ratio = gst_getbits4(&gb);
+ mb->info.video.picture_rate = gst_getbits4(&gb);
+ mb->info.video.bit_rate = gst_getbits18(&gb);
+ if (gst_getbits1(&gb) != 1) {
+ g_print("mpeg1mux::update_video_info: marker bit error\n");
+ }
+ mb->info.video.vbv_buffer_size = gst_getbits10(&gb);
+ mb->info.video.CSPF = gst_getbits1(&gb);
+
+ mb->info.video.secs_per_frame = 1. / picture_rates[mb->info.video.picture_rate];
+ mb->info.video.decoding_order=0;
+ mb->info.video.group_order=0;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: secs per frame %g\n", mb->info.video.secs_per_frame);
+ }
+ else {
+ g_print("mpeg1mux::update_video_info: Invalid MPEG Video header\n");
+ }
+ }
+ while (offset < mb->length-6) {
+ if (!have_sync) {
+ guchar byte = *(data+offset);
+ /*GST_DEBUG (0,"mpeg1mux::update_video_info: found #%d at %lu\n",byte,offset); */
+ offset++;
+ /* if it's zero, increment the zero count */
+ if (byte == 0) {
+ sync_zeros++;
+ /*GST_DEBUG (0,"mpeg1mux::update_video_info: found zero #%d at %lu\n",sync_zeros,offset-1); */
+ }
+ /* if it's a one and we have two previous zeros, we have sync */
+ else if ((byte == 1) && (sync_zeros >= 2)) {
+ GST_DEBUG (0,"mpeg1mux::update_video_info: synced at %lu\n",offset-1);
+ have_sync = TRUE;
+ sync_zeros = 0;
+ }
+ /* if it's anything else, we've lost it completely */
+ else sync_zeros = 0;
+ /* then snag the chunk ID */
+ } else if (id == 0) {
+ id = *(data+offset);
+ GST_DEBUG (0,"mpeg1mux::update_video_info: got id 0x%02lX\n",id);
+ id = (SYNCWORD_START<<8)+id;
+ switch (id) {
+ case SEQUENCE_HEADER:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: sequence header\n");
+ break;
+ case GROUP_START:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: group start\n");
+ mb->info.video.group_order=0;
+ break;
+ case PICTURE_START:
+ /* skip the first access unit */
+ if (mb->info.video.decoding_order != 0) {
+ Mpeg1MuxTimecode *tc;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: PTS %llu, DTS %llu, length %lu\n", mb->info.video.current_PTS,
+ mb->info.video.current_DTS, offset - mb->current_start-3);
+
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = offset - mb->current_start-3;
+ tc->original_length = tc->length;
+ tc->frame_type = mb->info.video.current_type;
+ tc->DTS = mb->info.video.current_DTS;
+ tc->PTS = mb->info.video.current_PTS;
+
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ if (mb->info.video.decoding_order == 0) {
+ mb->next_frame_time = tc->DTS;
+ }
+
+ mb->current_start = offset-3;
+ }
+
+ temp= (*(data+offset+1)<<8)+*(data+offset+2);
+ temporal_reference = (temp & 0xffc0) >> 6;
+ mb->info.video.current_type = (temp & 0x0038) >> 3;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: picture start temporal_ref:%d type:%s Frame\n", temporal_reference,
+ picture_types[mb->info.video.current_type-1]);
+
+ mb->info.video.current_DTS = mb->info.video.decoding_order * mb->info.video.secs_per_frame * CLOCKS;
+ mb->info.video.current_PTS = (temporal_reference - mb->info.video.group_order + 1 +
+ mb->info.video.decoding_order) *mb->info.video.secs_per_frame*CLOCKS;
+
+ mb->info.video.decoding_order++;
+ mb->info.video.group_order++;
+
+
+ offset++;
+ break;
+ case SEQUENCE_END:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: sequence end\n");
+ break;
+ }
+ /* prepare for next sync */
+ offset++;
+ have_sync = FALSE;
+ id = 0;
+ sync_zeros = 0;
+ }
+ }
+ mb->scan_pos = offset;
+}
+
+static void mpeg1mux_buffer_update_audio_info(Mpeg1MuxBuffer *mb) {
+ guchar *data = mb->buffer;
+ gulong offset = mb->scan_pos;
+ gulong id=0;
+ guint padding_bit;
+ gst_getbits_t gb;
+ guint startup_delay = 0;
+ int layer_index,lsf,samplerate_index,padding;
+ long bpf;
+ Mpeg1MuxTimecode *tc;
+
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info %lu %lu\n", mb->base, mb->scan_pos);
+ if (mb->base == 0 && mb->scan_pos == 0) {
+ id = GULONG_FROM_BE(*((gulong *)(data)));
+
+ printf("MPEG audio id = %08lx\n", id);
+ if ((id & 0xfff00000) == AUDIO_SYNCWORD<<20) {
+
+ /*mpegver = (header >> 19) & 0x3; // don't need this for bpf */
+ layer_index = (id >> 17) & 0x3;
+ mb->info.audio.layer = 4 - layer_index;
+ lsf = (id & (1 << 20)) ? ((id & (1 << 19)) ? 0 : 1) : 1;
+ mb->info.audio.bit_rate = bitrate_index[lsf][mb->info.audio.layer - 1][((id >> 12) & 0xf)];
+ samplerate_index = (id >> 10) & 0x3;
+ padding = (id >> 9) & 0x1;
+
+ if (mb->info.audio.layer == 1) {
+ bpf = mb->info.audio.bit_rate * 12000;
+ bpf /= frequency[samplerate_index];
+ bpf = ((bpf + padding) << 2);
+ } else {
+ bpf = mb->info.audio.bit_rate * 144000;
+ bpf /= frequency[samplerate_index];
+ bpf += padding;
+ }
+ mb->info.audio.framesize = bpf;
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: samples per second %d\n", samplerate_index);
+
+ gst_getbits_init(&gb, NULL, NULL);
+ gst_getbits_newbuf(&gb, data, mb->length);
+
+ gst_flushbitsn(&gb, 12);
+ if (gst_getbits1(&gb) != 1) {
+ g_print("mpeg1mux::update_audio_info: marker bit error\n");
+ }
+ gst_flushbitsn(&gb, 2);
+ mb->info.audio.protection = gst_getbits1(&gb);
+ gst_flushbitsn(&gb, 4);
+ mb->info.audio.frequency = gst_getbits2(&gb);
+ padding_bit = gst_getbits1(&gb);
+ gst_flushbitsn(&gb, 1);
+ mb->info.audio.mode = gst_getbits2(&gb);
+ mb->info.audio.mode_extension = gst_getbits2(&gb);
+ mb->info.audio.copyright = gst_getbits1(&gb);
+ mb->info.audio.original_copy = gst_getbits1(&gb);
+ mb->info.audio.emphasis = gst_getbits2(&gb);
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: layer %d\n", mb->info.audio.layer);
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: bit_rate %d\n", mb->info.audio.bit_rate);
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: frequency %d\n", mb->info.audio.frequency);
+
+ mb->info.audio.samples_per_second = (double)dfrequency [mb->info.audio.frequency];
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: samples per second %g\n", mb->info.audio.samples_per_second);
+
+ mb->info.audio.decoding_order=0;
+
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = mb->info.audio.framesize;
+ tc->original_length = tc->length;
+ tc->frame_type = FRAME_TYPE_AUDIO;
+
+ mb->info.audio.current_PTS = mb->info.audio.decoding_order * samples [mb->info.audio.layer] /
+ mb->info.audio.samples_per_second * 90. + startup_delay;
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: PTS %llu, length %u\n", mb->info.audio.current_PTS, mb->info.audio.framesize);
+ tc->PTS = mb->info.audio.current_PTS;
+ tc->DTS = mb->info.audio.current_PTS;
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ mb->next_frame_time = tc->PTS;
+
+ mb->info.audio.decoding_order++;
+ offset += tc->length;
+ }
+ else {
+ g_print("mpeg1mux::update_audio_info: Invalid MPEG Video header\n");
+ }
+ }
+ while (offset < mb->length-4) {
+ id = GULONG_FROM_BE(*((gulong *)(data+offset)));
+
+ /*mpegver = (header >> 19) & 0x3; // don't need this for bpf */
+ layer_index = (id >> 17) & 0x3;
+ mb->info.audio.layer = 4 - layer_index;
+ lsf = (id & (1 << 20)) ? ((id & (1 << 19)) ? 0 : 1) : 1;
+ mb->info.audio.bit_rate = bitrate_index[lsf][mb->info.audio.layer - 1][((id >> 12) & 0xf)];
+ samplerate_index = (id >> 10) & 0x3;
+ padding = (id >> 9) & 0x1;
+
+ if (mb->info.audio.layer == 1) {
+ bpf = mb->info.audio.bit_rate * 12000;
+ bpf /= frequency[samplerate_index];
+ bpf = ((bpf + padding) << 2);
+ } else {
+ bpf = mb->info.audio.bit_rate * 144000;
+ bpf /= frequency[samplerate_index];
+ bpf += padding;
+ }
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = bpf;
+ tc->original_length = tc->length;
+ tc->frame_type = FRAME_TYPE_AUDIO;
+
+ mb->current_start = offset + bpf;
+
+ mb->info.audio.samples_per_second = (double)dfrequency [mb->info.audio.frequency];
+
+ mb->info.audio.current_PTS = (mb->info.audio.decoding_order * samples [mb->info.audio.layer]) /
+ mb->info.audio.samples_per_second * 90. ;
+
+ tc->DTS = tc->PTS = mb->info.audio.current_PTS;
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: PTS %llu, %llu length %lu\n", mb->info.audio.current_PTS, tc->PTS, tc->length);
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ mb->info.audio.decoding_order++;
+ offset += tc->length;
+ }
+ mb->scan_pos = offset;
+}
diff --git a/gst/mpeg1sys/buffer.h b/gst/mpeg1sys/buffer.h
new file mode 100644
index 00000000..f3eba4f7
--- /dev/null
+++ b/gst/mpeg1sys/buffer.h
@@ -0,0 +1,141 @@
+/* Gnome-Streamer
+ * 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 __BUFFER_H__
+#define __BUFFER_H__
+
+#include <gst/gst.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define MPEG1MUX_BUFFER_QUEUED(mb) (g_list_length((mb)->timecode_list))
+#define MPEG1MUX_BUFFER_SPACE(mb) ((mb)->length)
+#define MPEG1MUX_BUFFER_DATA(mb) ((mb)->buffer)
+#define MPEG1MUX_BUFFER_TYPE(mb) ((mb)->buffer)
+#define MPEG1MUX_BUFFER_FIRST_TIMECODE(mb) (g_list_first((mb)->timecode_list)->data)
+
+#define BUFFER_TYPE_VIDEO 1
+#define BUFFER_TYPE_AUDIO 2
+
+#define FRAME_TYPE_IFRAME 1
+#define FRAME_TYPE_BFRAME 2
+#define FRAME_TYPE_PFRAME 3
+#define FRAME_TYPE_AUDIO 4
+
+typedef struct _Mpeg1MuxBuffer Mpeg1MuxBuffer;
+typedef struct _Mpeg1MuxTimecode Mpeg1MuxTimecode;
+
+typedef struct video_struc /* Informationen ueber Video Stream */
+{
+ unsigned int stream_length ;
+ unsigned int num_sequence ;
+ unsigned int num_seq_end ;
+ unsigned int num_pictures ;
+ unsigned int num_groups ;
+ unsigned int num_frames[4] ;
+ unsigned int avg_frames[4] ;
+
+ unsigned int horizontal_size;
+ unsigned int vertical_size ;
+ unsigned int aspect_ratio ;
+ unsigned int picture_rate ;
+ unsigned int bit_rate ;
+ unsigned int comp_bit_rate ;
+ unsigned int vbv_buffer_size;
+ unsigned int CSPF ;
+
+ guint64 PTS;
+ guint64 DTS;
+
+ guint64 current_PTS;
+ guint64 current_DTS;
+ guchar current_type;
+
+ double secs_per_frame;
+ gulong group_order, decoding_order;
+} Video_struc;
+
+typedef struct audio_struc /* Informationen ueber Audio Stream */
+{
+ unsigned int stream_length ;
+ unsigned int num_syncword ;
+ unsigned int num_frames [2] ;
+ unsigned int framesize ;
+ unsigned int layer ;
+ unsigned int protection ;
+ unsigned int bit_rate ;
+ unsigned int frequency ;
+ unsigned int mode ;
+ unsigned int mode_extension ;
+ unsigned int copyright ;
+ unsigned int original_copy ;
+ unsigned int emphasis ;
+
+ guint64 PTS;
+
+ guint64 current_PTS;
+
+ double samples_per_second;
+ gulong decoding_order;
+} Audio_struc;
+
+struct _Mpeg1MuxTimecode {
+ gulong length;
+ gulong original_length;
+ guchar frame_type;
+ guint64 PTS;
+ guint64 DTS;
+};
+
+struct _Mpeg1MuxBuffer {
+ unsigned char *buffer;
+ gulong length;
+ gulong base;
+ gulong scan_pos;
+ gulong last_pos;
+ gulong current_start;
+ guchar buffer_type;
+ guchar stream_id;
+ gboolean new_frame;
+ guint64 next_frame_time;
+
+ union {
+ Video_struc video;
+ Audio_struc audio;
+ } info;
+
+ GList *timecode_list;
+ GList *queued_list;
+};
+
+Mpeg1MuxBuffer *mpeg1mux_buffer_new(guchar type, guchar id);
+
+void mpeg1mux_buffer_queue(Mpeg1MuxBuffer *mb, GstBuffer *buf);
+void mpeg1mux_buffer_shrink(Mpeg1MuxBuffer *mb, gulong size);
+gulong mpeg1mux_buffer_update_queued(Mpeg1MuxBuffer *mb, guint64 scr);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __BUFFER_H__ */
diff --git a/gst/mpeg1sys/gstmpeg1systemencode.c b/gst/mpeg1sys/gstmpeg1systemencode.c
new file mode 100644
index 00000000..d8927d0f
--- /dev/null
+++ b/gst/mpeg1sys/gstmpeg1systemencode.c
@@ -0,0 +1,572 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/*#define DEBUG_ENABLED */
+#include "gstmpeg1systemencode.h"
+#include "main.h"
+
+/*#define GST_DEBUG(a, b...) g_print (##b) */
+
+/* elementfactory information */
+static GstElementDetails system_encode_details = {
+ "MPEG1 Multiplexer",
+ "Filter/Multiplexer/System",
+ "Multiplexes MPEG-1 Streams",
+ VERSION,
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2000",
+};
+
+/* GstMPEG1SystemEncode signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ /* FILL ME */
+};
+
+GST_PADTEMPLATE_FACTORY (src_factory,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "src_video",
+ "video/mpeg",
+ "mpegversion", GST_PROPS_INT (1),
+ "systemstream", GST_PROPS_BOOLEAN (TRUE)
+ )
+)
+GST_PADTEMPLATE_FACTORY (video_sink_factory,
+ "video_%02d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_CAPS_NEW (
+ "sink_video",
+ "video/mpeg",
+ "mpegversion", GST_PROPS_INT (1),
+ "systemstream", GST_PROPS_BOOLEAN (FALSE)
+ )
+)
+
+GST_PADTEMPLATE_FACTORY (audio_sink_factory,
+ "audio_%02d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_CAPS_NEW (
+ "sink_audio",
+ "audio/mp3",
+ NULL
+ )
+)
+
+static void gst_system_encode_class_init (GstMPEG1SystemEncodeClass *klass);
+static void gst_system_encode_init (GstMPEG1SystemEncode *system_encode);
+
+static GstPad* gst_system_encode_request_new_pad (GstElement *element, GstPadTemplate *templ,
+ const gchar *unused);
+static void gst_system_encode_chain (GstPad *pad, GstBuffer *buf);
+
+static void gst_system_encode_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void gst_system_encode_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_system_encode_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_mpeg1_system_encode_get_type (void)
+{
+ static GType system_encode_type = 0;
+
+ if (!system_encode_type) {
+ static const GTypeInfo system_encode_info = {
+ sizeof(GstMPEG1SystemEncodeClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)gst_system_encode_class_init,
+ NULL,
+ NULL,
+ sizeof(GstMPEG1SystemEncode),
+ 0,
+ (GInstanceInitFunc)gst_system_encode_init,
+ NULL
+ };
+ system_encode_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMPEG1SystemEncode", &system_encode_info, 0);
+ }
+ return system_encode_type;
+}
+
+static void
+gst_system_encode_class_init (GstMPEG1SystemEncodeClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_system_encode_set_property;
+ gobject_class->get_property = gst_system_encode_get_property;
+
+ gstelement_class->request_new_pad = gst_system_encode_request_new_pad;
+}
+
+static void
+gst_system_encode_init (GstMPEG1SystemEncode *system_encode)
+{
+ system_encode->srcpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (src_factory), "src");
+ gst_element_add_pad (GST_ELEMENT (system_encode), system_encode->srcpad);
+
+ system_encode->video_buffer = mpeg1mux_buffer_new (BUFFER_TYPE_VIDEO, 0xE0);
+ system_encode->audio_buffer = mpeg1mux_buffer_new (BUFFER_TYPE_AUDIO, 0xC0);
+ system_encode->have_setup = FALSE;
+ system_encode->mta = NULL;
+ system_encode->packet_size = 2048;
+ system_encode->lock = g_mutex_new();
+ system_encode->current_pack = system_encode->packets_per_pack = 3;
+ system_encode->video_delay_ms = 0;
+ system_encode->audio_delay_ms = 0;
+ system_encode->sectors_delay = 0;
+ system_encode->startup_delay = ~1;
+ system_encode->which_streams = 0;
+ system_encode->num_audio_pads = 0;
+ system_encode->num_video_pads = 0;
+ system_encode->pack = g_malloc (sizeof (Pack_struc));
+ system_encode->sys_header = g_malloc (sizeof (Sys_header_struc));
+ system_encode->sector = g_malloc (sizeof (Sector_struc));
+
+}
+
+static GstPad*
+gst_system_encode_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
+{
+ GstMPEG1SystemEncode *system_encode;
+ gchar *name = NULL;
+ GstPad *newpad;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+
+ if (templ->direction != GST_PAD_SINK) {
+ g_warning ("system_encode: request pad that is not a SINK pad\n");
+ return NULL;
+ }
+ system_encode = GST_SYSTEM_ENCODE (element);
+
+ if (templ == GST_PADTEMPLATE_GET (audio_sink_factory)) {
+ name = g_strdup_printf ("audio_%02d", system_encode->num_audio_pads);
+ g_print ("%s\n", name);
+ newpad = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (newpad, GINT_TO_POINTER (system_encode->num_audio_pads));
+
+ system_encode->audio_pad[system_encode->num_audio_pads] = newpad;
+ system_encode->num_audio_pads++;
+ system_encode->which_streams |= STREAMS_AUDIO;
+ }
+ else if (templ == GST_PADTEMPLATE_GET (video_sink_factory)) {
+ name = g_strdup_printf ("video_%02d", system_encode->num_video_pads);
+ g_print ("%s\n", name);
+ newpad = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (newpad, GINT_TO_POINTER (system_encode->num_video_pads));
+
+ system_encode->video_pad[system_encode->num_video_pads] = newpad;
+ system_encode->num_video_pads++;
+ system_encode->which_streams |= STREAMS_VIDEO;
+ }
+ else {
+ g_warning ("system_encode: this is not our template!\n");
+ return NULL;
+ }
+
+ gst_pad_set_chain_function (newpad, gst_system_encode_chain);
+ gst_element_add_pad (GST_ELEMENT (system_encode), newpad);
+
+ return newpad;
+}
+
+/* return a list of all the highest prioripty streams */
+static GList*
+gst_system_encode_pick_streams (GList *mta, GstMPEG1SystemEncode *system_encode)
+{
+ guint64 lowest = ~1;
+
+ GST_DEBUG (0, "pick_streams: %lld, %lld\n", system_encode->video_buffer->next_frame_time,
+ system_encode->audio_buffer->next_frame_time);
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ if (system_encode->video_buffer->next_frame_time < lowest-system_encode->video_delay) {
+ lowest = system_encode->video_buffer->next_frame_time;
+ }
+ }
+ if (system_encode->which_streams & STREAMS_AUDIO) {
+ if (system_encode->audio_buffer->next_frame_time < lowest-system_encode->audio_delay) {
+ lowest = system_encode->audio_buffer->next_frame_time;
+ }
+ }
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ if (system_encode->video_buffer->next_frame_time == lowest) {
+ mta = g_list_append(mta, system_encode->video_buffer);
+ }
+ }
+ if (system_encode->which_streams & STREAMS_AUDIO) {
+ if (system_encode->audio_buffer->next_frame_time == lowest) {
+ mta = g_list_append(mta, system_encode->audio_buffer);
+ }
+ }
+ return mta;
+}
+
+static gboolean
+gst_system_encode_have_data (GstMPEG1SystemEncode *system_encode)
+{
+
+ if (system_encode->which_streams == (STREAMS_VIDEO | STREAMS_AUDIO)) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->audio_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer) > system_encode->packet_size*2 &&
+ MPEG1MUX_BUFFER_QUEUED(system_encode->video_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+ if (system_encode->which_streams == STREAMS_VIDEO) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->video_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+ if (system_encode->which_streams == STREAMS_VIDEO) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->audio_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static GList*
+gst_system_encode_update_mta (GstMPEG1SystemEncode *system_encode, GList *mta, gulong size)
+{
+ GList *streams = g_list_first(mta);
+ Mpeg1MuxBuffer *mb = (Mpeg1MuxBuffer *)streams->data;
+
+ GST_DEBUG (0,"system_encode::multiplex: update mta\n");
+
+ mpeg1mux_buffer_shrink(mb, size);
+
+ mta = g_list_remove(mta, mb);
+
+ return mta;
+}
+
+static void
+gst_system_setup_multiplex (GstMPEG1SystemEncode *system_encode)
+{
+ Mpeg1MuxTimecode *video_tc, *audio_tc;
+
+ system_encode->audio_buffer_size = 4*1024;
+ system_encode->video_buffer_size = 46*1024;
+ system_encode->bytes_output = 0;
+ system_encode->min_packet_data = system_encode->packet_size - PACK_HEADER_SIZE - SYS_HEADER_SIZE -
+ PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH;
+ system_encode->max_packet_data = system_encode->packet_size - PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH;
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ system_encode->video_rate = system_encode->video_buffer->info.video.bit_rate * 50;
+ }
+ else system_encode->video_rate = 0;
+ if (system_encode->which_streams & STREAMS_AUDIO)
+ system_encode->audio_rate = system_encode->audio_buffer->info.audio.bit_rate * 128;
+ else system_encode->audio_rate = 0;
+
+ system_encode->data_rate = system_encode->video_rate + system_encode->audio_rate;
+
+ system_encode->dmux_rate = ceil((double)(system_encode->data_rate) *
+ ((double)(system_encode->packet_size)/(double)(system_encode->min_packet_data) +
+ ((double)(system_encode->packet_size)/(double)(system_encode->max_packet_data) *
+ (double)(system_encode->packets_per_pack-1.))) / (double)(system_encode->packets_per_pack) );
+ system_encode->data_rate = ceil(system_encode->dmux_rate/50.)*50;
+
+ GST_DEBUG (0,"system_encode::multiplex: data_rate %u, video_rate: %u, audio_rate: %u\n", system_encode->data_rate,
+ system_encode->video_rate, system_encode->audio_rate);
+
+ system_encode->video_delay = (double)system_encode->video_delay_ms*(double)(CLOCKS/1000);
+ system_encode->audio_delay = (double)system_encode->audio_delay_ms*(double)(CLOCKS/1000);
+
+ system_encode->mux_rate = ceil(system_encode->dmux_rate/50.);
+ system_encode->dmux_rate= system_encode->mux_rate * 50.;
+
+ video_tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(system_encode->video_buffer);
+ audio_tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(system_encode->audio_buffer);
+
+ GST_DEBUG (0,"system_encode::video tc %lld, audio tc %lld:\n", video_tc->DTS, audio_tc->DTS);
+
+ system_encode->delay = ((double)system_encode->sectors_delay +
+ ceil((double)video_tc->length/(double)system_encode->min_packet_data) +
+ ceil((double)video_tc->length/(double)system_encode->min_packet_data )) *
+ (double)system_encode->packet_size/system_encode->dmux_rate*(double)CLOCKS;
+
+ system_encode->audio_delay += system_encode->delay;
+ system_encode->video_delay += system_encode->delay;
+
+ system_encode->audio_delay = 0;
+ system_encode->video_delay = 0;
+ system_encode->delay = 0;
+
+ GST_DEBUG (0,"system_encode::multiplex: delay %g, mux_rate: %lu\n", system_encode->delay, system_encode->mux_rate);
+}
+
+static void
+gst_system_encode_multiplex(GstMPEG1SystemEncode *system_encode)
+{
+ GList *streams;
+ Mpeg1MuxBuffer *mb = (Mpeg1MuxBuffer *)streams->data;
+ guchar timestamps;
+ guchar buffer_scale;
+ GstBuffer *outbuf;
+ Pack_struc *pack;
+ Sys_header_struc *sys_header;
+ Mpeg1MuxTimecode *tc;
+ gulong buffer_size, non_scaled_buffer_size, total_queued;
+ guint64 PTS, DTS;
+
+ g_mutex_lock(system_encode->lock);
+
+ while (gst_system_encode_have_data(system_encode)) {
+ GST_DEBUG (0,"system_encode::multiplex: multiplexing\n");
+
+ if (!system_encode->have_setup) {
+ gst_system_setup_multiplex(system_encode);
+ system_encode->have_setup = TRUE;
+ }
+
+ if (system_encode->mta == NULL) {
+ system_encode->mta = gst_system_encode_pick_streams(system_encode->mta, system_encode);
+ }
+ if (system_encode->mta == NULL) break;
+
+
+ system_encode->SCR = (guint64)(system_encode->bytes_output+LAST_SCR_BYTE_IN_PACK)*CLOCKS/system_encode->dmux_rate;
+
+
+ streams = g_list_first(system_encode->mta);
+ mb = (Mpeg1MuxBuffer *)streams->data;
+
+ if (system_encode->current_pack == system_encode->packets_per_pack) {
+ create_pack(system_encode->pack, system_encode->SCR, system_encode->mux_rate);
+ create_sys_header (system_encode->sys_header, system_encode->mux_rate, 1, 1, 1, 1, 1, 1,
+ AUDIO_STR_0, 0, system_encode->audio_buffer_size/128,
+ VIDEO_STR_0, 1, system_encode->video_buffer_size/1024, system_encode->which_streams );
+ system_encode->current_pack = 0;
+ pack = system_encode->pack;
+ sys_header = system_encode->sys_header;
+ }
+ else {
+ system_encode->current_pack++;
+ pack = NULL;
+ sys_header = NULL;
+ }
+
+ tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(mb);
+ if (mb->new_frame) {
+ GST_DEBUG (0,"system_encode::multiplex: new frame\n");
+ if (tc->frame_type == FRAME_TYPE_AUDIO || tc->frame_type == FRAME_TYPE_IFRAME || tc->frame_type == FRAME_TYPE_PFRAME) {
+ timestamps = TIMESTAMPS_PTS;
+ }
+ else {
+ timestamps = TIMESTAMPS_PTS_DTS;
+ }
+ }
+ else {
+ timestamps = TIMESTAMPS_NO;
+ }
+
+ if (tc->frame_type != FRAME_TYPE_AUDIO) {
+ if (tc->PTS<system_encode->startup_delay)
+ system_encode->startup_delay = tc->PTS;
+ }
+
+ if (tc->frame_type == FRAME_TYPE_AUDIO) {
+ buffer_scale = 0;
+ non_scaled_buffer_size = system_encode->audio_buffer_size;
+ buffer_size = system_encode->audio_buffer_size/128;
+ PTS = tc->PTS + system_encode->audio_delay + system_encode->startup_delay;
+ DTS = tc->PTS + system_encode->audio_delay + system_encode->startup_delay;
+ }
+ else {
+ buffer_scale = 1;
+ non_scaled_buffer_size = system_encode->video_buffer_size;
+ buffer_size = system_encode->video_buffer_size/1024;
+ PTS = tc->PTS + system_encode->video_delay;
+ DTS = tc->DTS + system_encode->video_delay;
+ }
+
+ total_queued = mpeg1mux_buffer_update_queued(mb, system_encode->SCR);
+
+ if (non_scaled_buffer_size - total_queued >= system_encode->packet_size) {
+
+ /* write the pack/packet here */
+ create_sector (system_encode->sector, pack, sys_header,
+ system_encode->packet_size,
+ MPEG1MUX_BUFFER_DATA(mb), mb->stream_id, buffer_scale,
+ buffer_size, TRUE, PTS, DTS,
+ timestamps, system_encode->which_streams);
+ /* update mta */
+ system_encode->mta = gst_system_encode_update_mta(system_encode, system_encode->mta,
+ system_encode->sector->length_of_packet_data);
+ }
+ else {
+ /* write a padding packet */
+ create_sector (system_encode->sector, pack, sys_header,
+ system_encode->packet_size, NULL, PADDING_STR, 0,
+ 0, FALSE, 0, 0,
+ TIMESTAMPS_NO, system_encode->which_streams);
+ }
+
+ outbuf = gst_buffer_new();
+ GST_BUFFER_DATA(outbuf) = g_malloc(system_encode->sector->length_of_sector);
+ GST_BUFFER_SIZE(outbuf) = system_encode->sector->length_of_sector;
+ memcpy(GST_BUFFER_DATA(outbuf),system_encode->sector->buf, system_encode->sector->length_of_sector);
+ system_encode->bytes_output += GST_BUFFER_SIZE(outbuf);
+ gst_pad_push(system_encode->srcpad,outbuf);
+
+ GST_DEBUG (0,"system_encode::multiplex: writing %02x\n", mb->stream_id);
+
+ }
+ gst_info("system_encode::multiplex: data left in video buffer %lu\n", MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer));
+ gst_info("system_encode::multiplex: data left in audio buffer %lu\n", MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer));
+
+ g_mutex_unlock(system_encode->lock);
+}
+
+static void
+gst_system_encode_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstMPEG1SystemEncode *system_encode;
+ guchar *data;
+ gulong size;
+ const gchar *padname;
+ gint channel;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ system_encode = GST_SYSTEM_ENCODE (GST_OBJECT_PARENT (pad));
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ GST_DEBUG (0,"system_encode::chain: system_encode: have buffer of size %lu\n",size);
+ padname = GST_OBJECT_NAME (pad);
+
+ if (strncmp(padname, "audio_", 6) == 0) {
+ channel = atoi(&padname[6]);
+ GST_DEBUG (0,"gst_system_encode_chain: got audio buffer in from audio channel %02d\n", channel);
+
+ mpeg1mux_buffer_queue(system_encode->audio_buffer, buf);
+ }
+ else if (strncmp(padname, "video_", 6) == 0) {
+ channel = atoi(&padname[6]);
+ GST_DEBUG (0,"gst_system_encode_chain: got video buffer in from video channel %02d\n", channel);
+
+ mpeg1mux_buffer_queue(system_encode->video_buffer, buf);
+
+ }
+ else {
+ g_assert_not_reached ();
+ }
+ gst_system_encode_multiplex(system_encode);
+
+ gst_buffer_unref(buf);
+}
+
+static void
+gst_system_encode_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstMPEG1SystemEncode *system_encode;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SYSTEM_ENCODE(object));
+ system_encode = GST_SYSTEM_ENCODE(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_system_encode_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstMPEG1SystemEncode *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SYSTEM_ENCODE(object));
+ src = GST_SYSTEM_ENCODE(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* this filter needs the getbits functions */
+ if (!gst_library_load("gstgetbits")) {
+ gst_info("system_encode:: could not load support library: 'gstgetbits'\n");
+ return FALSE;
+ }
+
+ /* create an elementfactory for the system_encode element */
+ factory = gst_elementfactory_new("system_encode",GST_TYPE_SYSTEM_ENCODE,
+ &system_encode_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (audio_sink_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (video_sink_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "system_encode",
+ plugin_init
+};
diff --git a/gst/mpeg1sys/gstmpeg1systemencode.h b/gst/mpeg1sys/gstmpeg1systemencode.h
new file mode 100644
index 00000000..bb24f01d
--- /dev/null
+++ b/gst/mpeg1sys/gstmpeg1systemencode.h
@@ -0,0 +1,110 @@
+/* Gnome-Streamer
+ * 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 __SYSTEM_ENCODE_H__
+#define __SYSTEM_ENCODE_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+#include <libs/getbits/gstgetbits.h>
+
+#include "buffer.h"
+#include "main.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_SYSTEM_ENCODE \
+ (gst_mpeg1_system_encode_get_type())
+#define GST_SYSTEM_ENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYSTEM_ENCODE,GstMPEG1SystemEncode))
+#define GST_SYSTEM_ENCODE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYSTEM_ENCODE,GstMPEG1SystemEncode))
+#define GST_IS_SYSTEM_ENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYSTEM_ENCODE))
+#define GST_IS_SYSTEM_ENCODE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYSTEM_ENCODE))
+
+typedef struct _GstMPEG1SystemEncode GstMPEG1SystemEncode;
+typedef struct _GstMPEG1SystemEncodeClass GstMPEG1SystemEncodeClass;
+
+struct _GstMPEG1SystemEncode {
+ GstElement element;
+
+ GstPad *srcpad;
+
+ gboolean have_setup;
+
+ GMutex *lock;
+
+ guint num_audio_pads;
+ guint num_video_pads;
+
+ Mpeg1MuxBuffer *audio_buffer;
+ Mpeg1MuxBuffer *video_buffer;
+
+ Pack_struc *pack;
+ Sys_header_struc *sys_header;
+ Sector_struc *sector;
+
+ guint data_rate, video_rate, audio_rate;
+ gdouble delay, audio_delay, video_delay;
+ gdouble clock_cycles;
+ gulong sectors_delay, video_delay_ms, audio_delay_ms;
+ gulong startup_delay;
+ gulong audio_buffer_size;
+ gulong video_buffer_size;
+ gulong mux_rate, dmux_rate;
+ guint64 SCR;
+ gint which_streams;
+
+ gint current_pack;
+ gulong min_packet_data;
+ gulong max_packet_data;
+ gint packets_per_pack;
+ gulong packet_size;
+ gulong bytes_output;
+
+ GList *mta;
+
+ /* stream input pads */
+ GstPad *private_1_pad[8]; /* up to 8 ac3 audio tracks <grumble> */
+ GstPad *private_2_pad;
+ GstPad *video_pad[16];
+ GstPad *audio_pad[32];
+};
+
+struct _GstMPEG1SystemEncodeClass {
+ GstElementClass parent_class;
+};
+
+GType gst_mpeg1_system_encode_get_type(void);
+
+/* multplex.c */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SYSTEM_ENCODE_H__ */
diff --git a/gst/mpeg1sys/main.h b/gst/mpeg1sys/main.h
new file mode 100644
index 00000000..434f57f5
--- /dev/null
+++ b/gst/mpeg1sys/main.h
@@ -0,0 +1,140 @@
+/*************************************************************************
+* Generating a MPEG/SYSTEMS *
+* MULTIPLEXED VIDEO/AUDIO STREAM *
+* from two MPEG source streams *
+* Christoph Moar *
+* SIEMENS CORPORATE RESEARCH AND DEVELOPMENT ST SN 11 / T SN 6 *
+* (C) 1994 1995 *
+**************************************************************************
+* Restrictions apply. Will not support the whole MPEG/SYSTEM Standard. *
+* Basically, will generate Constrained System Parameter Files. *
+* Mixes only one audio and/or one video stream. Might be expanded. *
+*************************************************************************/
+
+/*************************************************************************
+* mplex - MPEG/SYSTEMS multiplexer *
+* Copyright (C) 1994 1995 Christoph Moar *
+* Siemens ZFE ST SN 11 / T SN 6 *
+* *
+* moar@informatik.tu-muenchen.de *
+* (Christoph Moar) *
+* *
+* 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. *
+*************************************************************************/
+
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <glib.h>
+
+#define PACK_START 0x000001ba
+#define SYS_HEADER_START 0x000001bb
+#define ISO11172_END 0x000001b9
+#define PACKET_START 0x000001
+
+#define CLOCKS 90000.0 /* System Clock Hertz */
+
+#define AFTER_PACKET_LENGTH 15 /* No of non-data-bytes */
+ /* following the packet */
+ /* length field */
+#define LAST_SCR_BYTE_IN_PACK 9 /* No of bytes in pack */
+ /* preceding, and */
+ /* including, the SCR */
+
+/* The following values for sys_header_length & size are only valid for */
+/* System streams consisting of two basic streams. When wrapping around */
+/* the system layer on a single video or a single audio stream, those */
+/* values get decreased by 3. */
+
+#define SYS_HEADER_LENGTH 12 /* length of Sys Header */
+ /* after start code and */
+ /* length field */
+
+#define SYS_HEADER_SIZE 18 /* incl. start code and */
+ /* length field */
+#define PACK_HEADER_SIZE 12
+
+#define PACKET_HEADER_SIZE 6
+
+#define MAX_SECTOR_SIZE 0x20000 /* Max Sektor Groesse */
+
+#define STREAMS_VIDEO 1
+#define STREAMS_AUDIO 2
+#define STREAMS_BOTH 3
+
+#define AUDIO_STREAMS 0xb8 /* Marker Audio Streams */
+#define VIDEO_STREAMS 0xb9 /* Marker Video Streams */
+#define AUDIO_STR_0 0xc0 /* Marker Audio Stream0 */
+#define VIDEO_STR_0 0xe0 /* Marker Video Stream0 */
+#define PADDING_STR 0xbe /* Marker Padding Stream*/
+
+#define ZERO_STUFFING_BYTE 0
+#define STUFFING_BYTE 0xff
+#define RESERVED_BYTE 0xff
+#define TIMESTAMPS_NO 0 /* Flag NO timestamps */
+#define TIMESTAMPS_PTS 1 /* Flag PTS timestamp */
+#define TIMESTAMPS_PTS_DTS 2 /* Flag BOTH timestamps */
+
+#define MARKER_SCR 2 /* Marker SCR */
+#define MARKER_JUST_PTS 2 /* Marker only PTS */
+#define MARKER_PTS 3 /* Marker PTS */
+#define MARKER_DTS 1 /* Marker DTS */
+#define MARKER_NO_TIMESTAMPS 0x0f /* Marker NO timestamps */
+
+#define STATUS_AUDIO_END 0 /* Statusmessage A end */
+#define STATUS_VIDEO_END 1 /* Statusmessage V end */
+#define STATUS_AUDIO_TIME_OUT 2 /* Statusmessage A out */
+#define STATUS_VIDEO_TIME_OUT 3 /* Statusmessage V out */
+
+/*************************************************************************
+ Typ- und Strukturdefinitionen
+*************************************************************************/
+
+typedef struct sector_struc /* A sector, can contain pack, sys header */
+ /* and packet. */
+{ unsigned char buf [MAX_SECTOR_SIZE] ;
+ unsigned int length_of_sector ;
+ unsigned int length_of_packet_data ;
+ guint64 TS ;
+} Sector_struc;
+
+typedef struct pack_struc /* Pack Info */
+{ unsigned char buf [PACK_HEADER_SIZE];
+ guint64 SCR;
+} Pack_struc;
+
+typedef struct sys_header_struc /* System Header Info */
+{ unsigned char buf [SYS_HEADER_SIZE];
+} Sys_header_struc;
+
+/*************************************************************************
+ Funktionsprototypen, keine Argumente, K&R Style
+*************************************************************************/
+
+/* systems.c */
+void create_sector (Sector_struc *sector, Pack_struc *pack, Sys_header_struc *sys_header,
+ unsigned int packet_size, unsigned char *inputbuffer, unsigned char type, unsigned char buffer_scale,
+ unsigned int buffer_size, unsigned char buffers, guint64 PTS, guint64 DTS,
+ unsigned char timestamps, unsigned int which_streams);
+
+void create_pack (Pack_struc *pack, guint64 SCR, unsigned int mux_rate);
+
+void create_sys_header (Sys_header_struc *sys_header, unsigned int rate_bound, unsigned char audio_bound,
+ unsigned char fixed, unsigned char CSPS, unsigned char audio_lock, unsigned char video_lock,
+ unsigned char video_bound, unsigned char stream1, unsigned char buffer1_scale, unsigned int buffer1_size,
+ unsigned char stream2, unsigned char buffer2_scale, unsigned int buffer2_size, unsigned int which_streams);
+
+#endif
diff --git a/gst/mpeg1sys/systems.c b/gst/mpeg1sys/systems.c
new file mode 100644
index 00000000..d0b3388a
--- /dev/null
+++ b/gst/mpeg1sys/systems.c
@@ -0,0 +1,290 @@
+#include <string.h>
+
+#include "main.h"
+
+static void buffer_timecode (timecode, marker, buffer)
+guint64 timecode;
+unsigned char marker;
+unsigned char **buffer;
+
+{
+ unsigned char temp;
+
+ temp = (marker << 4) | ((timecode>>29) & 0x38) |
+ ((timecode >> 29) & 0x6) | 1;
+ *((*buffer)++)=temp;
+ temp = (timecode & 0x3fc00000) >> 22;
+ *((*buffer)++)=temp;
+ temp = ((timecode & 0x003f8000) >> 14) | 1;
+ *((*buffer)++)=temp;
+ temp = (timecode & 0x7f80) >> 7;
+ *((*buffer)++)=temp;
+ temp = ((timecode & 0x007f) << 1) | 1;
+ *((*buffer)++)=temp;
+}
+
+/*************************************************************************
+ creates a complete sector.
+ Also copies Pack and Sys_Header informations into the
+ sector buffer, then reads a packet full of data from
+ the input stream into the sector buffer.
+*************************************************************************/
+
+
+void create_sector (sector, pack, sys_header,
+ packet_size, inputbuffer, type,
+ buffer_scale, buffer_size, buffers,
+ PTS, DTS, timestamps, which_streams )
+
+Sector_struc *sector;
+Pack_struc *pack;
+Sys_header_struc *sys_header;
+unsigned int packet_size;
+unsigned char *inputbuffer;
+
+unsigned char type;
+unsigned char buffer_scale;
+unsigned int buffer_size;
+unsigned char buffers;
+guint64 PTS;
+guint64 DTS;
+unsigned char timestamps;
+unsigned int which_streams;
+
+{
+ int i,j,tmp;
+ unsigned char *index;
+ unsigned char *size_offset;
+
+ /* printf("creating sector\n"); */
+
+ index = sector->buf;
+ sector->length_of_sector=0;
+
+/* Should we copy Pack Header information ? */
+
+ if (pack != NULL)
+ {
+ i = sizeof(pack->buf);
+ bcopy (pack->buf, index, i);
+ index += i;
+ sector->length_of_sector += i;
+ }
+
+/* Should we copy System Header information ? */
+
+ if (sys_header != NULL)
+ {
+ i = sizeof(sys_header->buf);
+
+ /* only one stream? 3 bytes less in sys header */
+ if (which_streams != STREAMS_BOTH) i -= 3;
+
+ bcopy (sys_header->buf, index, i);
+ index += i;
+ sector->length_of_sector += i;
+ }
+
+ /* write constant packet header data */
+
+ *(index++) = (unsigned char)(PACKET_START)>>16;
+ *(index++) = (unsigned char)(PACKET_START & 0x00ffff)>>8;
+ *(index++) = (unsigned char)(PACKET_START & 0x0000ff);
+ *(index++) = type;
+
+ /* we remember this offset in case we will have to shrink this packet */
+
+ size_offset = index;
+ *(index++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)>>8);
+ *(index++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)&0xff);
+
+ *(index++) = STUFFING_BYTE;
+ *(index++) = STUFFING_BYTE;
+ *(index++) = STUFFING_BYTE;
+
+ i = 0;
+
+ if (!buffers) i +=2;
+ if (timestamps == TIMESTAMPS_NO) i+=9;
+ else if (timestamps == TIMESTAMPS_PTS) i+=5;
+
+ /* printf("%i stuffing %d\n", i, timestamps); */
+
+ for (j=0; j<i; j++)
+ *(index++) = STUFFING_BYTE;
+
+ /* should we write buffer info ? */
+
+ if (buffers)
+ {
+ *(index++) = (unsigned char) (0x40 |
+ (buffer_scale << 5) | (buffer_size >> 8));
+ *(index++) = (unsigned char) (buffer_size & 0xff);
+ }
+
+ /* should we write PTS, PTS & DTS or nothing at all ? */
+
+ switch (timestamps)
+ {
+ case TIMESTAMPS_NO:
+ *(index++) = MARKER_NO_TIMESTAMPS;
+ break;
+ case TIMESTAMPS_PTS:
+ buffer_timecode (PTS, MARKER_JUST_PTS, &index);
+ sector->TS = PTS;
+ break;
+ case TIMESTAMPS_PTS_DTS:
+ buffer_timecode (PTS, MARKER_PTS, &index);
+ buffer_timecode (DTS, MARKER_DTS, &index);
+ sector->TS = DTS;
+ break;
+ }
+
+/* read in packet data */
+
+ i = (packet_size - PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH);
+
+ if (type == PADDING_STR)
+ {
+ for (j=0; j<i; j++)
+ *(index++)=(unsigned char) STUFFING_BYTE;
+ tmp = i;
+ }
+ else
+ {
+ /*tmp = fread (index, sizeof (unsigned char), i, inputstream);*/
+ memcpy(index, inputbuffer, i); tmp = i;
+ index += tmp;
+
+ /* if we did not get enough data bytes, shorten the Packet length */
+
+ if (tmp != i)
+ {
+ packet_size -= (i-tmp);
+ *(size_offset++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)>>8);
+ *(size_offset++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)&0xff);
+
+/* zero byte stuffing in the last Packet of a stream */
+/* we don't need this any more, since we shortenend the packet */
+/* for (j=tmp; j<i; j++) */
+/* *(index++)=(unsigned char) ZERO_STUFFING_BYTE; */
+ }
+ }
+
+
+ /* write other struct data */
+
+ sector->length_of_sector += packet_size;
+ sector->length_of_packet_data = tmp;
+
+}
+
+/*************************************************************************
+ writes specifical pack header information into a buffer
+ later this will be copied from the sector routine into
+ the sector buffer
+*************************************************************************/
+
+void create_pack (pack, SCR, mux_rate)
+
+Pack_struc *pack;
+unsigned int mux_rate;
+guint64 SCR;
+
+{
+ unsigned char *index;
+
+ index = pack->buf;
+
+ *(index++) = (unsigned char)((PACK_START)>>24);
+ *(index++) = (unsigned char)((PACK_START & 0x00ff0000)>>16);
+ *(index++) = (unsigned char)((PACK_START & 0x0000ff00)>>8);
+ *(index++) = (unsigned char)(PACK_START & 0x000000ff);
+ buffer_timecode (SCR, MARKER_SCR, &index);
+ *(index++) = (unsigned char)(0x80 | (mux_rate >>15));
+ *(index++) = (unsigned char)(0xff & (mux_rate >> 7));
+ *(index++) = (unsigned char)(0x01 | ((mux_rate & 0x7f)<<1));
+ pack->SCR = SCR;
+}
+
+
+/*************************************************************************
+ writes specifical system header information into a buffer
+ later this will be copied from the sector routine into
+ the sector buffer
+*************************************************************************/
+
+void create_sys_header (sys_header, rate_bound, audio_bound,
+ fixed, CSPS, audio_lock, video_lock,
+ video_bound,
+ stream1, buffer1_scale, buffer1_size,
+ stream2, buffer2_scale, buffer2_size,
+ which_streams)
+
+Sys_header_struc *sys_header;
+unsigned int rate_bound;
+unsigned char audio_bound;
+unsigned char fixed;
+unsigned char CSPS;
+unsigned char audio_lock;
+unsigned char video_lock;
+unsigned char video_bound;
+
+unsigned char stream1;
+unsigned char buffer1_scale;
+unsigned int buffer1_size;
+unsigned char stream2;
+unsigned char buffer2_scale;
+unsigned int buffer2_size;
+unsigned int which_streams;
+
+{
+ unsigned char *index;
+
+ index = sys_header->buf;
+
+ /* if we are not using both streams, we should clear some
+ options here */
+
+ if (!(which_streams & STREAMS_AUDIO))
+ audio_bound = 0;
+ if (!(which_streams & STREAMS_VIDEO))
+ video_bound = 0;
+
+ *(index++) = (unsigned char)((SYS_HEADER_START)>>24);
+ *(index++) = (unsigned char)((SYS_HEADER_START & 0x00ff0000)>>16);
+ *(index++) = (unsigned char)((SYS_HEADER_START & 0x0000ff00)>>8);
+ *(index++) = (unsigned char)(SYS_HEADER_START & 0x000000ff);
+
+ if (which_streams == STREAMS_BOTH) {
+ *(index++) = (unsigned char)(SYS_HEADER_LENGTH >> 8);
+ *(index++) = (unsigned char)(SYS_HEADER_LENGTH & 0xff);
+ } else {
+ *(index++) = (unsigned char)((SYS_HEADER_LENGTH-3) >> 8);
+ *(index++) = (unsigned char)((SYS_HEADER_LENGTH-3) & 0xff);
+ }
+
+ *(index++) = (unsigned char)(0x80 | (rate_bound >>15));
+ *(index++) = (unsigned char)(0xff & (rate_bound >> 7));
+ *(index++) = (unsigned char)(0x01 | ((rate_bound & 0x7f)<<1));
+ *(index++) = (unsigned char)((audio_bound << 2)|(fixed << 1)|CSPS);
+ *(index++) = (unsigned char)((audio_lock << 7)|
+ (video_lock << 6)|0x20|video_bound);
+
+ *(index++) = (unsigned char)RESERVED_BYTE;
+
+ if (which_streams & STREAMS_AUDIO) {
+ *(index++) = stream1;
+ *(index++) = (unsigned char) (0xc0 |
+ (buffer1_scale << 5) | (buffer1_size >> 8));
+ *(index++) = (unsigned char) (buffer1_size & 0xff);
+ }
+
+ if (which_streams & STREAMS_VIDEO) {
+ *(index++) = stream2;
+ *(index++) = (unsigned char) (0xc0 |
+ (buffer2_scale << 5) | (buffer2_size >> 8));
+ *(index++) = (unsigned char) (buffer2_size & 0xff);
+ }
+
+}
diff --git a/gst/mpeg2sub/.gitignore b/gst/mpeg2sub/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/mpeg2sub/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/mpeg2sub/Makefile.am b/gst/mpeg2sub/Makefile.am
new file mode 100644
index 00000000..d8bfe888
--- /dev/null
+++ b/gst/mpeg2sub/Makefile.am
@@ -0,0 +1,18 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstmpeg2subt.la
+
+libgstmpeg2subt_la_SOURCES = gstmpeg2subt.c
+
+if HAVE_CPU_I386
+ARCHCFLAGS = -m486
+else
+ARCHCFLAGS =
+endif
+
+libgstmpeg2subt_la_CFLAGS = -O3 $(ARCHCFLAGS) -fschedule-insns2 $(FOMIT_FRAME_POINTER) -finline-functions -ffast-math $(GST_CFLAGS)
+
+noinst_HEADERS = gstmpeg2subt.h
+
+EXTRA_DIST = Notes.txt
+
diff --git a/gst/mpeg2sub/Notes.txt b/gst/mpeg2sub/Notes.txt
new file mode 100644
index 00000000..a0e56e3c
--- /dev/null
+++ b/gst/mpeg2sub/Notes.txt
@@ -0,0 +1,324 @@
+
+ DVD subtitles
+ ---------------
+
+
+ 0. Introduction
+ 1. Basics
+ 2. The data structure
+ 3. Reading the control header
+ 4. Decoding the graphics
+ 5. What I do not know yet / What I need
+ 6. Thanks
+ 7. Changes
+
+
+
+
+
+The latest version of this document can be found here:
+http://www.via.ecp.fr/~sam/doc/dvd/
+
+
+
+
+
+0. Introduction
+
+ One of the last things we missed in DVD decoding under my system was the
+decoding of subtitles. I found no information on the web or Usenet about them,
+apart from a few words on them being run-length encoded in the DVD FAQ.
+
+ So we decided to reverse-engineer their format (it's completely legal in
+France, since we did it on interoperability purposes), and managed to get
+almost all of it.
+
+
+
+
+
+1. Basics
+
+ DVD subtitles are hidden in private PS packets (0x000001ba), just like AC3
+streams are.
+
+ Within the PS packet, there are PES packets, and like AC3, the header for the
+ones containing subtitles have a 0x000001bd header.
+ As for AC3, where there's an ID like (0x80 + x), there's a subtitle ID equal
+to (0x20 + x), where x is the subtitle ID. Thus there seems to be only
+16 possible different subtitles on a DVD (my Taxi Driver copy has 16).
+
+ I'll suppose you know how to extract AC3 from a DVD, and jump to the
+interesting part of this documentation. Anyway you're unlikely to have
+understood what I said without already being familiar with MPEG2.
+
+
+
+
+
+2. The data structure
+
+A subtitle packet, after its parts have been collected and appended, looks
+like this :
+
+ +----------------------------------------------------------+
+ | |
+ | 0 2 size |
+ | +----+------------------------+-----------------+ |
+ | |size| data packet | control | |
+ | +----+------------------------+-----------------+ |
+ | |
+ | a subtitle packet |
+ | |
+ +----------------------------------------------------------+
+
+size is a 2 bytes word, and data packet and control may have any size.
+
+
+Here is the structure of the data packet :
+
+ +----------------------------------------------------------+
+ | |
+ | 2 4 S0+2 |
+ | +----+------------------------------------------+ |
+ | | S0 | data | |
+ | +----+------------------------------------------+ |
+ | |
+ | the data packet |
+ | |
+ +----------------------------------------------------------+
+
+S0, the data packet size, is a 2 bytes word.
+
+
+Finally, here's the structure of the control packet :
+
+ +----------------------------------------------------------+
+ | |
+ | S0+2 S0+4 S1 size |
+ | +----+---------+---------+--+---------+--+---------+ |
+ | | S1 |ctrl seq |ctrl seq |..|ctrl seq |ff| end seq | |
+ | +----+---------+---------+--+---------+--+---------+ |
+ | |
+ | the control packet |
+ | |
+ +----------------------------------------------------------+
+
+To summarize :
+
+ - S1, at offset S0+2, the position of the end sequence
+ - several control sequences
+ - the 'ff' byte
+ - the end sequence
+
+
+
+
+
+3. Reading the control header
+
+The first thing to read is the control sequences. There are several
+types of them, and each type is determined by its first byte. As far
+as I know, each type has a fixed length.
+
+ * type 0x01 : '01' - 1 byte
+ it seems to be an empty control sequence.
+
+ * type 0x03 : '03wxyz' - 3 bytes
+ this one has the palette information ; it basically says 'encoded color 0
+ is the wth color of the palette, encoded color 1 is the xth color, aso.
+
+ * type 0x04 : '04wxyz' - 3 bytes
+ I *think* this is the alpha channel information ; I only saw values of 0 or f
+ for those nibbles, so I can't really be sure, but it seems plausable.
+
+ * type 0x05 : '05xxxXXXyyyYYY' - 7 bytes
+ the coordinates of the subtitle on the screen :
+ xxx is the first column of the subtitle
+ XXX is the last column of the subtitle
+ yyy is the first line of the subtitle
+ YYY is the last line of the subtitle
+ thus the subtitle's size is (XXX-xxx+1) x (YYY-yyy+1)
+
+ * type 0x06 : '06xxxxyyyy' - 5 bytes
+ xxxx is the position of the first graphic line, and yyyy is the position of
+ the second one (the graphics are interlaced, so it helps a lot :p)
+
+The end sequence has this structure:
+
+ xxxx yyyy 02 ff (ff)
+
+ it ends with 'ff' or 'ffff', to make the whole packet have an even length.
+
+FIXME: I absolutely don't know what xxxx is. I suppose it may be some date
+information since I found it nowhere else, but I can't be sure.
+
+ yyyy is equal to S1 (see picture).
+
+
+Example of a control header :
+----
+0A 0C 01 03 02 31 04 0F F0 05 00 02 CF 00 22 3E 06 00 06 04 E9 FF 00 93 0A 0C 02 FF
+----
+Let's decode it. First of all, S1 = 0x0a0c.
+
+The control sequences are :
+ 01
+ Nothing to say about this one
+ 03 02 31
+ Color 0 is 0, color 1 is 2, color 2 is 3, and color 3 is 1.
+ 04 0F F0
+ Colors 0 and 3 are transparent, and colors 2 and 3 are opaque (not sure of this one)
+ 05 00 02 CF 00 22 3E
+ The first column is 0x000, the last one is 0x2cf, the first line is 0x002, and
+ the last line is 0x23e. Thus the subtitle's size is 0x2d0 x 0x23d.
+ 06 00 06 04 E9
+ The first encoded image starts at offset 0x006, and the second one starts at 0x04e9.
+
+And the end sequence is :
+ 00 93 0A 0C 02 FF
+ Which means... well, not many things now. We can at least verify that S1 (0x0a0c) is
+ there.
+
+
+
+
+
+4. Decoding the graphics
+
+ The graphics are rather easy to decode (at least, when you know how to do it - it
+ took us one whole week to figure out what the encoding was :p).
+
+ The picture is interlaced, for instance for a 40 lines picture :
+
+ line 0 ---------------#----------
+ line 2 ------#-------------------
+ ...
+ line 38 ------------#-------------
+ line 1 ------------------#-------
+ line 3 --------#-----------------
+ ...
+ line 39 -------------#------------
+
+ When decoding you should get:
+
+ line 0 ---------------#----------
+ line 1 ------------------#-------
+ line 2 ------#-------------------
+ line 3 --------#-----------------
+ ...
+ line 38 ------------#-------------
+ line 39 -------------#------------
+
+ Computers with weak processors could choose only to decode even lines
+ in order to gain some time, for instance.
+
+
+ The encoding is run-length encoded, with the following alphabet:
+
+ 0xf
+ 0xe
+ 0xd
+ 0xc
+ 0xb
+ 0xa
+ 0x9
+ 0x8
+ 0x7
+ 0x6
+ 0x5
+ 0x4
+ 0x3-
+ 0x2-
+ 0x1-
+ 0x0f-
+ 0x0e-
+ 0x0d-
+ 0x0c-
+ 0x0b-
+ 0x0a-
+ 0x09-
+ 0x08-
+ 0x07-
+ 0x06-
+ 0x05-
+ 0x04-
+ 0x03--
+ 0x02--
+ 0x01--
+ 0x0000
+
+ '-' stands for any other nibble. Once a sequence X of this alphabet has
+ been read, the pixels can be displayed : (X >> 2) is the number of pixels
+ to display, and (X & 0x3) is the color of the pixel.
+
+ For instance, 0x23 means "8 pixels of color 3".
+
+ "0000" has a special meaning : it's a carriage return. The decoder should
+ do a carriage return when reaching the end of the line, or when encountering
+ this "0000" sequence. When doing a carriage return, the parser should be
+ reset to the next even position (it cannot be nibble-aligned at the start
+ of a line).
+
+ After a carriage return, the parser should read a line on the other
+ interlaced picture, and swap like this after each carriage return.
+
+ Perhaps I don't explain this very well, so you'd better have a look at
+ the enclosed source.
+
+
+
+
+
+5. What I do not know yet / What I need
+
+I don't know what's in the end sequence yet.
+
+Also, I don't know exactly when to display subtitles, and when to remove them.
+
+I don't know if there are other types of control sequences (in my programs I consider
+0xff as a control sequence type, as well as 0x02. I don't know if it's correct or not,
+so please comment on this).
+
+I don't know what the "official" color palette is.
+
+I don't know how to handle transparency information.
+
+I don't know if this document is generic enough.
+
+So what I need is you :
+
+ - if you can, patch this document or my programs to fix strange behaviour with your subtitles.
+
+ - send me your subtitles (there's a program to extract them enclosed) ; the first 10 KB
+ of subtitles in a VOB should be enough, but it would be cool if you sent me one subtitle
+ file per language.
+
+
+
+
+
+6. Thanks
+
+ Thanks to Michel Lespinasse <walken@via.ecp.fr> for his great help on understanding
+the RLE stuff, and for all the ideas he had.
+
+ Thanks to mass (David Waite) and taaz (David I. Lehn) from irc at
+openprojects.net for sending me their subtitles.
+
+
+
+
+
+7. Changes
+
+ 20000116: added the 'changes' section.
+ 20000116: added David Waite's and David I. Lehn's name.
+ 20000116: changed "x0" and "x1" to "S0" and "S1" to make it less confusing.
+
+
+
+
+--
+Paris, January 16th 2000
+Samuel Hocevar <sam@via.ecp.fr>
diff --git a/gst/mpeg2sub/gstmpeg2subt.c b/gst/mpeg2sub/gstmpeg2subt.c
new file mode 100644
index 00000000..ee51d067
--- /dev/null
+++ b/gst/mpeg2sub/gstmpeg2subt.c
@@ -0,0 +1,443 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+
+/*#define DEBUG_ENABLED */
+#include <mpeg2subt.h>
+
+static void gst_mpeg2subt_class_init (GstMpeg2SubtClass *klass);
+static void gst_mpeg2subt_init (GstMpeg2Subt *mpeg2subt);
+
+static void gst_mpeg2subt_chain_video (GstPad *pad,GstBuffer *buf);
+static void gst_mpeg2subt_chain_subtitle (GstPad *pad,GstBuffer *buf);
+
+static void gst_mpeg2subt_merge_title (GstMpeg2Subt *mpeg2subt, GstBuffer *buf);
+
+static void gst_mpeg2subt_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_mpeg2subt_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+/* elementfactory information */
+static GstElementDetails mpeg2subt_details = {
+ "MPEG2 subtitle Decoder",
+ "Filter/Decoder/Video",
+ "Decodes and merges MPEG2 subtitles into a video frame",
+ VERSION,
+ "Samuel Hocevar <sam@via.ecp.fr>\n"
+ "Michel Lespinasse <walken@via.ecp.fr>\n"
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2000",
+};
+
+static GstTypeDefinition mpeg2subtitledefinition = {
+ "mpeg2subt_video/mpeg2ubtitle",
+ "video/mpeg2subtitle",
+ NULL,
+ NULL,
+};
+
+/* GstMpeg2Subt signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_SKIP,
+ /* FILL ME */
+};
+
+static guchar yuv_color[16] = {
+ 0x99,
+ 0x00,
+ 0xFF,
+ 0x00,
+ 0x40,
+ 0x50,
+ 0x60,
+ 0x70,
+ 0x80,
+ 0x90,
+ 0xA0,
+ 0xB0,
+ 0xC0,
+ 0xD0,
+ 0xE0,
+ 0xF0
+};
+
+
+
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_mpeg2subt_signals[LAST_SIGNAL] = { 0 };*/
+
+GType
+gst_mpeg2subt_get_type (void)
+{
+ static GType mpeg2subt_type = 0;
+
+ if (!mpeg2subt_type) {
+ static const GTypeInfo mpeg2subt_info = {
+ sizeof(GstMpeg2SubtClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_mpeg2subt_class_init,
+ NULL,
+ NULL,
+ sizeof(GstMpeg2Subt),
+ 0,
+ (GInstanceInitFunc)gst_mpeg2subt_init,
+ };
+ mpeg2subt_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMpeg2Subt", &mpeg2subt_info, 0);
+ }
+ return mpeg2subt_type;
+}
+
+static void
+gst_mpeg2subt_class_init (GstMpeg2SubtClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SKIP,
+ g_param_spec_int("skip","skip","skip",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); /* CHECKME */
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_mpeg2subt_set_property;
+ gobject_class->get_property = gst_mpeg2subt_get_property;
+
+}
+
+static void
+gst_mpeg2subt_init (GstMpeg2Subt *mpeg2subt)
+{
+ mpeg2subt->videopad = gst_pad_new("video",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(mpeg2subt),mpeg2subt->videopad);
+ gst_pad_set_chain_function(mpeg2subt->videopad,gst_mpeg2subt_chain_video);
+
+ mpeg2subt->subtitlepad = gst_pad_new("subtitle",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(mpeg2subt),mpeg2subt->subtitlepad);
+ gst_pad_set_chain_function(mpeg2subt->subtitlepad,gst_mpeg2subt_chain_subtitle);
+
+ mpeg2subt->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_element_add_pad(GST_ELEMENT(mpeg2subt),mpeg2subt->srcpad);
+
+ mpeg2subt->partialbuf = NULL;
+ mpeg2subt->have_title = FALSE;
+}
+
+static void
+gst_mpeg2subt_chain_video (GstPad *pad, GstBuffer *buf)
+{
+ GstMpeg2Subt *mpeg2subt;
+ guchar *data;
+ glong size;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ mpeg2subt = GST_MPEG2SUBT (GST_OBJECT_PARENT (pad));
+
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ if (mpeg2subt->have_title && mpeg2subt->duration != 0) {
+ gst_mpeg2subt_merge_title(mpeg2subt, buf);
+ mpeg2subt->duration--;
+ }
+
+ gst_pad_push(mpeg2subt->srcpad, buf);
+}
+
+
+static void
+gst_mpeg2subt_parse_header (GstMpeg2Subt *mpeg2subt)
+{
+ guchar *buffer = GST_BUFFER_DATA(mpeg2subt->partialbuf);
+ guchar dummy;
+ guint i;
+
+ i = mpeg2subt->data_size + 4;
+ while (i < mpeg2subt->packet_size)
+ {
+ dummy = buffer [i];
+ switch (dummy)
+ {
+ case 0x01: /* null packet ? */
+ i++;
+ break;
+ case 0x02: /* 02 ff (ff) is the end of the packet */
+ i = mpeg2subt->packet_size;
+ break;
+ case 0x03: /* palette */
+ mpeg2subt->color[0] = yuv_color[buffer [i+1] >> 4];
+ mpeg2subt->color[1] = yuv_color[buffer [i+1] & 0xf];
+ mpeg2subt->color[2] = yuv_color[buffer [i+2] >> 4];
+ mpeg2subt->color[3] = yuv_color[buffer [i+2] & 0xf];
+ mpeg2subt->color[4] = yuv_color[0xf];
+ GST_DEBUG (0,"mpeg2subt: colors %d %d %d %d\n", mpeg2subt->color[0],mpeg2subt->color[1],mpeg2subt->color[2],mpeg2subt->color[3]);
+ i += 3;
+ break;
+ case 0x04: /* transparency palette */
+ mpeg2subt->trans[3] = buffer [i+1] >> 4;
+ mpeg2subt->trans[2] = buffer [i+1] & 0xf;
+ mpeg2subt->trans[1] = buffer [i+2] >> 4;
+ mpeg2subt->trans[0] = buffer [i+2] & 0xf;
+ GST_DEBUG (0,"mpeg2subt: transparency %d %d %d %d\n", mpeg2subt->trans[0],mpeg2subt->trans[1],mpeg2subt->trans[2],mpeg2subt->trans[3]);
+ i += 3;
+ break;
+ case 0x05: /* image coordinates */
+ mpeg2subt->width = 1 + ( ((buffer[i+2] & 0x0f) << 8) + buffer[i+3] )
+ - ( (((unsigned int)buffer[i+1]) << 4) + (buffer[i+2] >> 4) );
+ mpeg2subt->height = 1 + ( ((buffer[i+5] & 0x0f) << 8) + buffer[i+6] )
+ - ( (((unsigned int)buffer[i+4]) << 4) + (buffer[i+5] >> 4) );
+ i += 7;
+ break;
+ case 0x06: /* image 1 / image 2 offsets */
+ mpeg2subt->offset[0] = (((unsigned int)buffer[i+1]) << 8) + buffer[i+2];
+ mpeg2subt->offset[1] = (((unsigned int)buffer[i+3]) << 8) + buffer[i+4];
+ i += 5;
+ break;
+ case 0xff: /* "ff xx yy zz uu" with 'zz uu' == start of control packet
+ * xx and yy are the end time in 90th/sec
+ */
+ mpeg2subt->duration = (((buffer[i+1] << 8) + buffer[i+2]) * 25)/90;
+
+ GST_DEBUG (0,"duration %d\n", mpeg2subt->duration);
+
+ if ( (buffer[i+3] != buffer[mpeg2subt->data_size+2])
+ || (buffer[i+4] != buffer[mpeg2subt->data_size+3]) )
+ {
+ g_print("mpeg2subt: invalid control header (%.2x%.2x != %.2x%.2x) !\n",
+ buffer[i+3], buffer[i+4], buffer[mpeg2subt->data_size+2], buffer[mpeg2subt->data_size+3] );
+/* FIXME */
+/* exit(1); */
+ }
+ i += 5;
+ break;
+ default:
+ g_print("mpeg2subt: invalid sequence in control header (%.2x) !\n", dummy);
+ break;
+ }
+ }
+}
+
+static int
+get_nibble (guchar *buffer, gint *offset, gint id, gint *aligned)
+{
+ static int next;
+
+ if (*aligned)
+ {
+ next = buffer[offset[id]];
+ offset[id]++;
+
+ *aligned = 0;
+ return next >> 4;
+ }
+ else
+ {
+ *aligned = 1;
+ return next & 0xf;
+ }
+}
+
+static void
+gst_mpeg2subt_merge_title (GstMpeg2Subt *mpeg2subt, GstBuffer *buf)
+{
+ gint x=0, y=0;
+ gint width = mpeg2subt->width;
+ gint height = mpeg2subt->height;
+ guchar *buffer = GST_BUFFER_DATA(mpeg2subt->partialbuf);
+ guchar *target = GST_BUFFER_DATA(buf);
+ gint id=0, aligned=1;
+ gint offset[2];
+
+ offset[0] = mpeg2subt->offset[0];
+ offset[1] = mpeg2subt->offset[1];
+#define get_nibble() get_nibble (buffer, offset, id, &aligned)
+
+ GST_DEBUG (0,"mpeg2subt: merging subtitle\n");
+
+ while ((offset[1] < mpeg2subt->data_size + 2) && (y < height))
+ {
+ gint code;
+ gint length, colorid;
+
+ code = get_nibble();
+ if (code >= 0x4) /* 4 .. f */
+ {
+found_code:
+ length = code >> 2;
+ colorid = code & 3;
+ while (length--)
+ if (x++ < width) {
+ if (mpeg2subt->trans[colorid] != 0x0) {
+ *target++ = mpeg2subt->color[colorid];
+ }
+ else target++;
+ }
+
+ if (x >= width)
+ {
+ if (!aligned)
+ get_nibble ();
+ goto next_line;
+ }
+ continue;
+ }
+
+ code = (code << 4) + get_nibble();
+ if (code >= 0x10) /* 1x .. 3x */
+ goto found_code;
+
+ code = (code << 4) + get_nibble();
+ if (code >= 0x40) /* 04x .. 0fx */
+ goto found_code;
+
+ code = (code << 4) + get_nibble();
+ if (code >= 0x100) /* 01xx .. 03xx */
+ goto found_code;
+
+ /* 00xx - should only happen for 00 00 */
+ if (!aligned)
+ code = (code << 4) + get_nibble(); /* 0 0x xx */
+
+ if (code)
+ {
+ g_print("mpeg2subt: got unknown code 00%x (offset %x side %x, x=%d, y=%d)\n", code, mpeg2subt->offset[id], id, x, y);
+ goto next_line;
+ }
+next_line:
+ /* aligned 00 00 */
+ if (y < height) {
+ target+=(width-x);
+ x = 0;
+ y++;
+ id = 1 - id;
+ }
+ }
+}
+
+static void
+gst_mpeg2subt_chain_subtitle (GstPad *pad, GstBuffer *buf)
+{
+ GstMpeg2Subt *mpeg2subt;
+ guchar *data;
+ glong size = 0;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+/* g_return_if_fail(GST_IS_BUFFER(buf)); */
+
+ mpeg2subt = GST_MPEG2SUBT (GST_OBJECT_PARENT (pad));
+
+ if (mpeg2subt->have_title) {
+ gst_buffer_unref(mpeg2subt->partialbuf);
+ mpeg2subt->partialbuf = NULL;
+ mpeg2subt->have_title = FALSE;
+ }
+
+ GST_DEBUG (0,"presentation time %llu\n", GST_BUFFER_TIMESTAMP(buf));
+
+ /* deal with partial frame from previous buffer */
+ if (mpeg2subt->partialbuf) {
+
+ mpeg2subt->partialbuf = gst_buffer_append(mpeg2subt->partialbuf, buf);;
+ /* and the one we received.. */
+ gst_buffer_unref(buf);
+ }
+ else {
+ mpeg2subt->partialbuf = buf;
+ }
+
+ data = GST_BUFFER_DATA(mpeg2subt->partialbuf);
+ size = GST_BUFFER_SIZE(mpeg2subt->partialbuf);
+
+ mpeg2subt->packet_size = GUINT16_FROM_BE(*(guint16 *)data);
+
+ if (mpeg2subt->packet_size == size) {
+
+ GST_DEBUG (0,"mpeg2subt: subtitle packet size %d, current size %ld\n", mpeg2subt->packet_size, size);
+
+ mpeg2subt->data_size = GUINT16_FROM_BE(*(guint16 *)(data+2));
+
+ gst_mpeg2subt_parse_header(mpeg2subt);
+ mpeg2subt->have_title = TRUE;
+ }
+}
+
+static void
+gst_mpeg2subt_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstMpeg2Subt *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_MPEG2SUBT(object));
+ src = GST_MPEG2SUBT(object);
+
+ switch (prop_id) {
+ default:
+ break;
+ }
+}
+
+static void
+gst_mpeg2subt_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstMpeg2Subt *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_MPEG2SUBT(object));
+ src = GST_MPEG2SUBT(object);
+
+ switch (prop_id) {
+ default:
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the mpeg2subt element */
+ factory = gst_elementfactory_new("mpeg2subt",GST_TYPE_MPEG2SUBT,
+ &mpeg2subt_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "mpeg2subt",
+ plugin_init
+};
diff --git a/gst/mpeg2sub/gstmpeg2subt.h b/gst/mpeg2sub/gstmpeg2subt.h
new file mode 100644
index 00000000..71e88909
--- /dev/null
+++ b/gst/mpeg2sub/gstmpeg2subt.h
@@ -0,0 +1,82 @@
+/* Gnome-Streamer
+ * 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_MPEG2SUBT_H__
+#define __GST_MPEG2SUBT_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_MPEG2SUBT \
+ (gst_mpeg2subt_get_type())
+#define GST_MPEG2SUBT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MPEG2SUBT,GstMpeg2Subt))
+#define GST_MPEG2SUBT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MPEG2SUBT,GstMpeg2Subt))
+#define GST_IS_MPEG2SUBT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MPEG2SUBT))
+#define GST_IS_MPEG2SUBT_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MPEG2SUBT))
+
+typedef struct _GstMpeg2Subt GstMpeg2Subt;
+typedef struct _GstMpeg2SubtClass GstMpeg2SubtClass;
+
+struct _GstMpeg2Subt {
+ GstElement element;
+
+ GstPad *videopad,*subtitlepad,*srcpad;
+
+ GstBuffer *partialbuf; /* previous buffer (if carryover) */
+
+ gboolean have_title;
+
+ guint16 packet_size;
+ guint16 data_size;
+
+ gint offset[2];
+ guchar color[5];
+ guchar trans[4];
+
+ guint duration;
+
+ gint width, height;
+
+};
+
+struct _GstMpeg2SubtClass {
+ GstElementClass parent_class;
+};
+
+GType gst_mpeg2subt_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_MPEG2SUBT_H__ */
diff --git a/gst/mpegaudioparse/Makefile.am b/gst/mpegaudioparse/Makefile.am
new file mode 100644
index 00000000..9d670bd3
--- /dev/null
+++ b/gst/mpegaudioparse/Makefile.am
@@ -0,0 +1,16 @@
+#FIXME clean me up a bit
+
+filterdir = $(libdir)/gst
+filter_LTLIBRARIES = libgstmpegaudioparse.la libgstmp3types.la
+
+libgstmpegaudioparse_la_SOURCES = gstmpegaudioparse.c gstmp3types.c
+# FIXME is this useful?
+libgstmpegaudioparse_la_CFLAGS = -O3 $(FOMIT_FRAME_POINTER) -ffast-math -finline-functions $(GST_CFLAGS)
+
+libgstmp3types_la_SOURCES = gstmp3types.c
+libgstmp3types_la_CFLAGS = -O3 $(FOMIT_FRAME_POINTER) -ffast-math -finline-functions $(GST_CFLAGS)
+
+noinst_HEADERS = gstmpegaudioparse.h
+EXTRA_DIST = README
+
+# FIXME is this needed?
diff --git a/gst/mpegaudioparse/README b/gst/mpegaudioparse/README
new file mode 100644
index 00000000..8a803d3e
--- /dev/null
+++ b/gst/mpegaudioparse/README
@@ -0,0 +1,12 @@
+MP3 Audio Parser
+================
+
+This element acts as a parser for mpeg audio data. It's called 'mp3' but
+in reality will work for any MPEG-1, MPEG-2, or MPEG-2.5 elemental audio
+stream of any of Layers I, II, and III. It will not (currently, ever?)
+handle MPEG-2 BC or NBC streams, as those have rather specialized needs
+best served be a different filter.
+
+It will take an mpeg audio stream in any form on its 'src' input, with any
+buffer size, and split it into buffers containing a single frame each.
+NOTE: ancillary data is not dealt with right now.
diff --git a/gst/mpegaudioparse/gstmp3types.c b/gst/mpegaudioparse/gstmp3types.c
new file mode 100644
index 00000000..efb9fd5b
--- /dev/null
+++ b/gst/mpegaudioparse/gstmp3types.c
@@ -0,0 +1,77 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+//#define DEBUG_ENABLED
+#include <gst/gst.h>
+
+static GstCaps* mp3_typefind(GstBuffer *buf, gpointer private);
+
+static GstTypeDefinition mp3type_definitions[] = {
+ { "mp3types_audio/mp3", "audio/mp3", ".mp3 .mp2 .mp1 .mpga", mp3_typefind },
+ { NULL, NULL, NULL, NULL },
+};
+
+static GstCaps*
+mp3_typefind(GstBuffer *buf, gpointer private)
+{
+ gulong head = GULONG_FROM_BE(*((gulong *)GST_BUFFER_DATA(buf)));
+ GstCaps *caps;
+
+ GST_DEBUG (0,"mp3typefind: typefind\n");
+ if ((head & 0xffe00000) != 0xffe00000)
+ return NULL;
+ if (!((head >> 17) & 3))
+ return NULL;
+ if (((head >> 12) & 0xf) == 0xf)
+ return NULL;
+ if (!((head >> 12) & 0xf))
+ return NULL;
+ if (((head >> 10) & 0x3) == 0x3)
+ return NULL;
+
+ caps = gst_caps_new ("mp3_typefind", "audio/mp3", NULL);
+// gst_caps_set(caps,"layer",GST_PROPS_INT(4-((head>>17)&0x3)));
+
+ return caps;
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ gint i=0;
+
+ while (mp3type_definitions[i].name) {
+ GstTypeFactory *type;
+
+ type = gst_typefactory_new (&mp3type_definitions[i]);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
+ i++;
+ }
+
+// gst_info("gsttypes: loaded %d mp3 types\n",i);
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "mp3types",
+ plugin_init
+};
diff --git a/gst/mpegaudioparse/gstmpegaudioparse.c b/gst/mpegaudioparse/gstmpegaudioparse.c
new file mode 100644
index 00000000..b1431c73
--- /dev/null
+++ b/gst/mpegaudioparse/gstmpegaudioparse.c
@@ -0,0 +1,506 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+//#define GST_DEBUG_ENABLED
+#include <gstmpegaudioparse.h>
+
+
+/* elementfactory information */
+static GstElementDetails mp3parse_details = {
+ "MP3 Parser",
+ "Filter/Parser/Audio",
+ "Parses and frames MP3 audio streams, provides seek",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+static GstPadTemplate*
+mp3_src_factory (void)
+{
+ return
+ gst_padtemplate_new (
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ gst_caps_new (
+ "mp3parse_src",
+ "audio/mp3",
+ gst_props_new (
+ "layer", GST_PROPS_INT_RANGE (1, 3),
+ "bitrate", GST_PROPS_INT_RANGE (8, 320),
+ "framed", GST_PROPS_BOOLEAN (TRUE),
+ NULL)),
+ NULL);
+}
+
+static GstPadTemplate*
+mp3_sink_factory (void)
+{
+ return
+ gst_padtemplate_new (
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ gst_caps_new (
+ "mp3parse_sink",
+ "audio/mp3",
+ NULL),
+ NULL);
+};
+
+/* GstMPEGAudioParse signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_SKIP,
+ ARG_BIT_RATE,
+ /* FILL ME */
+};
+
+static GstPadTemplate *sink_temp, *src_temp;
+
+static void gst_mp3parse_class_init (GstMPEGAudioParseClass *klass);
+static void gst_mp3parse_init (GstMPEGAudioParse *mp3parse);
+
+static void gst_mp3parse_loop (GstElement *element);
+static void gst_mp3parse_chain (GstPad *pad,GstBuffer *buf);
+static long bpf_from_header (GstMPEGAudioParse *parse, unsigned long header);
+static int head_check (unsigned long head);
+
+static void gst_mp3parse_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_mp3parse_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_mp3parse_signals[LAST_SIGNAL] = { 0 };
+
+GType
+mp3parse_get_type(void) {
+ static GType mp3parse_type = 0;
+
+ if (!mp3parse_type) {
+ static const GTypeInfo mp3parse_info = {
+ sizeof(GstMPEGAudioParseClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_mp3parse_class_init,
+ NULL,
+ NULL,
+ sizeof(GstMPEGAudioParse),
+ 0,
+ (GInstanceInitFunc)gst_mp3parse_init,
+ };
+ mp3parse_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMPEGAudioParse", &mp3parse_info, 0);
+ }
+ return mp3parse_type;
+}
+
+static void
+gst_mp3parse_class_init (GstMPEGAudioParseClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SKIP,
+ g_param_spec_int("skip","skip","skip",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BIT_RATE,
+ g_param_spec_int("bit_rate","bit_rate","bit_rate",
+ G_MININT,G_MAXINT,0,G_PARAM_READABLE)); // CHECKME
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_mp3parse_set_property;
+ gobject_class->get_property = gst_mp3parse_get_property;
+}
+
+static void
+gst_mp3parse_init (GstMPEGAudioParse *mp3parse)
+{
+ mp3parse->sinkpad = gst_pad_new_from_template(sink_temp, "sink");
+ gst_pad_set_caps(mp3parse->sinkpad, gst_pad_get_padtemplate_caps (mp3parse->sinkpad));
+ gst_element_add_pad(GST_ELEMENT(mp3parse),mp3parse->sinkpad);
+// gst_pad_set_type_id(mp3parse->sinkpad, mp3type);
+
+#if 1 // set this to one to use the old chaining code
+ gst_pad_set_chain_function(mp3parse->sinkpad,gst_mp3parse_chain);
+#else // else you get the new loop-based code, which isn't complete yet
+ gst_element_set_loop_function (GST_ELEMENT(mp3parse),gst_mp3parse_loop);
+#endif
+
+ mp3parse->srcpad = gst_pad_new_from_template(src_temp, "src");
+ gst_element_add_pad(GST_ELEMENT(mp3parse),mp3parse->srcpad);
+ //gst_pad_set_type_id(mp3parse->srcpad, mp3frametype);
+
+ mp3parse->partialbuf = NULL;
+ mp3parse->skip = 0;
+ mp3parse->in_flush = FALSE;
+}
+
+static guint32
+gst_mp3parse_next_header (guchar *buf,guint32 len,guint32 start)
+{
+ guint32 offset = start;
+ int f = 0;
+
+ while (offset < (len - 4)) {
+ fprintf(stderr,"%02x ",buf[offset]);
+ if (buf[offset] == 0xff)
+ f = 1;
+ else if (f && ((buf[offset] >> 4) == 0x0f))
+ return offset - 1;
+ else
+ f = 0;
+ offset++;
+ }
+ return -1;
+}
+
+static void
+gst_mp3parse_loop (GstElement *element)
+{
+ GstMPEGAudioParse *parse = GST_MP3PARSE(element);
+ GstBuffer *inbuf, *outbuf;
+ guint32 size, offset;
+ guchar *data;
+ guint32 start;
+ guint32 header;
+ gint bpf;
+
+ while (1) {
+ // get a new buffer
+ inbuf = gst_pad_pull (parse->sinkpad);
+ size = GST_BUFFER_SIZE (inbuf);
+ data = GST_BUFFER_DATA (inbuf);
+ offset = 0;
+fprintf(stderr, "have buffer of %d bytes\n",size);
+
+ // loop through it and find all the frames
+ while (offset < (size - 4)) {
+ start = gst_mp3parse_next_header (data,size,offset);
+fprintf(stderr, "skipped %d bytes searching for the next header\n",start-offset);
+ header = GULONG_FROM_BE(*((guint32 *)(data+start)));
+fprintf(stderr, "header is 0x%08x\n",header);
+
+ // figure out how big the frame is supposed to be
+ bpf = bpf_from_header (parse, header);
+
+ // see if there are enough bytes in this buffer for the whole frame
+ if ((start + bpf) <= size) {
+ outbuf = gst_buffer_create_sub (inbuf,start,bpf);
+fprintf(stderr, "sending buffer of %d bytes\n",bpf);
+ gst_pad_push (parse->srcpad, outbuf);
+ offset = start + bpf;
+
+ // if not, we have to deal with it somehow
+ } else {
+fprintf(stderr,"don't have enough data for this frame\n");
+
+ break;
+ }
+ }
+ }
+}
+
+static void
+gst_mp3parse_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstMPEGAudioParse *mp3parse;
+ guchar *data;
+ glong size,offset = 0;
+ unsigned long header;
+ int bpf;
+ GstBuffer *outbuf;
+ guint64 last_ts;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+// g_return_if_fail(GST_IS_BUFFER(buf));
+
+ mp3parse = GST_MP3PARSE (gst_pad_get_parent (pad));
+
+ GST_DEBUG (0,"mp3parse: received buffer of %d bytes\n",GST_BUFFER_SIZE(buf));
+
+ last_ts = GST_BUFFER_TIMESTAMP(buf);
+
+ if (GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
+ if (mp3parse->partialbuf) {
+ gst_buffer_unref(mp3parse->partialbuf);
+ mp3parse->partialbuf = NULL;
+ }
+ mp3parse->in_flush = TRUE;
+ }
+
+ // if we have something left from the previous frame
+ if (mp3parse->partialbuf) {
+
+ mp3parse->partialbuf = gst_buffer_append(mp3parse->partialbuf, buf);
+ // and the one we received..
+ gst_buffer_unref(buf);
+ }
+ else {
+ mp3parse->partialbuf = buf;
+ }
+
+ size = GST_BUFFER_SIZE(mp3parse->partialbuf);
+ data = GST_BUFFER_DATA(mp3parse->partialbuf);
+
+ // while we still have bytes left -4 for the header
+ while (offset < size-4) {
+ int skipped = 0;
+
+ GST_DEBUG (0,"mp3parse: offset %ld, size %ld \n",offset, size);
+
+ // search for a possible start byte
+ for (;((data[offset] != 0xff) && (offset < size));offset++) skipped++;
+ if (skipped && !mp3parse->in_flush) {
+ GST_DEBUG (0,"mp3parse: **** now at %ld skipped %d bytes\n",offset,skipped);
+ }
+ // construct the header word
+ header = GULONG_FROM_BE(*((gulong *)(data+offset)));
+ // if it's a valid header, go ahead and send off the frame
+ if (head_check(header)) {
+ // calculate the bpf of the frame
+ bpf = bpf_from_header(mp3parse, header);
+
+ /********************************************************************************
+ * robust seek support
+ * - This performs additional frame validation if the in_flush flag is set
+ * (indicating a discontinuous stream).
+ * - The current frame header is not accepted as valid unless the NEXT frame
+ * header has the same values for most fields. This significantly increases
+ * the probability that we aren't processing random data.
+ * - It is not clear if this is sufficient for robust seeking of Layer III
+ * streams which utilize the concept of a "bit reservoir" by borrow bitrate
+ * from previous frames. In this case, seeking may be more complicated because
+ * the frames are not independently coded.
+ ********************************************************************************/
+ if ( mp3parse->in_flush ) {
+ unsigned long header2;
+
+ if ((size-offset)<(bpf+4)) { if (mp3parse->in_flush) break; } // wait until we have the the entire current frame as well as the next frame header
+
+ header2 = GULONG_FROM_BE(*((gulong *)(data+offset+bpf)));
+ GST_DEBUG(0,"mp3parse: header=%08lX, header2=%08lX, bpf=%d\n", header, header2, bpf );
+
+ #define HDRMASK ~( (0xF<<12)/*bitrate*/ | (1<<9)/*padding*/ | (3<<4)/*mode extension*/ ) // mask the bits which are allowed to differ between frames
+
+ if ( (header2&HDRMASK) != (header&HDRMASK) ) { // require 2 matching headers in a row
+ GST_DEBUG(0,"mp3parse: next header doesn't match (header=%08lX, header2=%08lX, bpf=%d)\n", header, header2, bpf );
+ offset++; // This frame is invalid. Start looking for a valid frame at the next position in the stream
+ continue;
+ }
+
+ }
+
+ // if we don't have the whole frame...
+ if ((size - offset) < bpf) {
+ GST_DEBUG (0,"mp3parse: partial buffer needed %ld < %d \n",(size-offset), bpf);
+ break;
+ } else {
+
+ outbuf = gst_buffer_create_sub(mp3parse->partialbuf,offset,bpf);
+
+ offset += bpf;
+ if (mp3parse->skip == 0) {
+ GST_DEBUG (0,"mp3parse: pushing buffer of %d bytes\n",GST_BUFFER_SIZE(outbuf));
+ if (mp3parse->in_flush) {
+ GST_BUFFER_FLAG_SET(outbuf, GST_BUFFER_FLUSH);
+ mp3parse->in_flush = FALSE;
+ }
+ else {
+ GST_BUFFER_FLAG_UNSET(outbuf, GST_BUFFER_FLUSH);
+ }
+ GST_BUFFER_TIMESTAMP(outbuf) = last_ts;
+ gst_pad_push(mp3parse->srcpad,outbuf);
+ }
+ else {
+ GST_DEBUG (0,"mp3parse: skipping buffer of %d bytes\n",GST_BUFFER_SIZE(outbuf));
+ gst_buffer_unref(outbuf);
+ mp3parse->skip--;
+ }
+ }
+ } else {
+ offset++;
+ if (!mp3parse->in_flush) GST_DEBUG (0,"mp3parse: *** wrong header, skipping byte (FIXME?)\n");
+ }
+ }
+ // if we have processed this block and there are still
+ // bytes left not in a partial block, copy them over.
+ if (size-offset > 0) {
+ glong remainder = (size - offset);
+ GST_DEBUG (0,"mp3parse: partial buffer needed %ld for trailing bytes\n",remainder);
+
+ outbuf = gst_buffer_create_sub(mp3parse->partialbuf,offset,remainder);
+ gst_buffer_unref(mp3parse->partialbuf);
+ mp3parse->partialbuf = outbuf;
+ }
+ else {
+ gst_buffer_unref(mp3parse->partialbuf);
+ mp3parse->partialbuf = NULL;
+ }
+}
+
+static int mp3parse_tabsel[2][3][16] =
+{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, },
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, },
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } },
+ { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } },
+};
+
+static long mp3parse_freqs[9] =
+{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
+
+
+static long
+bpf_from_header (GstMPEGAudioParse *parse, unsigned long header)
+{
+ int layer_index,layer,lsf,samplerate_index,padding;
+ long bpf;
+
+ //mpegver = (header >> 19) & 0x3; // don't need this for bpf
+ layer_index = (header >> 17) & 0x3;
+ layer = 4 - layer_index;
+ lsf = (header & (1 << 20)) ? ((header & (1 << 19)) ? 0 : 1) : 1;
+ parse->bit_rate = mp3parse_tabsel[lsf][layer - 1][((header >> 12) & 0xf)];
+ samplerate_index = (header >> 10) & 0x3;
+ padding = (header >> 9) & 0x1;
+
+ if (layer == 1) {
+ bpf = parse->bit_rate * 12000;
+ bpf /= mp3parse_freqs[samplerate_index];
+ bpf = ((bpf + padding) << 2);
+ } else {
+ bpf = parse->bit_rate * 144000;
+ bpf /= mp3parse_freqs[samplerate_index];
+ bpf += padding;
+ }
+
+ //g_print("%08x: layer %d lsf %d bitrate %d samplerate_index %d padding %d - bpf %d\n",
+//header,layer,lsf,bitrate,samplerate_index,padding,bpf);
+
+ return bpf;
+}
+
+static gboolean
+head_check (unsigned long head)
+{
+ GST_DEBUG (0,"checking mp3 header 0x%08lx\n",head);
+ /* if it's not a valid sync */
+ if ((head & 0xffe00000) != 0xffe00000) {
+ GST_DEBUG (0,"invalid sync\n");return FALSE; }
+ /* if it's an invalid MPEG version */
+ if (((head >> 19) & 3) == 0x1) {
+ GST_DEBUG (0,"invalid MPEG version\n");return FALSE; }
+ /* if it's an invalid layer */
+ if (!((head >> 17) & 3)) {
+ GST_DEBUG (0,"invalid layer\n");return FALSE; }
+ /* if it's an invalid bitrate */
+ if (((head >> 12) & 0xf) == 0x0) {
+ GST_DEBUG (0,"invalid bitrate\n");return FALSE; }
+ if (((head >> 12) & 0xf) == 0xf) {
+ GST_DEBUG (0,"invalid bitrate\n");return FALSE; }
+ /* if it's an invalid samplerate */
+ if (((head >> 10) & 0x3) == 0x3) {
+ GST_DEBUG (0,"invalid samplerate\n");return FALSE; }
+ if ((head & 0xffff0000) == 0xfffe0000) {
+ GST_DEBUG (0,"invalid sync\n");return FALSE; }
+ if (head & 0x00000002) {
+ GST_DEBUG (0,"invalid emphasis\n");return FALSE; }
+
+ return TRUE;
+}
+
+static void
+gst_mp3parse_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstMPEGAudioParse *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_MP3PARSE(object));
+ src = GST_MP3PARSE(object);
+
+ switch (prop_id) {
+ case ARG_SKIP:
+ src->skip = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_mp3parse_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstMPEGAudioParse *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_MP3PARSE(object));
+ src = GST_MP3PARSE(object);
+
+ switch (prop_id) {
+ case ARG_SKIP:
+ g_value_set_int (value, src->skip);
+ break;
+ case ARG_BIT_RATE:
+ g_value_set_int (value, src->bit_rate * 1000);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the mp3parse element */
+ factory = gst_elementfactory_new ("mp3parse",
+ GST_TYPE_MP3PARSE,
+ &mp3parse_details);
+ g_return_val_if_fail (factory != NULL, FALSE);
+
+ sink_temp = mp3_sink_factory ();
+ gst_elementfactory_add_padtemplate (factory, sink_temp);
+
+ src_temp = mp3_src_factory ();
+ gst_elementfactory_add_padtemplate (factory, src_temp);
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "mp3parse",
+ plugin_init
+};
diff --git a/gst/mpegaudioparse/gstmpegaudioparse.h b/gst/mpegaudioparse/gstmpegaudioparse.h
new file mode 100644
index 00000000..fbd1047e
--- /dev/null
+++ b/gst/mpegaudioparse/gstmpegaudioparse.h
@@ -0,0 +1,71 @@
+/* Gnome-Streamer
+ * 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 __MP3PARSE_H__
+#define __MP3PARSE_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_MP3PARSE \
+ (gst_mp3parse_get_type())
+#define GST_MP3PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MP3PARSE,GstMPEGAudioParse))
+#define GST_MP3PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MP3PARSE,GstMPEGAudioParse))
+#define GST_IS_MP3PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MP3PARSE))
+#define GST_IS_MP3PARSE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MP3PARSE))
+
+typedef struct _GstMPEGAudioParse GstMPEGAudioParse;
+typedef struct _GstMPEGAudioParseClass GstMPEGAudioParseClass;
+
+struct _GstMPEGAudioParse {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ GstBuffer *partialbuf; // previous buffer (if carryover)
+ guint skip; /* number of frames to skip */
+ guint bit_rate;
+ gboolean in_flush;
+};
+
+struct _GstMPEGAudioParseClass {
+ GstElementClass parent_class;
+};
+
+GType gst_mp3parse_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __MP3PARSE_H__ */
diff --git a/gst/passthrough/.gitignore b/gst/passthrough/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/passthrough/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/passthrough/Makefile.am b/gst/passthrough/Makefile.am
new file mode 100644
index 00000000..500d4679
--- /dev/null
+++ b/gst/passthrough/Makefile.am
@@ -0,0 +1,10 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstpassthrough.la
+
+libgstpassthrough_la_SOURCES = gstpassthrough.c
+libgstpassthrough_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstpassthrough.h filter.func
+
+EXTRA_DIST =
diff --git a/gst/passthrough/filter.func b/gst/passthrough/filter.func
new file mode 100644
index 00000000..99a9308b
--- /dev/null
+++ b/gst/passthrough/filter.func
@@ -0,0 +1,18 @@
+{
+ guint j;
+ static long int sample = 0; /* you can use this to count samples */
+
+ /*
+ * process data here
+ * *data contains the original 8 or 16 bit samples and is modified in place
+ * channels are interleaved in input data
+ */
+
+ /* do nothing */
+
+ for (j = 0; j < num_samples; j++)
+ {
+ data[j] = data[j];
+ }
+ sample += num_samples;
+}
diff --git a/gst/passthrough/gstpassthrough.c b/gst/passthrough/gstpassthrough.c
new file mode 100644
index 00000000..dc50e626
--- /dev/null
+++ b/gst/passthrough/gstpassthrough.c
@@ -0,0 +1,351 @@
+/* -*- c-basic-offset: 2 -*-
+ * GStreamer
+ * Copyright (C) 1999-2001 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.
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+#include <libs/audio/gstaudio.h>
+#include "gstpassthrough.h"
+
+
+
+static GstElementDetails passthrough_details = {
+ "Passthrough",
+ "Filter/Effect",
+ "Transparent filter for audio/raw (boilerplate for effects)",
+ VERSION,
+ "Thomas <thomas@apestaart.org>, "\
+ "Andy Wingo <apwingo@eos.ncsu.edu>",
+ "(C) 2001",
+};
+
+
+/* Filter signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_SILENT
+};
+
+static GstPadTemplate*
+passthrough_sink_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template) {
+ template = gst_padtemplate_new
+ ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ gst_caps_append(gst_caps_new ("sink_int", "audio/raw",
+ GST_AUDIO_INT_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("sink_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS)),
+ NULL);
+ }
+ return template;
+}
+
+static GstPadTemplate*
+passthrough_src_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template)
+ template = gst_padtemplate_new
+ ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ gst_caps_append (gst_caps_new ("src_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("src_int", "audio/raw",
+ GST_AUDIO_INT_PAD_TEMPLATE_PROPS)),
+ NULL);
+
+ return template;
+}
+
+static void passthrough_class_init (GstPassthroughClass *klass);
+static void passthrough_init (GstPassthrough *filter);
+
+static void passthrough_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void passthrough_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static gint passthrough_parse_caps (GstPassthrough *filter, GstCaps *caps);
+
+static void passthrough_chain (GstPad *pad, GstBuffer *buf);
+static void inline passthrough_fast_float_chain (gfloat* data, guint numsamples);
+static void inline passthrough_fast_16bit_chain (gint16* data, guint numsamples);
+static void inline passthrough_fast_8bit_chain (gint8* data, guint numsamples);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
+
+static GstBufferPool*
+passthrough_get_bufferpool (GstPad *pad)
+{
+ GstPassthrough *filter;
+
+ filter = GST_PASSTHROUGH (gst_pad_get_parent (pad));
+
+ return gst_pad_get_bufferpool (filter->srcpad);
+}
+
+static GstPadNegotiateReturn
+passthrough_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstPassthrough* filter = GST_PASSTHROUGH (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (passthrough_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->sinkpad,caps);
+}
+
+static GstPadNegotiateReturn
+passthrough_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstPassthrough* filter = GST_PASSTHROUGH (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (passthrough_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->srcpad,caps);
+}
+
+static gint
+passthrough_parse_caps (GstPassthrough *filter, GstCaps *caps)
+{
+ const gchar *format;
+
+ g_return_val_if_fail(filter!=NULL,-1);
+ g_return_val_if_fail(caps!=NULL,-1);
+
+ format = gst_caps_get_string(caps, "format");
+
+ filter->rate = gst_caps_get_int (caps, "rate");
+ filter->channels = gst_caps_get_int (caps, "channels");
+
+ if (strcmp(format, "int")==0) {
+ filter->format = GST_PASSTHROUGH_FORMAT_INT;
+ filter->width = gst_caps_get_int (caps, "width");
+ filter->depth = gst_caps_get_int (caps, "depth");
+ filter->law = gst_caps_get_int (caps, "law");
+ filter->endianness = gst_caps_get_int (caps, "endianness");
+ filter->is_signed = gst_caps_get_int (caps, "signed");
+ if (!filter->silent) {
+ g_print ("Passthrough : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("Passthrough : format int, bit width %d, endianness %d, signed %s\n",
+ filter->width, filter->endianness, filter->is_signed ? "yes" : "no");
+ }
+ } else if (strcmp(format, "float")==0) {
+ filter->format = GST_PASSTHROUGH_FORMAT_FLOAT;
+ filter->layout = gst_caps_get_string(caps, "layout");
+ filter->intercept = gst_caps_get_float(caps, "intercept");
+ filter->slope = gst_caps_get_float(caps, "slope");
+ if (!filter->silent) {
+ g_print ("Passthrough : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("Passthrough : format float, layout %s, intercept %f, slope %f\n",
+ filter->layout, filter->intercept, filter->slope);
+ }
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+GType
+gst_passthrough_get_type(void) {
+ static GType passthrough_type = 0;
+
+ if (!passthrough_type) {
+ static const GTypeInfo passthrough_info = {
+ sizeof(GstPassthroughClass), NULL,
+ NULL,
+ (GClassInitFunc)passthrough_class_init,
+ NULL,
+ NULL,
+ sizeof(GstPassthrough),
+ 0,
+ (GInstanceInitFunc)passthrough_init,
+ };
+ passthrough_type = g_type_register_static(GST_TYPE_ELEMENT, "GstPassthrough", &passthrough_info, 0);
+ }
+ return passthrough_type;
+}
+
+static void
+passthrough_class_init (GstPassthroughClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SILENT,
+ g_param_spec_boolean("silent","silent","silent",
+ TRUE,G_PARAM_READWRITE)); // CHECKME
+
+ gobject_class->set_property = passthrough_set_property;
+ gobject_class->get_property = passthrough_get_property;
+}
+
+static void
+passthrough_init (GstPassthrough *filter)
+{
+ filter->sinkpad = gst_pad_new_from_template(passthrough_sink_factory (),"sink");
+ gst_pad_set_negotiate_function(filter->sinkpad,passthrough_negotiate_sink);
+ gst_pad_set_bufferpool_function(filter->sinkpad,passthrough_get_bufferpool);
+ filter->srcpad = gst_pad_new_from_template(passthrough_src_factory (),"src");
+ gst_pad_set_negotiate_function(filter->srcpad,passthrough_negotiate_src);
+
+ gst_element_add_pad(GST_ELEMENT(filter),filter->sinkpad);
+ gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
+ gst_pad_set_chain_function(filter->sinkpad,passthrough_chain);
+ filter->silent = FALSE;
+}
+
+static void
+passthrough_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstPassthrough *filter;
+ gint16 *int_data;
+ gfloat *float_data;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ filter = GST_PASSTHROUGH(GST_OBJECT_PARENT (pad));
+ g_return_if_fail(filter != NULL);
+ g_return_if_fail(GST_IS_PASSTHROUGH(filter));
+
+ switch (filter->format) {
+ case GST_PASSTHROUGH_FORMAT_INT:
+ int_data = (gint16 *)GST_BUFFER_DATA(buf);
+
+ switch (filter->width) {
+ case 16:
+ passthrough_fast_16bit_chain(int_data,GST_BUFFER_SIZE(buf)/2);
+ break;
+ case 8:
+ passthrough_fast_8bit_chain((gint8*)int_data,GST_BUFFER_SIZE(buf));
+ break;
+ }
+
+ break;
+ case GST_PASSTHROUGH_FORMAT_FLOAT:
+ float_data = (gfloat *)GST_BUFFER_DATA(buf);
+
+ passthrough_fast_float_chain(float_data,GST_BUFFER_SIZE(buf)/sizeof(float));
+
+ break;
+ }
+
+ gst_pad_push(filter->srcpad,buf);
+}
+
+static void inline
+passthrough_fast_float_chain(gfloat* data,
+ guint num_samples)
+#include "filter.func"
+
+static void inline
+passthrough_fast_16bit_chain(gint16* data,
+ guint num_samples)
+#include "filter.func"
+
+static void inline
+passthrough_fast_8bit_chain(gint8* data,
+ guint num_samples)
+#include "filter.func"
+
+static void
+passthrough_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstPassthrough *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_PASSTHROUGH(object));
+ filter = GST_PASSTHROUGH(object);
+
+ switch (prop_id)
+ {
+ case ARG_SILENT:
+ filter->silent = g_value_get_boolean (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+passthrough_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstPassthrough *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_PASSTHROUGH(object));
+ filter = GST_PASSTHROUGH(object);
+
+ switch (prop_id) {
+ case ARG_SILENT:
+ g_value_set_boolean (value, filter->silent);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("passthrough",GST_TYPE_PASSTHROUGH,
+ &passthrough_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, passthrough_src_factory ());
+ gst_elementfactory_add_padtemplate (factory, passthrough_sink_factory ());
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "passthrough",
+ plugin_init
+};
diff --git a/gst/passthrough/gstpassthrough.h b/gst/passthrough/gstpassthrough.h
new file mode 100644
index 00000000..d8c2f63e
--- /dev/null
+++ b/gst/passthrough/gstpassthrough.h
@@ -0,0 +1,103 @@
+/* -*- c-basic-offset: 2 -*-
+ * 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_PASSTHROUGH_H__
+#define __GST_PASSTHROUGH_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+// #include <gst/meta/audioraw.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_PASSTHROUGH \
+ (gst_passthrough_get_type())
+#define GST_PASSTHROUGH(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PASSTHROUGH,GstPassthrough))
+#define GST_PASSTHROUGH_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstPassthrough))
+#define GST_IS_PASSTHROUGH(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PASSTHROUGH))
+#define GST_IS_PASSTHROUGH_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PASSTHROUGH))
+
+typedef struct _GstPassthrough GstPassthrough;
+typedef struct _GstPassthroughClass GstPassthroughClass;
+typedef enum _GstPassthroughFormat GstPassthroughFormat;
+
+enum _GstPassthroughFormat {
+ GST_PASSTHROUGH_FORMAT_INT,
+ GST_PASSTHROUGH_FORMAT_FLOAT
+};
+
+struct _GstPassthrough {
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ gboolean silent;
+
+ /* the next three are valid for both int and float */
+
+ GstPassthroughFormat format;
+
+ guint rate;
+
+ guint channels;
+
+ /* the next five are valid only for format==GST_PASSTHROUGH_FORMAT_INT */
+
+ guint width;
+
+ guint depth;
+
+ guint endianness;
+
+ guint law;
+
+ gboolean is_signed;
+
+ /* the next three are valid only for format==GST_PASSTHROUGH_FORMAT_FLOAT */
+
+ const gchar *layout;
+
+ gfloat slope;
+
+ gfloat intercept;
+};
+
+struct _GstPassthroughClass {
+ GstElementClass parent_class;
+};
+
+GType gst_passthrough_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PASSTHROUGH_H__ */
diff --git a/gst/playondemand/Makefile.am b/gst/playondemand/Makefile.am
new file mode 100644
index 00000000..fc2b93b9
--- /dev/null
+++ b/gst/playondemand/Makefile.am
@@ -0,0 +1,10 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstplayondemand.la
+
+libgstplayondemand_la_SOURCES = gstplayondemand.c
+libgstplayondemand_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstplayondemand.h filter.func
+
+# EXTRA_DIST = README
diff --git a/gst/playondemand/filter.func b/gst/playondemand/filter.func
new file mode 100644
index 00000000..6f81c975
--- /dev/null
+++ b/gst/playondemand/filter.func
@@ -0,0 +1,120 @@
+/* -*- C -*- */
+
+_TYPE_ *data_in, *data_out, *filter_data;
+
+filter_data = (_TYPE_ *) filter->buffer;
+num_filter = filter->buffer_size / sizeof(_TYPE_);
+
+/******************************************************************************/
+/* see if we've got any events coming through ... */
+
+do {
+ GST_DEBUG(0, "--- going to events\n");
+
+ while (! filter->eos && GST_IS_EVENT(in)) {
+ if (GST_EVENT_TYPE(in) == GST_EVENT_EOS) {
+ filter->eos = TRUE;
+ } else {
+ gst_pad_push(filter->srcpad, in);
+ }
+
+ in = gst_pad_pull(filter->sinkpad);
+ }
+
+ /******************************************************************************/
+ /* first handle data from the input buffer. */
+
+ GST_DEBUG(0, "--- done with events, going to input\n");
+
+ /* only update the input if there hasn't been an eos yet. */
+ if (! filter->eos) {
+ data_in = (_TYPE_ *) GST_BUFFER_DATA(in);
+ num_in = GST_BUFFER_SIZE(in) / sizeof(_TYPE_);
+
+ w = filter->write;
+
+ /* copy the input data to the filter's internal buffer. */
+ if (filter->follow_stream_tail) {
+ for (j = 0; j < num_in; j++) {
+ filter_data[(w + j) % num_filter] = data_in[j];
+ }
+
+ filter->write = (w + j) % num_filter;
+
+ /* update the start pointer */
+ if ((filter->start != 0) || ((w + j) >= num_filter)) {
+ filter->start = (filter->write + 1) % num_filter;
+ }
+ } else {
+ for (j = 0; (j < num_in) && ((w + j) < num_filter); j++) {
+ filter_data[w + j] = data_in[j];
+ }
+
+ filter->write += j;
+
+ /* if we're not following the stream tail, the buffer is just a straight
+ buffer. so we need to set eos if we've passed the limit of the internal
+ buffer size. */
+ if ((w + j) >= num_filter) {
+ filter->eos = TRUE;
+ }
+ }
+
+ out = in;
+ } else {
+ j = 0;
+
+ if (filter->srcpool) {
+ out = gst_buffer_new_from_pool(filter->srcpool, 0, 0);
+ } else {
+ out = gst_buffer_new();
+
+ GST_BUFFER_DATA(out) = (gchar *) g_new(_TYPE_, POD_GSTBUFSIZE / sizeof(_TYPE_));
+ GST_BUFFER_SIZE(out) = POD_GSTBUFSIZE;
+ }
+ }
+
+ /******************************************************************************/
+ /* now handle output data. */
+
+ GST_DEBUG(0, "--- done with input, going to output\n");
+
+ data_out = (_TYPE_ *) GST_BUFFER_DATA(out);
+ num_out = GST_BUFFER_SIZE(out) / sizeof(_TYPE_);
+
+ for (k = 0; k < num_out; k++) {
+ data_out[k] = zero;
+ }
+
+ /* output play pointer data. */
+ for (t = 0; t < POD_MAX_PLAYS; t++) {
+ offset = filter->plays[t];
+
+ if (offset != G_MAXUINT) {
+ if (filter->follow_stream_tail) {
+ for (k = 0; k < num_out; k++) {
+ data_out[k] = CLAMP(data_out[k] + filter_data[(offset + k) % num_filter], min, max);
+ }
+ } else {
+ for (k = 0; (k < num_out) && ((offset + k) < (w + j)); k++) {
+ data_out[k] = CLAMP(data_out[k] + filter_data[offset + k], min, max);
+ }
+ }
+
+ if ((offset < w) && ((offset + k) >= (w + j))) {
+ filter->plays[t] = G_MAXUINT;
+ } else {
+ filter->plays[t] = (filter->plays[t] + k) % num_filter;
+ }
+ }
+ }
+
+ GST_DEBUG(0, "--- done with output, pushing buffer %p\n", out);
+
+ gst_pad_push(filter->srcpad, out);
+
+ if (! filter->eos) {
+ in = gst_pad_pull(filter->sinkpad);
+ }
+
+} while (! GST_ELEMENT_IS_COTHREAD_STOPPING(elem));
diff --git a/gst/playondemand/gstplayondemand.c b/gst/playondemand/gstplayondemand.c
new file mode 100644
index 00000000..9d2ebff3
--- /dev/null
+++ b/gst/playondemand/gstplayondemand.c
@@ -0,0 +1,448 @@
+/* GStreamer
+ * Copyright (C) 1999-2001 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.
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+#include <libs/audio/gstaudio.h>
+#include "gstplayondemand.h"
+
+
+#define POD_MAX_PLAYS 192 /* maximum number of simultaneous plays */
+#define POD_GSTBUFSIZE 4096 /* gstreamer buffer size to make if no
+ bufferpool is available, must be divisible
+ by sizeof(gfloat) */
+#define POD_BUFSPERCHUNK 6 /* number of buffers to allocate per chunk in
+ sink buffer pool */
+#define POD_BUFFER_SIZE 882000 /* enough space for 10 seconds of 16-bit audio
+ at 44100 samples per second ... */
+
+static GstElementDetails play_on_demand_details = {
+ "Play On Demand",
+ "Filter/Effect",
+ "Plays a stream whenever it receives a certain signal",
+ VERSION,
+ "Leif Morgan Johnson <lmjohns3@eos.ncsu.edu>",
+ "(C) 2001",
+};
+
+
+/* Filter signals and args */
+enum {
+ /* FILL ME */
+ PLAY_SIGNAL,
+ RESET_SIGNAL,
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_SILENT,
+ ARG_FOLLOWTAIL,
+ ARG_BUFFERSIZE
+};
+
+static GstPadTemplate*
+play_on_demand_sink_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template) {
+ template = gst_padtemplate_new
+ ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ gst_caps_append(gst_caps_new ("sink_int", "audio/raw",
+ GST_AUDIO_INT_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("sink_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS)),
+ NULL);
+ }
+ return template;
+}
+
+static GstPadTemplate*
+play_on_demand_src_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template)
+ template = gst_padtemplate_new
+ ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ gst_caps_append (gst_caps_new ("src_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("src_int", "audio/raw",
+ GST_AUDIO_INT_PAD_TEMPLATE_PROPS)),
+ NULL);
+
+ return template;
+}
+
+static void play_on_demand_class_init (GstPlayOnDemandClass *klass);
+static void play_on_demand_init (GstPlayOnDemand *filter);
+
+static void play_on_demand_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void play_on_demand_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static gint play_on_demand_parse_caps (GstPlayOnDemand *filter, GstCaps *caps);
+
+static void play_on_demand_loop (GstElement *elem);
+
+static void play_on_demand_play_handler (GstElement *elem);
+static void play_on_demand_reset_handler (GstElement *elem);
+
+static GstElementClass *parent_class = NULL;
+static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 };
+
+static GstBufferPool*
+play_on_demand_get_bufferpool (GstPad *pad)
+{
+ GstPlayOnDemand *filter;
+
+ filter = GST_PLAYONDEMAND(gst_pad_get_parent(pad));
+
+ return gst_pad_get_bufferpool(filter->srcpad);
+}
+
+static GstPadNegotiateReturn
+play_on_demand_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstPlayOnDemand* filter = GST_PLAYONDEMAND(gst_pad_get_parent(pad));
+
+ if (*caps == NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (play_on_demand_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad, filter->sinkpad, caps);
+}
+
+static GstPadNegotiateReturn
+play_on_demand_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstPlayOnDemand* filter = GST_PLAYONDEMAND(gst_pad_get_parent(pad));
+
+ if (*caps == NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (play_on_demand_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad, filter->srcpad, caps);
+}
+
+static gint
+play_on_demand_parse_caps (GstPlayOnDemand *filter, GstCaps *caps)
+{
+ const gchar *format;
+
+ g_return_val_if_fail(filter != NULL, -1);
+ g_return_val_if_fail(caps != NULL, -1);
+
+ format = gst_caps_get_string(caps, "format");
+
+ filter->rate = gst_caps_get_int(caps, "rate");
+ filter->channels = gst_caps_get_int(caps, "channels");
+
+ if (strcmp(format, "int") == 0) {
+ filter->format = GST_PLAYONDEMAND_FORMAT_INT;
+ filter->width = gst_caps_get_int(caps, "width");
+ filter->depth = gst_caps_get_int(caps, "depth");
+ filter->law = gst_caps_get_int(caps, "law");
+ filter->endianness = gst_caps_get_int(caps, "endianness");
+ filter->is_signed = gst_caps_get_int(caps, "signed");
+ if (!filter->silent) {
+ g_print ("PlayOnDemand : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("PlayOnDemand : format int, bit width %d, endianness %d, signed %s\n",
+ filter->width, filter->endianness, filter->is_signed ? "yes" : "no");
+ }
+ } else if (strcmp(format, "float")==0) {
+ filter->format = GST_PLAYONDEMAND_FORMAT_FLOAT;
+ filter->layout = gst_caps_get_string(caps, "layout");
+ filter->intercept = gst_caps_get_float(caps, "intercept");
+ filter->slope = gst_caps_get_float(caps, "slope");
+ if (!filter->silent) {
+ g_print ("PlayOnDemand : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("PlayOnDemand : format float, layout %s, intercept %f, slope %f\n",
+ filter->layout, filter->intercept, filter->slope);
+ }
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+GType
+gst_play_on_demand_get_type(void) {
+ static GType play_on_demand_type = 0;
+
+ if (! play_on_demand_type) {
+ static const GTypeInfo play_on_demand_info = {
+ sizeof(GstPlayOnDemandClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) play_on_demand_class_init,
+ NULL,
+ NULL,
+ sizeof(GstPlayOnDemand),
+ 0,
+ (GInstanceInitFunc) play_on_demand_init,
+ };
+ play_on_demand_type = g_type_register_static(GST_TYPE_ELEMENT, "GstPlayOnDemand", &play_on_demand_info, 0);
+ }
+ return play_on_demand_type;
+}
+
+static void
+play_on_demand_class_init (GstPlayOnDemandClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gst_pod_filter_signals[PLAY_SIGNAL] =
+ g_signal_new("play",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GstPlayOnDemandClass, play),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ gst_pod_filter_signals[RESET_SIGNAL] =
+ g_signal_new("reset",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GstPlayOnDemandClass, reset),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ klass->play = play_on_demand_play_handler;
+ klass->reset = play_on_demand_reset_handler;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SILENT,
+ g_param_spec_boolean("silent","silent","silent",
+ TRUE, G_PARAM_READWRITE)); // CHECKME
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FOLLOWTAIL,
+ g_param_spec_boolean("follow-stream-tail","follow-stream-tail","follow-stream-tail",
+ FALSE, G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE,
+ g_param_spec_uint("buffer-size","buffer-size","buffer-size",
+ 0, G_MAXUINT - 1, POD_BUFFER_SIZE, G_PARAM_READWRITE));
+
+ gobject_class->set_property = play_on_demand_set_property;
+ gobject_class->get_property = play_on_demand_get_property;
+}
+
+static void
+play_on_demand_init (GstPlayOnDemand *filter)
+{
+ guint i;
+
+ filter->sinkpad = gst_pad_new_from_template(play_on_demand_sink_factory(), "sink");
+ gst_pad_set_negotiate_function(filter->sinkpad, play_on_demand_negotiate_sink);
+ gst_pad_set_bufferpool_function(filter->sinkpad, play_on_demand_get_bufferpool);
+
+ filter->srcpad = gst_pad_new_from_template(play_on_demand_src_factory(), "src");
+ gst_pad_set_negotiate_function(filter->srcpad, play_on_demand_negotiate_src);
+
+ gst_element_add_pad(GST_ELEMENT(filter), filter->sinkpad);
+ gst_element_add_pad(GST_ELEMENT(filter), filter->srcpad);
+
+ gst_element_set_loop_function(GST_ELEMENT(filter), play_on_demand_loop);
+
+ filter->sinkpool = gst_buffer_pool_get_default(POD_GSTBUFSIZE, POD_BUFSPERCHUNK);
+
+ filter->follow_stream_tail = FALSE;
+ filter->silent = TRUE;
+
+ filter->buffer = g_new(gchar, POD_BUFFER_SIZE);
+ filter->buffer_size = POD_BUFFER_SIZE;
+ filter->start = 0;
+ filter->write = 0;
+
+ filter->eos = FALSE;
+
+ /* the plays are stored as an array of buffer offsets. this initializes the
+ array to `blank' values (G_MAXUINT is an invalid index for this filter). */
+ filter->plays = g_new(guint, POD_MAX_PLAYS);
+ for (i = 0; i < POD_MAX_PLAYS; i++) {
+ filter->plays[i] = G_MAXUINT;
+ }
+}
+
+static void
+play_on_demand_loop (GstElement *elem)
+{
+ GstPlayOnDemand *filter = GST_PLAYONDEMAND(elem);
+ guint num_in, num_out, num_filter;
+ GstBuffer *in, *out;
+ register guint j, k, t;
+ guint w, offset;
+
+ g_return_if_fail(filter != NULL);
+ g_return_if_fail(GST_IS_PLAYONDEMAND(filter));
+
+ filter->srcpool = gst_pad_get_bufferpool(filter->srcpad);
+
+ in = gst_pad_pull(filter->sinkpad);
+
+ if (filter->format == GST_PLAYONDEMAND_FORMAT_INT) {
+ if (filter->width == 16) {
+ gint16 min = -32768;
+ gint16 max = 32767;
+ gint16 zero = 0;
+#define _TYPE_ gint16
+#include "filter.func"
+#undef _TYPE_
+ } else if (filter->width == 8) {
+ gint8 min = -128;
+ gint8 max = 127;
+ gint8 zero = 0;
+#define _TYPE_ gint8
+#include "filter.func"
+#undef _TYPE_
+ }
+ } else if (filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT) {
+ gfloat min = -1.0;
+ gfloat max = 1.0;
+ gfloat zero = 0.0;
+#define _TYPE_ gfloat
+#include "filter.func"
+#undef _TYPE_
+ }
+}
+
+static void
+play_on_demand_play_handler(GstElement *elem)
+{
+ GstPlayOnDemand *filter = GST_PLAYONDEMAND(elem);
+ register guint i;
+
+ for (i = 0; i < POD_MAX_PLAYS; i++) {
+ if (filter->plays[i] == G_MAXUINT) {
+ filter->plays[i] = filter->start;
+ break;
+ }
+ }
+}
+
+static void
+play_on_demand_reset_handler(GstElement *elem)
+{
+ GstPlayOnDemand *filter = GST_PLAYONDEMAND(elem);
+ register guint i;
+
+ for (i = 0; i < POD_MAX_PLAYS; i++) {
+ filter->plays[i] = G_MAXUINT;
+ }
+
+ filter->start = 0;
+ filter->write = 0;
+}
+
+static void
+play_on_demand_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstPlayOnDemand *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_PLAYONDEMAND(object));
+ filter = GST_PLAYONDEMAND(object);
+
+ switch (prop_id) {
+ case ARG_BUFFERSIZE:
+ filter->buffer_size = g_value_get_uint(value);
+
+ /* reallocate space for the buffer with the new size values. */
+ g_free(filter->buffer);
+ filter->buffer = g_new(gchar, filter->buffer_size);
+
+ /* reset the play pointers and read/write indexes. */
+ play_on_demand_reset_handler(GST_ELEMENT(filter));
+ break;
+ case ARG_SILENT:
+ filter->silent = g_value_get_boolean(value);
+ break;
+ case ARG_FOLLOWTAIL:
+ filter->follow_stream_tail = g_value_get_boolean(value);
+ play_on_demand_reset_handler(GST_ELEMENT(filter));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+play_on_demand_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstPlayOnDemand *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_PLAYONDEMAND(object));
+ filter = GST_PLAYONDEMAND(object);
+
+ switch (prop_id) {
+ case ARG_BUFFERSIZE:
+ g_value_set_uint(value, filter->buffer_size);
+ break;
+ case ARG_SILENT:
+ g_value_set_boolean(value, filter->silent);
+ break;
+ case ARG_FOLLOWTAIL:
+ g_value_set_boolean(value, filter->follow_stream_tail);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("playondemand",
+ GST_TYPE_PLAYONDEMAND,
+ &play_on_demand_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate(factory, play_on_demand_src_factory());
+ gst_elementfactory_add_padtemplate(factory, play_on_demand_sink_factory());
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "playondemand",
+ plugin_init
+};
diff --git a/gst/playondemand/gstplayondemand.h b/gst/playondemand/gstplayondemand.h
new file mode 100644
index 00000000..7ca8206e
--- /dev/null
+++ b/gst/playondemand/gstplayondemand.h
@@ -0,0 +1,112 @@
+/* -*- c-basic-offset: 2 -*-
+ * 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_PLAYONDEMAND_H__
+#define __GST_PLAYONDEMAND_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+/* #include <gst/meta/audioraw.h> */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_PLAYONDEMAND \
+ (gst_play_on_demand_get_type())
+#define GST_PLAYONDEMAND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAYONDEMAND,GstPlayOnDemand))
+#define GST_PLAYONDEMAND_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstPlayOnDemand))
+#define GST_IS_PLAYONDEMAND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAYONDEMAND))
+#define GST_IS_PLAYONDEMAND_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAYONDEMAND))
+
+typedef struct _GstPlayOnDemand GstPlayOnDemand;
+typedef struct _GstPlayOnDemandClass GstPlayOnDemandClass;
+typedef enum _GstPlayOnDemandFormat GstPlayOnDemandFormat;
+
+enum _GstPlayOnDemandFormat {
+ GST_PLAYONDEMAND_FORMAT_INT,
+ GST_PLAYONDEMAND_FORMAT_FLOAT
+};
+
+struct _GstPlayOnDemand {
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+ GstBufferPool *sinkpool, *srcpool;
+
+ /* these next data elements are for the filter's internal buffers and list of
+ play pointers (offsets in the internal buffers). there are also flags for
+ repeating from the beginning or end of the input stream, and a max buffer
+ size. */
+ gchar *buffer;
+ guint buffer_size;
+
+ guint write;
+ guint start;
+
+ guint *plays;
+
+ gboolean eos;
+
+ gboolean follow_stream_tail;
+
+ gboolean silent;
+
+ /* the next three are valid for both int and float */
+ GstPlayOnDemandFormat format;
+ guint rate;
+ guint channels;
+
+ /* the next five are valid only for format == GST_PLAYONDEMAND_FORMAT_INT */
+ guint width;
+ guint depth;
+ guint endianness;
+ guint law;
+ gboolean is_signed;
+
+ /* the next three are valid only for format == GST_PLAYONDEMAND_FORMAT_FLOAT */
+ const gchar *layout;
+ gfloat slope;
+ gfloat intercept;
+};
+
+struct _GstPlayOnDemandClass {
+ GstElementClass parent_class;
+
+ void (*play) (GstElement *elem);
+ void (*reset) (GstElement *elem);
+};
+
+GType gst_play_on_demand_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PLAYONDEMAND_H__ */
diff --git a/gst/rtjpeg/.gitignore b/gst/rtjpeg/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/rtjpeg/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/rtjpeg/Makefile.am b/gst/rtjpeg/Makefile.am
new file mode 100644
index 00000000..157ac760
--- /dev/null
+++ b/gst/rtjpeg/Makefile.am
@@ -0,0 +1,8 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstrtjpeg.la
+
+libgstrtjpeg_la_SOURCES = gstrtjpeg.c rtjpegenc.c rtjpegdec.c RTjpeg.c
+libgstrtjpeg_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstrtjpegenc.h gstrtjpegdec.h RTjpeg.h
diff --git a/gst/rtjpeg/README b/gst/rtjpeg/README
new file mode 100644
index 00000000..34796867
--- /dev/null
+++ b/gst/rtjpeg/README
@@ -0,0 +1,12 @@
+This plugin contains elements necessary for doing RTjpeg compression and
+decompression, as well as conversion from RGB to YUV and back, based
+entirely on functions supplied by RTjpeg.c.
+
+You can find RTjpeg at Justin Schoeman's site:
+http://www.ee.up.ac.za/~justin/bttv/
+
+The idea is to start out with the code elements reading and writing YUV420
+images, with external elements to do the conversion. Eventually (when
+typing is a bit more sane/globally used) the codec elements will
+automatically convert images to/from the proper format based on what their
+peer wants to be dealing with.
diff --git a/gst/rtjpeg/RTjpeg.c b/gst/rtjpeg/RTjpeg.c
new file mode 100644
index 00000000..38d3ce12
--- /dev/null
+++ b/gst/rtjpeg/RTjpeg.c
@@ -0,0 +1,3434 @@
+/*
+ This program is free software; you can redristibute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file is a modified version of RTjpeg 0.1.2, (C) Justin Schoeman 1998
+
+ (991101) Wim Taymans : added MMX dct and idct from intels site.
+*/
+
+
+/*
+
+Main Routines
+
+This file contains most of the initialisation and control functions
+
+(C) Justin Schoeman 1998
+
+*/
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef unsigned char __u8;
+typedef signed char __s8;
+typedef unsigned short __u16;
+typedef signed short __s16;
+typedef unsigned long __u32;
+typedef signed long __s32;
+typedef unsigned long long __u64;
+
+//#define MMX_TRACE
+
+
+#ifdef HAVE_LIBMMX
+#include "mmx.h"
+#endif
+
+static const unsigned char RTjpeg_ZZ[64]={
+0,
+8, 1,
+2, 9, 16,
+24, 17, 10, 3,
+4, 11, 18, 25, 32,
+40, 33, 26, 19, 12, 5,
+6, 13, 20, 27, 34, 41, 48,
+56, 49, 42, 35, 28, 21, 14, 7,
+15, 22, 29, 36, 43, 50, 57,
+58, 51, 44, 37, 30, 23,
+31, 38, 45, 52, 59,
+60, 53, 46, 39,
+47, 54, 61,
+62, 55,
+63 };
+
+static const __u64 RTjpeg_aan_tab[64]={
+4294967296ULL, 5957222912ULL, 5611718144ULL, 5050464768ULL, 4294967296ULL, 3374581504ULL, 2324432128ULL, 1184891264ULL,
+5957222912ULL, 8263040512ULL, 7783580160ULL, 7005009920ULL, 5957222912ULL, 4680582144ULL, 3224107520ULL, 1643641088ULL,
+5611718144ULL, 7783580160ULL, 7331904512ULL, 6598688768ULL, 5611718144ULL, 4408998912ULL, 3036936960ULL, 1548224000ULL,
+5050464768ULL, 7005009920ULL, 6598688768ULL, 5938608128ULL, 5050464768ULL, 3968072960ULL, 2733115392ULL, 1393296000ULL,
+4294967296ULL, 5957222912ULL, 5611718144ULL, 5050464768ULL, 4294967296ULL, 3374581504ULL, 2324432128ULL, 1184891264ULL,
+3374581504ULL, 4680582144ULL, 4408998912ULL, 3968072960ULL, 3374581504ULL, 2651326208ULL, 1826357504ULL, 931136000ULL,
+2324432128ULL, 3224107520ULL, 3036936960ULL, 2733115392ULL, 2324432128ULL, 1826357504ULL, 1258030336ULL, 641204288ULL,
+1184891264ULL, 1643641088ULL, 1548224000ULL, 1393296000ULL, 1184891264ULL, 931136000ULL, 641204288ULL, 326894240ULL,
+};
+
+#ifndef HAVE_LIBMMX
+static __s32 RTjpeg_ws[64+31];
+#endif
+__u8 RTjpeg_alldata[2*64+4*64+4*64+4*64+4*64+32];
+
+__s16 *RTjpeg_block;
+__s32 *RTjpeg_lqt;
+__s32 *RTjpeg_cqt;
+__u32 *RTjpeg_liqt;
+__u32 *RTjpeg_ciqt;
+
+unsigned char RTjpeg_lb8;
+unsigned char RTjpeg_cb8;
+int RTjpeg_width, RTjpeg_height;
+int RTjpeg_Ywidth, RTjpeg_Cwidth;
+int RTjpeg_Ysize, RTjpeg_Csize;
+
+__s16 *RTjpeg_old=NULL;
+
+#ifdef HAVE_LIBMMX
+mmx_t RTjpeg_lmask;
+mmx_t RTjpeg_cmask;
+#else
+__u16 RTjpeg_lmask;
+__u16 RTjpeg_cmask;
+#endif
+int RTjpeg_mtest=0;
+
+static const unsigned char RTjpeg_lum_quant_tbl[64] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+ };
+
+static const unsigned char RTjpeg_chrom_quant_tbl[64] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+int RTjpeg_b2s(__s16 *data, __s8 *strm, __u8 bt8)
+{
+ register int ci, co=1, tmp;
+ register __s16 ZZvalue;
+
+ (__u8)strm[0]=(__u8)(data[RTjpeg_ZZ[0]]>254) ? 254:((data[RTjpeg_ZZ[0]]<0)?0:data[RTjpeg_ZZ[0]]);
+
+ for(ci=1; ci<=bt8; ci++)
+ {
+ ZZvalue = data[RTjpeg_ZZ[ci]];
+
+ if(ZZvalue>0)
+ {
+ strm[co++]=(__s8)(ZZvalue>127)?127:ZZvalue;
+ }
+ else
+ {
+ strm[co++]=(__s8)(ZZvalue<-128)?-128:ZZvalue;
+ }
+ }
+
+ for(; ci<64; ci++)
+ {
+ ZZvalue = data[RTjpeg_ZZ[ci]];
+
+ if(ZZvalue>0)
+ {
+ strm[co++]=(__s8)(ZZvalue>63)?63:ZZvalue;
+ }
+ else if(ZZvalue<0)
+ {
+ strm[co++]=(__s8)(ZZvalue<-64)?-64:ZZvalue;
+ }
+ else /* compress zeros */
+ {
+ tmp=ci;
+ do
+ {
+ ci++;
+ }
+ while((ci<64)&&(data[RTjpeg_ZZ[ci]]==0));
+
+ strm[co++]=(__s8)(63+(ci-tmp));
+ ci--;
+ }
+ }
+ return (int)co;
+}
+
+int RTjpeg_s2b(__s16 *data, __s8 *strm, __u8 bt8, __u32 *qtbl)
+{
+ int ci=1, co=1, tmp;
+ register int i;
+
+ i=RTjpeg_ZZ[0];
+ data[i]=((__u8)strm[0])*qtbl[i];
+
+ for(co=1; co<=bt8; co++)
+ {
+ i=RTjpeg_ZZ[co];
+ data[i]=strm[ci++]*qtbl[i];
+ }
+
+ for(; co<64; co++)
+ {
+ if(strm[ci]>63)
+ {
+ tmp=co+strm[ci]-63;
+ for(; co<tmp; co++)data[RTjpeg_ZZ[co]]=0;
+ co--;
+ } else
+ {
+ i=RTjpeg_ZZ[co];
+ data[i]=strm[ci]*qtbl[i];
+ }
+ ci++;
+ }
+ return (int)ci;
+}
+
+#if defined(HAVE_LIBMMX)
+void RTjpeg_quant_init(void)
+{
+ int i;
+ __s16 *qtbl;
+
+ qtbl=(__s16 *)RTjpeg_lqt;
+ for(i=0; i<64; i++)qtbl[i]=(__s16)RTjpeg_lqt[i];
+
+ qtbl=(__s16 *)RTjpeg_cqt;
+ for(i=0; i<64; i++)qtbl[i]=(__s16)RTjpeg_cqt[i];
+}
+
+static mmx_t RTjpeg_ones=(mmx_t)(long long)0x0001000100010001LL;
+static mmx_t RTjpeg_half=(mmx_t)(long long)0x7fff7fff7fff7fffLL;
+
+void RTjpeg_quant(__s16 *block, __s32 *qtbl)
+{
+ int i;
+ mmx_t *bl, *ql;
+
+ ql=(mmx_t *)qtbl;
+ bl=(mmx_t *)block;
+
+ movq_m2r(RTjpeg_ones, mm6);
+ movq_m2r(RTjpeg_half, mm7);
+
+ for(i=16; i; i--)
+ {
+ movq_m2r(*(ql++), mm0); /* quant vals (4) */
+ movq_m2r(*bl, mm2); /* block vals (4) */
+ movq_r2r(mm0, mm1);
+ movq_r2r(mm2, mm3);
+
+ punpcklwd_r2r(mm6, mm0); /* 1 qb 1 qa */
+ punpckhwd_r2r(mm6, mm1); /* 1 qd 1 qc */
+
+ punpcklwd_r2r(mm7, mm2); /* 32767 bb 32767 ba */
+ punpckhwd_r2r(mm7, mm3); /* 32767 bd 32767 bc */
+
+ pmaddwd_r2r(mm2, mm0); /* 32767+bb*qb 32767+ba*qa */
+ pmaddwd_r2r(mm3, mm1); /* 32767+bd*qd 32767+bc*qc */
+
+ psrad_i2r(16, mm0);
+ psrad_i2r(16, mm1);
+
+ packssdw_r2r(mm1, mm0);
+
+ movq_r2m(mm0, *(bl++));
+
+ }
+}
+#else
+void RTjpeg_quant_init(void)
+{
+}
+
+void RTjpeg_quant(__s16 *block, __s32 *qtbl)
+{
+ int i;
+
+ for(i=0; i<64; i++)
+ block[i]=(__s16)((block[i]*qtbl[i]+32767)>>16);
+}
+#endif
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+#ifdef HAVE_LIBMMX
+static mmx_t RTjpeg_C4 =(mmx_t)(long long)0x2D412D412D412D41LL;
+static mmx_t RTjpeg_C6 =(mmx_t)(long long)0x187E187E187E187ELL;
+static mmx_t RTjpeg_C2mC6=(mmx_t)(long long)0x22A322A322A322A3LL;
+static mmx_t RTjpeg_C2pC6=(mmx_t)(long long)0x539F539F539F539FLL;
+static mmx_t RTjpeg_zero =(mmx_t)(long long)0x0000000000000000LL;
+
+#else
+
+#define FIX_0_382683433 ((__s32) 98) /* FIX(0.382683433) */
+#define FIX_0_541196100 ((__s32) 139) /* FIX(0.541196100) */
+#define FIX_0_707106781 ((__s32) 181) /* FIX(0.707106781) */
+#define FIX_1_306562965 ((__s32) 334) /* FIX(1.306562965) */
+
+#define DESCALE10(x) (__s16)( ((x)+128) >> 8)
+#define DESCALE20(x) (__s16)(((x)+32768) >> 16)
+#define D_MULTIPLY(var,const) ((__s32) ((var) * (const)))
+#endif
+
+void RTjpeg_dct_init(void)
+{
+ int i;
+
+ for(i=0; i<64; i++)
+ {
+ RTjpeg_lqt[i]=(((__u64)RTjpeg_lqt[i]<<32)/RTjpeg_aan_tab[i]);
+ RTjpeg_cqt[i]=(((__u64)RTjpeg_cqt[i]<<32)/RTjpeg_aan_tab[i]);
+ }
+}
+
+void RTjpeg_dctY(__u8 *idata, __s16 *odata, int rskip)
+{
+#ifndef HAVE_LIBMMX
+ __s32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ __s32 tmp10, tmp11, tmp12, tmp13;
+ __s32 z1, z2, z3, z4, z5, z11, z13;
+ __u8 *idataptr;
+ __s16 *odataptr;
+ __s32 *wsptr;
+ int ctr;
+
+ idataptr = idata;
+ wsptr = RTjpeg_ws;
+ for (ctr = 7; ctr >= 0; ctr--) {
+ tmp0 = idataptr[0] + idataptr[7];
+ tmp7 = idataptr[0] - idataptr[7];
+ tmp1 = idataptr[1] + idataptr[6];
+ tmp6 = idataptr[1] - idataptr[6];
+ tmp2 = idataptr[2] + idataptr[5];
+ tmp5 = idataptr[2] - idataptr[5];
+ tmp3 = idataptr[3] + idataptr[4];
+ tmp4 = idataptr[3] - idataptr[4];
+
+ tmp10 = (tmp0 + tmp3); /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = (tmp1 + tmp2);
+ tmp12 = tmp1 - tmp2;
+
+ wsptr[0] = (tmp10 + tmp11)<<8; /* phase 3 */
+ wsptr[4] = (tmp10 - tmp11)<<8;
+
+ z1 = D_MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ wsptr[2] = (tmp13<<8) + z1; /* phase 5 */
+ wsptr[6] = (tmp13<<8) - z1;
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ z5 = D_MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = D_MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = D_MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = D_MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = (tmp7<<8) + z3; /* phase 5 */
+ z13 = (tmp7<<8) - z3;
+
+ wsptr[5] = z13 + z2; /* phase 6 */
+ wsptr[3] = z13 - z2;
+ wsptr[1] = z11 + z4;
+ wsptr[7] = z11 - z4;
+
+ idataptr += rskip<<3; /* advance pointer to next row */
+ wsptr += 8;
+ }
+
+ wsptr = RTjpeg_ws;
+ odataptr=odata;
+ for (ctr = 7; ctr >= 0; ctr--) {
+ tmp0 = wsptr[0] + wsptr[56];
+ tmp7 = wsptr[0] - wsptr[56];
+ tmp1 = wsptr[8] + wsptr[48];
+ tmp6 = wsptr[8] - wsptr[48];
+ tmp2 = wsptr[16] + wsptr[40];
+ tmp5 = wsptr[16] - wsptr[40];
+ tmp3 = wsptr[24] + wsptr[32];
+ tmp4 = wsptr[24] - wsptr[32];
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ odataptr[0] = DESCALE10(tmp10 + tmp11); /* phase 3 */
+ odataptr[32] = DESCALE10(tmp10 - tmp11);
+
+ z1 = D_MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ odataptr[16] = DESCALE20((tmp13<<8) + z1); /* phase 5 */
+ odataptr[48] = DESCALE20((tmp13<<8) - z1);
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ z5 = D_MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = D_MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = D_MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = D_MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = (tmp7<<8) + z3; /* phase 5 */
+ z13 = (tmp7<<8) - z3;
+
+ odataptr[40] = DESCALE20(z13 + z2); /* phase 6 */
+ odataptr[24] = DESCALE20(z13 - z2);
+ odataptr[8] = DESCALE20(z11 + z4);
+ odataptr[56] = DESCALE20(z11 - z4);
+
+ odataptr++; /* advance pointer to next column */
+ wsptr++;
+ }
+#else
+ mmx_t tmp6, tmp7;
+ register mmx_t *dataptr = (mmx_t *)odata;
+ mmx_t *idata2 = (mmx_t *)idata;
+
+ // first copy the input 8 bit to the destination 16 bits
+
+ movq_m2r(RTjpeg_zero, mm2);
+
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+1));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+2));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+3));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+4));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+5));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+6));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+7));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+8));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+9));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+10));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+11));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+12));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+13));
+
+ idata2 += rskip;
+
+ movq_m2r(*idata2, mm0);
+ movq_r2r(mm0, mm1);
+
+ punpcklbw_r2r(mm2, mm0);
+ movq_r2m(mm0, *(dataptr+14));
+
+ punpckhbw_r2r(mm2, mm1);
+ movq_r2m(mm1, *(dataptr+15));
+
+/* Start Transpose to do calculations on rows */
+
+ movq_m2r(*(dataptr+9), mm7); // m03:m02|m01:m00 - first line (line 4)and copy into m5
+
+ movq_m2r(*(dataptr+13), mm6); // m23:m22|m21:m20 - third line (line 6)and copy into m2
+ movq_r2r(mm7, mm5);
+
+ punpcklwd_m2r(*(dataptr+11), mm7); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm6, mm2);
+
+ punpcklwd_m2r(*(dataptr+15), mm6); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm7, mm1);
+
+ movq_m2r(*(dataptr+11), mm3); // m13:m13|m11:m10 - second line
+ punpckldq_r2r(mm6, mm7); // m30:m20|m10:m00 - interleave to produce result 1
+
+ movq_m2r(*(dataptr+15), mm0); // m13:m13|m11:m10 - fourth line
+ punpckhdq_r2r(mm6, mm1); // m31:m21|m11:m01 - interleave to produce result 2
+
+ movq_r2m(mm7,*(dataptr+9)); // write result 1
+ punpckhwd_r2r(mm3, mm5); // m13:m03|m12:m02 - interleave first and second lines
+
+ movq_r2m(mm1,*(dataptr+11)); // write result 2
+ punpckhwd_r2r(mm0, mm2); // m33:m23|m32:m22 - interleave third and fourth lines
+
+ movq_r2r(mm5, mm1);
+ punpckldq_r2r(mm2, mm5); // m32:m22|m12:m02 - interleave to produce result 3
+
+ movq_m2r(*(dataptr+1), mm0); // m03:m02|m01:m00 - first line, 4x4
+ punpckhdq_r2r(mm2, mm1); // m33:m23|m13:m03 - interleave to produce result 4
+
+ movq_r2m(mm5,*(dataptr+13)); // write result 3
+
+ // last 4x4 done
+
+ movq_r2m(mm1, *(dataptr+15)); // write result 4, last 4x4
+
+ movq_m2r(*(dataptr+5), mm2); // m23:m22|m21:m20 - third line
+ movq_r2r(mm0, mm6);
+
+ punpcklwd_m2r(*(dataptr+3), mm0); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm2, mm7);
+
+ punpcklwd_m2r(*(dataptr+7), mm2); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm0, mm4);
+
+ //
+ movq_m2r(*(dataptr+8), mm1); // n03:n02|n01:n00 - first line
+ punpckldq_r2r(mm2, mm0); // m30:m20|m10:m00 - interleave to produce first result
+
+ movq_m2r(*(dataptr+12), mm3); // n23:n22|n21:n20 - third line
+ punpckhdq_r2r(mm2, mm4); // m31:m21|m11:m01 - interleave to produce second result
+
+ punpckhwd_m2r(*(dataptr+3), mm6); // m13:m03|m12:m02 - interleave first and second lines
+ movq_r2r(mm1, mm2); // copy first line
+
+ punpckhwd_m2r(*(dataptr+7), mm7); // m33:m23|m32:m22 - interleave third and fourth lines
+ movq_r2r(mm6, mm5); // copy first intermediate result
+
+ movq_r2m(mm0, *(dataptr+8)); // write result 1
+ punpckhdq_r2r(mm7, mm5); // m33:m23|m13:m03 - produce third result
+
+ punpcklwd_m2r(*(dataptr+10), mm1); // n11:n01|n10:n00 - interleave first and second lines
+ movq_r2r(mm3, mm0); // copy third line
+
+ punpckhwd_m2r(*(dataptr+10), mm2); // n13:n03|n12:n02 - interleave first and second lines
+
+ movq_r2m(mm4, *(dataptr+10)); // write result 2 out
+ punpckldq_r2r(mm7, mm6); // m32:m22|m12:m02 - produce fourth result
+
+ punpcklwd_m2r(*(dataptr+14), mm3); // n31:n21|n30:n20 - interleave third and fourth lines
+ movq_r2r(mm1, mm4);
+
+ movq_r2m(mm6, *(dataptr+12)); // write result 3 out
+ punpckldq_r2r(mm3, mm1); // n30:n20|n10:n00 - produce first result
+
+ punpckhwd_m2r(*(dataptr+14), mm0); // n33:n23|n32:n22 - interleave third and fourth lines
+ movq_r2r(mm2, mm6);
+
+ movq_r2m(mm5, *(dataptr+14)); // write result 4 out
+ punpckhdq_r2r(mm3, mm4); // n31:n21|n11:n01- produce second result
+
+ movq_r2m(mm1, *(dataptr+1)); // write result 5 out - (first result for other 4 x 4 block)
+ punpckldq_r2r(mm0, mm2); // n32:n22|n12:n02- produce third result
+
+ movq_r2m(mm4, *(dataptr+3)); // write result 6 out
+ punpckhdq_r2r(mm0, mm6); // n33:n23|n13:n03 - produce fourth result
+
+ movq_r2m(mm2, *(dataptr+5)); // write result 7 out
+
+ movq_m2r(*dataptr, mm0); // m03:m02|m01:m00 - first line, first 4x4
+
+ movq_r2m(mm6, *(dataptr+7)); // write result 8 out
+
+
+// Do first 4x4 quadrant, which is used in the beginning of the DCT:
+
+ movq_m2r(*(dataptr+4), mm7); // m23:m22|m21:m20 - third line
+ movq_r2r(mm0, mm2);
+
+ punpcklwd_m2r(*(dataptr+2), mm0); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm7, mm4);
+
+ punpcklwd_m2r(*(dataptr+6), mm7); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm0, mm1);
+
+ movq_m2r(*(dataptr+2), mm6); // m13:m12|m11:m10 - second line
+ punpckldq_r2r(mm7, mm0); // m30:m20|m10:m00 - interleave to produce result 1
+
+ movq_m2r(*(dataptr+6), mm5); // m33:m32|m31:m30 - fourth line
+ punpckhdq_r2r(mm7, mm1); // m31:m21|m11:m01 - interleave to produce result 2
+
+ movq_r2r(mm0, mm7); // write result 1
+ punpckhwd_r2r(mm6, mm2); // m13:m03|m12:m02 - interleave first and second lines
+
+ psubw_m2r(*(dataptr+14), mm7); // tmp07=x0-x7 /* Stage 1 */
+ movq_r2r(mm1, mm6); // write result 2
+
+ paddw_m2r(*(dataptr+14), mm0); // tmp00=x0+x7 /* Stage 1 */
+ punpckhwd_r2r(mm5, mm4); // m33:m23|m32:m22 - interleave third and fourth lines
+
+ paddw_m2r(*(dataptr+12), mm1); // tmp01=x1+x6 /* Stage 1 */
+ movq_r2r(mm2, mm3); // copy first intermediate result
+
+ psubw_m2r(*(dataptr+12), mm6); // tmp06=x1-x6 /* Stage 1 */
+ punpckldq_r2r(mm4, mm2); // m32:m22|m12:m02 - interleave to produce result 3
+
+ movq_r2m(mm7, tmp7);
+ movq_r2r(mm2, mm5); // write result 3
+
+ movq_r2m(mm6, tmp6);
+ punpckhdq_r2r(mm4, mm3); // m33:m23|m13:m03 - interleave to produce result 4
+
+ paddw_m2r(*(dataptr+10), mm2); // tmp02=x2+5 /* Stage 1 */
+ movq_r2r(mm3, mm4); // write result 4
+
+/************************************************************************************************
+ End of Transpose
+************************************************************************************************/
+
+
+ paddw_m2r(*(dataptr+8), mm3); // tmp03=x3+x4 /* stage 1*/
+ movq_r2r(mm0, mm7);
+
+ psubw_m2r(*(dataptr+8), mm4); // tmp04=x3-x4 /* stage 1*/
+ movq_r2r(mm1, mm6);
+
+ paddw_r2r(mm3, mm0); // tmp10 = tmp00 + tmp03 /* even 2 */
+ psubw_r2r(mm3, mm7); // tmp13 = tmp00 - tmp03 /* even 2 */
+
+ psubw_r2r(mm2, mm6); // tmp12 = tmp01 - tmp02 /* even 2 */
+ paddw_r2r(mm2, mm1); // tmp11 = tmp01 + tmp02 /* even 2 */
+
+ psubw_m2r(*(dataptr+10), mm5); // tmp05=x2-x5 /* stage 1*/
+ paddw_r2r(mm7, mm6); // tmp12 + tmp13
+
+ /* stage 3 */
+
+ movq_m2r(tmp6, mm2);
+ movq_r2r(mm0, mm3);
+
+ psllw_i2r(2, mm6); // m8 * 2^2
+ paddw_r2r(mm1, mm0);
+
+ pmulhw_m2r(RTjpeg_C4, mm6); // z1
+ psubw_r2r(mm1, mm3);
+
+ movq_r2m(mm0, *dataptr);
+ movq_r2r(mm7, mm0);
+
+ /* Odd part */
+ movq_r2m(mm3, *(dataptr+8));
+ paddw_r2r(mm5, mm4); // tmp10
+
+ movq_m2r(tmp7, mm3);
+ paddw_r2r(mm6, mm0); // tmp32
+
+ paddw_r2r(mm2, mm5); // tmp11
+ psubw_r2r(mm6, mm7); // tmp33
+
+ movq_r2m(mm0, *(dataptr+4));
+ paddw_r2r(mm3, mm2); // tmp12
+
+ /* stage 4 */
+
+ movq_r2m(mm7, *(dataptr+12));
+ movq_r2r(mm4, mm1); // copy of tmp10
+
+ psubw_r2r(mm2, mm1); // tmp10 - tmp12
+ psllw_i2r(2, mm4); // m8 * 2^2
+
+ movq_m2r(RTjpeg_C2mC6, mm0);
+ psllw_i2r(2, mm1);
+
+ pmulhw_m2r(RTjpeg_C6, mm1); // z5
+ psllw_i2r(2, mm2);
+
+ pmulhw_r2r(mm0, mm4); // z5
+
+ /* stage 5 */
+
+ pmulhw_m2r(RTjpeg_C2pC6, mm2);
+ psllw_i2r(2, mm5);
+
+ pmulhw_m2r(RTjpeg_C4, mm5); // z3
+ movq_r2r(mm3, mm0); // copy tmp7
+
+ movq_m2r(*(dataptr+1), mm7);
+ paddw_r2r(mm1, mm4); // z2
+
+ paddw_r2r(mm1, mm2); // z4
+
+ paddw_r2r(mm5, mm0); // z11
+ psubw_r2r(mm5, mm3); // z13
+
+ /* stage 6 */
+
+ movq_r2r(mm3, mm5); // copy z13
+ psubw_r2r(mm4, mm3); // y3=z13 - z2
+
+ paddw_r2r(mm4, mm5); // y5=z13 + z2
+ movq_r2r(mm0, mm6); // copy z11
+
+ movq_r2m(mm3, *(dataptr+6)); //save y3
+ psubw_r2r(mm2, mm0); // y7=z11 - z4
+
+ movq_r2m(mm5, *(dataptr+10)); //save y5
+ paddw_r2r(mm2, mm6); // y1=z11 + z4
+
+ movq_r2m(mm0, *(dataptr+14)); //save y7
+
+ /************************************************
+ * End of 1st 4 rows
+ ************************************************/
+
+ movq_m2r(*(dataptr+3), mm1); // load x1 /* stage 1 */
+ movq_r2r(mm7, mm0); // copy x0
+
+ movq_r2m(mm6, *(dataptr+2)); //save y1
+
+ movq_m2r(*(dataptr+5), mm2); // load x2 /* stage 1 */
+ movq_r2r(mm1, mm6); // copy x1
+
+ paddw_m2r(*(dataptr+15), mm0); // tmp00 = x0 + x7
+
+ movq_m2r(*(dataptr+7), mm3); // load x3 /* stage 1 */
+ movq_r2r(mm2, mm5); // copy x2
+
+ psubw_m2r(*(dataptr+15), mm7); // tmp07 = x0 - x7
+ movq_r2r(mm3, mm4); // copy x3
+
+ paddw_m2r(*(dataptr+13), mm1); // tmp01 = x1 + x6
+
+ movq_r2m(mm7, tmp7); // save tmp07
+ movq_r2r(mm0, mm7); // copy tmp00
+
+ psubw_m2r(*(dataptr+13), mm6); // tmp06 = x1 - x6
+
+ /* stage 2, Even Part */
+
+ paddw_m2r(*(dataptr+9), mm3); // tmp03 = x3 + x4
+
+ movq_r2m(mm6, tmp6); // save tmp07
+ movq_r2r(mm1, mm6); // copy tmp01
+
+ paddw_m2r(*(dataptr+11), mm2); // tmp02 = x2 + x5
+ paddw_r2r(mm3, mm0); // tmp10 = tmp00 + tmp03
+
+ psubw_r2r(mm3, mm7); // tmp13 = tmp00 - tmp03
+
+ psubw_m2r(*(dataptr+9), mm4); // tmp04 = x3 - x4
+ psubw_r2r(mm2, mm6); // tmp12 = tmp01 - tmp02
+
+ paddw_r2r(mm2, mm1); // tmp11 = tmp01 + tmp02
+
+ psubw_m2r(*(dataptr+11), mm5); // tmp05 = x2 - x5
+ paddw_r2r(mm7, mm6); // tmp12 + tmp13
+
+ /* stage 3, Even and stage 4 & 5 even */
+
+ movq_m2r(tmp6, mm2); // load tmp6
+ movq_r2r(mm0, mm3); // copy tmp10
+
+ psllw_i2r(2, mm6); // shift z1
+ paddw_r2r(mm1, mm0); // y0=tmp10 + tmp11
+
+ pmulhw_m2r(RTjpeg_C4, mm6); // z1
+ psubw_r2r(mm1, mm3); // y4=tmp10 - tmp11
+
+ movq_r2m(mm0, *(dataptr+1)); //save y0
+ movq_r2r(mm7, mm0); // copy tmp13
+
+ /* odd part */
+
+ movq_r2m(mm3, *(dataptr+9)); //save y4
+ paddw_r2r(mm5, mm4); // tmp10 = tmp4 + tmp5
+
+ movq_m2r(tmp7, mm3); // load tmp7
+ paddw_r2r(mm6, mm0); // tmp32 = tmp13 + z1
+
+ paddw_r2r(mm2, mm5); // tmp11 = tmp5 + tmp6
+ psubw_r2r(mm6, mm7); // tmp33 = tmp13 - z1
+
+ movq_r2m(mm0, *(dataptr+5)); //save y2
+ paddw_r2r(mm3, mm2); // tmp12 = tmp6 + tmp7
+
+ /* stage 4 */
+
+ movq_r2m(mm7, *(dataptr+13)); //save y6
+ movq_r2r(mm4, mm1); // copy tmp10
+
+ psubw_r2r(mm2, mm1); // tmp10 - tmp12
+ psllw_i2r(2, mm4); // shift tmp10
+
+ movq_m2r(RTjpeg_C2mC6, mm0); // load C2mC6
+ psllw_i2r(2, mm1); // shift (tmp10-tmp12)
+
+ pmulhw_m2r(RTjpeg_C6, mm1); // z5
+ psllw_i2r(2, mm5); // prepare for multiply
+
+ pmulhw_r2r(mm0, mm4); // multiply by converted real
+
+ /* stage 5 */
+
+ pmulhw_m2r(RTjpeg_C4, mm5); // z3
+ psllw_i2r(2, mm2); // prepare for multiply
+
+ pmulhw_m2r(RTjpeg_C2pC6, mm2); // multiply
+ movq_r2r(mm3, mm0); // copy tmp7
+
+ movq_m2r(*(dataptr+9), mm7); // m03:m02|m01:m00 - first line (line 4)and copy into mm7
+ paddw_r2r(mm1, mm4); // z2
+
+ paddw_r2r(mm5, mm0); // z11
+ psubw_r2r(mm5, mm3); // z13
+
+ /* stage 6 */
+
+ movq_r2r(mm3, mm5); // copy z13
+ paddw_r2r(mm1, mm2); // z4
+
+ movq_r2r(mm0, mm6); // copy z11
+ psubw_r2r(mm4, mm5); // y3
+
+ paddw_r2r(mm2, mm6); // y1
+ paddw_r2r(mm4, mm3); // y5
+
+ movq_r2m(mm5, *(dataptr+7)); //save y3
+
+ movq_r2m(mm6, *(dataptr+3)); //save y1
+ psubw_r2r(mm2, mm0); // y7
+
+/************************************************************************************************
+ Start of Transpose
+************************************************************************************************/
+
+ movq_m2r(*(dataptr+13), mm6); // m23:m22|m21:m20 - third line (line 6)and copy into m2
+ movq_r2r(mm7, mm5); // copy first line
+
+ punpcklwd_r2r(mm3, mm7); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm6, mm2); // copy third line
+
+ punpcklwd_r2r(mm0, mm6); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm7, mm1); // copy first intermediate result
+
+ punpckldq_r2r(mm6, mm7); // m30:m20|m10:m00 - interleave to produce result 1
+
+ punpckhdq_r2r(mm6, mm1); // m31:m21|m11:m01 - interleave to produce result 2
+
+ movq_r2m(mm7, *(dataptr+9)); // write result 1
+ punpckhwd_r2r(mm3, mm5); // m13:m03|m12:m02 - interleave first and second lines
+
+ movq_r2m(mm1, *(dataptr+11)); // write result 2
+ punpckhwd_r2r(mm0, mm2); // m33:m23|m32:m22 - interleave third and fourth lines
+
+ movq_r2r(mm5, mm1); // copy first intermediate result
+ punpckldq_r2r(mm2, mm5); // m32:m22|m12:m02 - interleave to produce result 3
+
+ movq_m2r(*(dataptr+1), mm0); // m03:m02|m01:m00 - first line, 4x4
+ punpckhdq_r2r(mm2, mm1); // m33:m23|m13:m03 - interleave to produce result 4
+
+ movq_r2m(mm5, *(dataptr+13)); // write result 3
+
+ /****** last 4x4 done */
+
+ movq_r2m(mm1, *(dataptr+15)); // write result 4, last 4x4
+
+ movq_m2r(*(dataptr+5), mm2); // m23:m22|m21:m20 - third line
+ movq_r2r(mm0, mm6); // copy first line
+
+ punpcklwd_m2r(*(dataptr+3), mm0); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm2, mm7); // copy third line
+
+ punpcklwd_m2r(*(dataptr+7), mm2); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm0, mm4); // copy first intermediate result
+
+
+
+ movq_m2r(*(dataptr+8), mm1); // n03:n02|n01:n00 - first line
+ punpckldq_r2r(mm2, mm0); // m30:m20|m10:m00 - interleave to produce first result
+
+ movq_m2r(*(dataptr+12), mm3); // n23:n22|n21:n20 - third line
+ punpckhdq_r2r(mm2, mm4); // m31:m21|m11:m01 - interleave to produce second result
+
+ punpckhwd_m2r(*(dataptr+3), mm6); // m13:m03|m12:m02 - interleave first and second lines
+ movq_r2r(mm1, mm2); // copy first line
+
+ punpckhwd_m2r(*(dataptr+7), mm7); // m33:m23|m32:m22 - interleave third and fourth lines
+ movq_r2r(mm6, mm5); // copy first intermediate result
+
+ movq_r2m(mm0, *(dataptr+8)); // write result 1
+ punpckhdq_r2r(mm7, mm5); // m33:m23|m13:m03 - produce third result
+
+ punpcklwd_m2r(*(dataptr+10), mm1); // n11:n01|n10:n00 - interleave first and second lines
+ movq_r2r(mm3, mm0); // copy third line
+
+ punpckhwd_m2r(*(dataptr+10), mm2); // n13:n03|n12:n02 - interleave first and second lines
+
+ movq_r2m(mm4, *(dataptr+10)); // write result 2 out
+ punpckldq_r2r(mm7, mm6); // m32:m22|m12:m02 - produce fourth result
+
+ punpcklwd_m2r(*(dataptr+14), mm3); // n33:n23|n32:n22 - interleave third and fourth lines
+ movq_r2r(mm1, mm4); // copy second intermediate result
+
+ movq_r2m(mm6, *(dataptr+12)); // write result 3 out
+ punpckldq_r2r(mm3, mm1); //
+
+ punpckhwd_m2r(*(dataptr+14), mm0); // n33:n23|n32:n22 - interleave third and fourth lines
+ movq_r2r(mm2, mm6); // copy second intermediate result
+
+ movq_r2m(mm5, *(dataptr+14)); // write result 4 out
+ punpckhdq_r2r(mm3, mm4); // n31:n21|n11:n01- produce second result
+
+ movq_r2m(mm1, *(dataptr+1)); // write result 5 out - (first result for other 4 x 4 block)
+ punpckldq_r2r(mm0, mm2); // n32:n22|n12:n02- produce third result
+
+ movq_r2m(mm4, *(dataptr+3)); // write result 6 out
+ punpckhdq_r2r(mm0, mm6); // n33:n23|n13:n03 - produce fourth result
+
+ movq_r2m(mm2, *(dataptr+5)); // write result 7 out
+
+ movq_m2r(*dataptr, mm0); // m03:m02|m01:m00 - first line, first 4x4
+
+ movq_r2m(mm6, *(dataptr+7)); // write result 8 out
+
+// Do first 4x4 quadrant, which is used in the beginning of the DCT:
+
+ movq_m2r(*(dataptr+4), mm7); // m23:m22|m21:m20 - third line
+ movq_r2r(mm0, mm2); // copy first line
+
+ punpcklwd_m2r(*(dataptr+2), mm0); // m11:m01|m10:m00 - interleave first and second lines
+ movq_r2r(mm7, mm4); // copy third line
+
+ punpcklwd_m2r(*(dataptr+6), mm7); // m31:m21|m30:m20 - interleave third and fourth lines
+ movq_r2r(mm0, mm1); // copy first intermediate result
+
+ movq_m2r(*(dataptr+2), mm6); // m13:m12|m11:m10 - second line
+ punpckldq_r2r(mm7, mm0); // m30:m20|m10:m00 - interleave to produce result 1
+
+ movq_m2r(*(dataptr+6), mm5); // m33:m32|m31:m30 - fourth line
+ punpckhdq_r2r(mm7, mm1); // m31:m21|m11:m01 - interleave to produce result 2
+
+ movq_r2r(mm0, mm7); // write result 1
+ punpckhwd_r2r(mm6, mm2); // m13:m03|m12:m02 - interleave first and second lines
+
+ psubw_m2r(*(dataptr+14), mm7); // tmp07=x0-x7 /* Stage 1 */
+ movq_r2r(mm1, mm6); // write result 2
+
+ paddw_m2r(*(dataptr+14), mm0); // tmp00=x0+x7 /* Stage 1 */
+ punpckhwd_r2r(mm5, mm4); // m33:m23|m32:m22 - interleave third and fourth lines
+
+ paddw_m2r(*(dataptr+12), mm1); // tmp01=x1+x6 /* Stage 1 */
+ movq_r2r(mm2, mm3); // copy first intermediate result
+
+ psubw_m2r(*(dataptr+12), mm6); // tmp06=x1-x6 /* Stage 1 */
+ punpckldq_r2r(mm4, mm2); // m32:m22|m12:m02 - interleave to produce result 3
+
+ movq_r2m(mm7, tmp7); // save tmp07
+ movq_r2r(mm2, mm5); // write result 3
+
+ movq_r2m(mm6, tmp6); // save tmp06
+
+ punpckhdq_r2r(mm4, mm3); // m33:m23|m13:m03 - interleave to produce result 4
+
+ paddw_m2r(*(dataptr+10), mm2); // tmp02=x2+x5 /* stage 1 */
+ movq_r2r(mm3, mm4); // write result 4
+
+/************************************************************************************************
+ End of Transpose 2
+************************************************************************************************/
+
+ paddw_m2r(*(dataptr+8), mm3); // tmp03=x3+x4 /* stage 1*/
+ movq_r2r(mm0, mm7);
+
+ psubw_m2r(*(dataptr+8), mm4); // tmp04=x3-x4 /* stage 1*/
+ movq_r2r(mm1, mm6);
+
+ paddw_r2r(mm3, mm0); // tmp10 = tmp00 + tmp03 /* even 2 */
+ psubw_r2r(mm3, mm7); // tmp13 = tmp00 - tmp03 /* even 2 */
+
+ psubw_r2r(mm2, mm6); // tmp12 = tmp01 - tmp02 /* even 2 */
+ paddw_r2r(mm2, mm1); // tmp11 = tmp01 + tmp02 /* even 2 */
+
+ psubw_m2r(*(dataptr+10), mm5); // tmp05=x2-x5 /* stage 1*/
+ paddw_r2r(mm7, mm6); // tmp12 + tmp13
+
+ /* stage 3 */
+
+ movq_m2r(tmp6, mm2);
+ movq_r2r(mm0, mm3);
+
+ psllw_i2r(2, mm6); // m8 * 2^2
+ paddw_r2r(mm1, mm0);
+
+ pmulhw_m2r(RTjpeg_C4, mm6); // z1
+ psubw_r2r(mm1, mm3);
+
+ movq_r2m(mm0, *dataptr);
+ movq_r2r(mm7, mm0);
+
+ /* Odd part */
+ movq_r2m(mm3, *(dataptr+8));
+ paddw_r2r(mm5, mm4); // tmp10
+
+ movq_m2r(tmp7, mm3);
+ paddw_r2r(mm6, mm0); // tmp32
+
+ paddw_r2r(mm2, mm5); // tmp11
+ psubw_r2r(mm6, mm7); // tmp33
+
+ movq_r2m(mm0, *(dataptr+4));
+ paddw_r2r(mm3, mm2); // tmp12
+
+ /* stage 4 */
+ movq_r2m(mm7, *(dataptr+12));
+ movq_r2r(mm4, mm1); // copy of tmp10
+
+ psubw_r2r(mm2, mm1); // tmp10 - tmp12
+ psllw_i2r(2, mm4); // m8 * 2^2
+
+ movq_m2r(RTjpeg_C2mC6, mm0);
+ psllw_i2r(2, mm1);
+
+ pmulhw_m2r(RTjpeg_C6, mm1); // z5
+ psllw_i2r(2, mm2);
+
+ pmulhw_r2r(mm0, mm4); // z5
+
+ /* stage 5 */
+
+ pmulhw_m2r(RTjpeg_C2pC6, mm2);
+ psllw_i2r(2, mm5);
+
+ pmulhw_m2r(RTjpeg_C4, mm5); // z3
+ movq_r2r(mm3, mm0); // copy tmp7
+
+ movq_m2r(*(dataptr+1), mm7);
+ paddw_r2r(mm1, mm4); // z2
+
+ paddw_r2r(mm1, mm2); // z4
+
+ paddw_r2r(mm5, mm0); // z11
+ psubw_r2r(mm5, mm3); // z13
+
+ /* stage 6 */
+
+ movq_r2r(mm3, mm5); // copy z13
+ psubw_r2r(mm4, mm3); // y3=z13 - z2
+
+ paddw_r2r(mm4, mm5); // y5=z13 + z2
+ movq_r2r(mm0, mm6); // copy z11
+
+ movq_r2m(mm3, *(dataptr+6)); //save y3
+ psubw_r2r(mm2, mm0); // y7=z11 - z4
+
+ movq_r2m(mm5, *(dataptr+10)); //save y5
+ paddw_r2r(mm2, mm6); // y1=z11 + z4
+
+ movq_r2m(mm0, *(dataptr+14)); //save y7
+
+ /************************************************
+ * End of 1st 4 rows
+ ************************************************/
+
+ movq_m2r(*(dataptr+3), mm1); // load x1 /* stage 1 */
+ movq_r2r(mm7, mm0); // copy x0
+
+ movq_r2m(mm6, *(dataptr+2)); //save y1
+
+ movq_m2r(*(dataptr+5), mm2); // load x2 /* stage 1 */
+ movq_r2r(mm1, mm6); // copy x1
+
+ paddw_m2r(*(dataptr+15), mm0); // tmp00 = x0 + x7
+
+ movq_m2r(*(dataptr+7), mm3); // load x3 /* stage 1 */
+ movq_r2r(mm2, mm5); // copy x2
+
+ psubw_m2r(*(dataptr+15), mm7); // tmp07 = x0 - x7
+ movq_r2r(mm3, mm4); // copy x3
+
+ paddw_m2r(*(dataptr+13), mm1); // tmp01 = x1 + x6
+
+ movq_r2m(mm7, tmp7); // save tmp07
+ movq_r2r(mm0, mm7); // copy tmp00
+
+ psubw_m2r(*(dataptr+13), mm6); // tmp06 = x1 - x6
+
+ /* stage 2, Even Part */
+
+ paddw_m2r(*(dataptr+9), mm3); // tmp03 = x3 + x4
+
+ movq_r2m(mm6, tmp6); // save tmp07
+ movq_r2r(mm1, mm6); // copy tmp01
+
+ paddw_m2r(*(dataptr+11), mm2); // tmp02 = x2 + x5
+ paddw_r2r(mm3, mm0); // tmp10 = tmp00 + tmp03
+
+ psubw_r2r(mm3, mm7); // tmp13 = tmp00 - tmp03
+
+ psubw_m2r(*(dataptr+9), mm4); // tmp04 = x3 - x4
+ psubw_r2r(mm2, mm6); // tmp12 = tmp01 - tmp02
+
+ paddw_r2r(mm2, mm1); // tmp11 = tmp01 + tmp02
+
+ psubw_m2r(*(dataptr+11), mm5); // tmp05 = x2 - x5
+ paddw_r2r(mm7, mm6); // tmp12 + tmp13
+
+ /* stage 3, Even and stage 4 & 5 even */
+
+ movq_m2r(tmp6, mm2); // load tmp6
+ movq_r2r(mm0, mm3); // copy tmp10
+
+ psllw_i2r(2, mm6); // shift z1
+ paddw_r2r(mm1, mm0); // y0=tmp10 + tmp11
+
+ pmulhw_m2r(RTjpeg_C4, mm6); // z1
+ psubw_r2r(mm1, mm3); // y4=tmp10 - tmp11
+
+ movq_r2m(mm0, *(dataptr+1)); //save y0
+ movq_r2r(mm7, mm0); // copy tmp13
+
+ /* odd part */
+
+ movq_r2m(mm3, *(dataptr+9)); //save y4
+ paddw_r2r(mm5, mm4); // tmp10 = tmp4 + tmp5
+
+ movq_m2r(tmp7, mm3); // load tmp7
+ paddw_r2r(mm6, mm0); // tmp32 = tmp13 + z1
+
+ paddw_r2r(mm2, mm5); // tmp11 = tmp5 + tmp6
+ psubw_r2r(mm6, mm7); // tmp33 = tmp13 - z1
+
+ movq_r2m(mm0, *(dataptr+5)); //save y2
+ paddw_r2r(mm3, mm2); // tmp12 = tmp6 + tmp7
+
+ /* stage 4 */
+
+ movq_r2m(mm7, *(dataptr+13)); //save y6
+ movq_r2r(mm4, mm1); // copy tmp10
+
+ psubw_r2r(mm2, mm1); // tmp10 - tmp12
+ psllw_i2r(2, mm4); // shift tmp10
+
+ movq_m2r(RTjpeg_C2mC6, mm0); // load C2mC6
+ psllw_i2r(2, mm1); // shift (tmp10-tmp12)
+
+ pmulhw_m2r(RTjpeg_C6, mm1); // z5
+ psllw_i2r(2, mm5); // prepare for multiply
+
+ pmulhw_r2r(mm0, mm4); // multiply by converted real
+
+ /* stage 5 */
+
+ pmulhw_m2r(RTjpeg_C4, mm5); // z3
+ psllw_i2r(2, mm2); // prepare for multiply
+
+ pmulhw_m2r(RTjpeg_C2pC6, mm2); // multiply
+ movq_r2r(mm3, mm0); // copy tmp7
+
+ movq_m2r(*(dataptr+9), mm7); // m03:m02|m01:m00 - first line (line 4)and copy into mm7
+ paddw_r2r(mm1, mm4); // z2
+
+ paddw_r2r(mm5, mm0); // z11
+ psubw_r2r(mm5, mm3); // z13
+
+ /* stage 6 */
+
+ movq_r2r(mm3, mm5); // copy z13
+ paddw_r2r(mm1, mm2); // z4
+
+ movq_r2r(mm0, mm6); // copy z11
+ psubw_r2r(mm4, mm5); // y3
+
+ paddw_r2r(mm2, mm6); // y1
+ paddw_r2r(mm4, mm3); // y5
+
+ movq_r2m(mm5, *(dataptr+7)); //save y3
+ psubw_r2r(mm2, mm0); // yè=z11 - z4
+
+ movq_r2m(mm3, *(dataptr+11)); //save y5
+
+ movq_r2m(mm6, *(dataptr+3)); //save y1
+
+ movq_r2m(mm0, *(dataptr+15)); //save y7
+
+
+#endif
+}
+
+#define FIX_1_082392200 ((__s32) 277) /* FIX(1.082392200) */
+#define FIX_1_414213562 ((__s32) 362) /* FIX(1.414213562) */
+#define FIX_1_847759065 ((__s32) 473) /* FIX(1.847759065) */
+#define FIX_2_613125930 ((__s32) 669) /* FIX(2.613125930) */
+
+#define DESCALE(x) (__s16)( ((x)+4) >> 3)
+
+/* clip yuv to 16..235 (should be 16..240 for cr/cb but ... */
+
+#define RL(x) ((x)>235) ? 235 : (((x)<16) ? 16 : (x))
+#define MULTIPLY(var,const) (((__s32) ((var) * (const)) + 128)>>8)
+
+void RTjpeg_idct_init(void)
+{
+ int i;
+
+ for(i=0; i<64; i++)
+ {
+ RTjpeg_liqt[i]=((__u64)RTjpeg_liqt[i]*RTjpeg_aan_tab[i])>>32;
+ RTjpeg_ciqt[i]=((__u64)RTjpeg_ciqt[i]*RTjpeg_aan_tab[i])>>32;
+ }
+}
+
+void RTjpeg_idct(__u8 *odata, __s16 *data, int rskip)
+{
+#ifdef HAVE_LIBMMX
+
+static mmx_t fix_141 = (mmx_t)(long long)0x5a825a825a825a82LL;
+static mmx_t fix_184n261 = (mmx_t)(long long)0xcf04cf04cf04cf04LL;
+static mmx_t fix_184 = (mmx_t)(long long)0x7641764176417641LL;
+static mmx_t fix_n184 = (mmx_t)(long long)0x896f896f896f896fLL;
+static mmx_t fix_108n184 = (mmx_t)(long long)0xcf04cf04cf04cf04LL;
+
+ mmx_t workspace[64];
+ mmx_t *wsptr = workspace;
+ register mmx_t *dataptr = (mmx_t *)odata;
+ mmx_t *idata = (mmx_t *)data;
+
+ rskip = rskip>>3;
+/*
+ * Perform inverse DCT on one block of coefficients.
+ */
+
+ /* Odd part */
+
+ movq_m2r(*(idata+10), mm1); // load idata[DCTSIZE*5]
+
+ movq_m2r(*(idata+6), mm0); // load idata[DCTSIZE*3]
+
+ movq_m2r(*(idata+2), mm3); // load idata[DCTSIZE*1]
+
+ movq_r2r(mm1, mm2); // copy tmp6 /* phase 6 */
+
+ movq_m2r(*(idata+14), mm4); // load idata[DCTSIZE*7]
+
+ paddw_r2r(mm0, mm1); // z13 = tmp6 + tmp5;
+
+ psubw_r2r(mm0, mm2); // z10 = tmp6 - tmp5
+
+ psllw_i2r(2, mm2); // shift z10
+ movq_r2r(mm2, mm0); // copy z10
+
+ pmulhw_m2r(fix_184n261, mm2); // MULTIPLY( z12, FIX_1_847759065); /* 2*c2 */
+ movq_r2r(mm3, mm5); // copy tmp4
+
+ pmulhw_m2r(fix_n184, mm0); // MULTIPLY(z10, -FIX_1_847759065); /* 2*c2 */
+ paddw_r2r(mm4, mm3); // z11 = tmp4 + tmp7;
+
+ movq_r2r(mm3, mm6); // copy z11 /* phase 5 */
+ psubw_r2r(mm4, mm5); // z12 = tmp4 - tmp7;
+
+ psubw_r2r(mm1, mm6); // z11-z13
+ psllw_i2r(2, mm5); // shift z12
+
+ movq_m2r(*(idata+12), mm4); // load idata[DCTSIZE*6], even part
+ movq_r2r(mm5, mm7); // copy z12
+
+ pmulhw_m2r(fix_108n184, mm5); // MULT(z12, (FIX_1_08-FIX_1_84)) //- z5; /* 2*(c2-c6) */ even part
+ paddw_r2r(mm1, mm3); // tmp7 = z11 + z13;
+
+ //ok
+
+ /* Even part */
+ pmulhw_m2r(fix_184, mm7); // MULTIPLY(z10,(FIX_1_847759065 - FIX_2_613125930)) //+ z5; /* -2*(c2+c6) */
+ psllw_i2r(2, mm6);
+
+ movq_m2r(*(idata+4), mm1); // load idata[DCTSIZE*2]
+
+ paddw_r2r(mm5, mm0); // tmp10
+
+ paddw_r2r(mm7, mm2); // tmp12
+
+ pmulhw_m2r(fix_141, mm6); // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+ psubw_r2r(mm3, mm2); // tmp6 = tmp12 - tmp7
+
+ movq_r2r(mm1, mm5); // copy tmp1
+ paddw_r2r(mm4, mm1); // tmp13= tmp1 + tmp3; /* phases 5-3 */
+
+ psubw_r2r(mm4, mm5); // tmp1-tmp3
+ psubw_r2r(mm2, mm6); // tmp5 = tmp11 - tmp6;
+
+ movq_r2m(mm1, *(wsptr)); // save tmp13 in workspace
+ psllw_i2r(2, mm5); // shift tmp1-tmp3
+
+ movq_m2r(*(idata), mm7); // load idata[DCTSIZE*0]
+
+ pmulhw_m2r(fix_141, mm5); // MULTIPLY(tmp1 - tmp3, FIX_1_414213562)
+ paddw_r2r(mm6, mm0); // tmp4 = tmp10 + tmp5;
+
+ movq_m2r(*(idata+8), mm4); // load idata[DCTSIZE*4]
+
+ psubw_r2r(mm1, mm5); // tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+ movq_r2m(mm0, *(wsptr+4)); // save tmp4 in workspace
+ movq_r2r(mm7, mm1); // copy tmp0 /* phase 3 */
+
+ movq_r2m(mm5, *(wsptr+2)); // save tmp12 in workspace
+ psubw_r2r(mm4, mm1); // tmp11 = tmp0 - tmp2;
+
+ paddw_r2r(mm4, mm7); // tmp10 = tmp0 + tmp2;
+ movq_r2r(mm1, mm5); // copy tmp11
+
+ paddw_m2r(*(wsptr+2), mm1); // tmp1 = tmp11 + tmp12;
+ movq_r2r(mm7, mm4); // copy tmp10 /* phase 2 */
+
+ paddw_m2r(*(wsptr), mm7); // tmp0 = tmp10 + tmp13;
+
+ psubw_m2r(*(wsptr), mm4); // tmp3 = tmp10 - tmp13;
+ movq_r2r(mm7, mm0); // copy tmp0
+
+ psubw_m2r(*(wsptr+2), mm5); // tmp2 = tmp11 - tmp12;
+ paddw_r2r(mm3, mm7); // wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+
+ psubw_r2r(mm3, mm0); // wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+
+ movq_r2m(mm7, *(wsptr)); // wsptr[DCTSIZE*0]
+ movq_r2r(mm1, mm3); // copy tmp1
+
+ movq_r2m(mm0, *(wsptr+14)); // wsptr[DCTSIZE*7]
+ paddw_r2r(mm2, mm1); // wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+
+ psubw_r2r(mm2, mm3); // wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+
+ movq_r2m(mm1, *(wsptr+2)); // wsptr[DCTSIZE*1]
+ movq_r2r(mm4, mm1); // copy tmp3
+
+ movq_r2m(mm3, *(wsptr+12)); // wsptr[DCTSIZE*6]
+
+ paddw_m2r(*(wsptr+4), mm4); // wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+
+ psubw_m2r(*(wsptr+4), mm1); // wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+ movq_r2m(mm4, *(wsptr+8));
+ movq_r2r(mm5, mm7); // copy tmp2
+
+ paddw_r2r(mm6, mm5); // wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5)
+
+ movq_r2m(mm1, *(wsptr+6));
+ psubw_r2r(mm6, mm7); // wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+
+ movq_r2m(mm5, *(wsptr+4));
+
+ movq_r2m(mm7, *(wsptr+10));
+
+ //ok
+
+
+/*****************************************************************/
+
+ idata++;
+ wsptr++;
+
+/*****************************************************************/
+
+ movq_m2r(*(idata+10), mm1); // load idata[DCTSIZE*5]
+
+ movq_m2r(*(idata+6), mm0); // load idata[DCTSIZE*3]
+
+ movq_m2r(*(idata+2), mm3); // load idata[DCTSIZE*1]
+ movq_r2r(mm1, mm2); // copy tmp6 /* phase 6 */
+
+ movq_m2r(*(idata+14), mm4); // load idata[DCTSIZE*7]
+ paddw_r2r(mm0, mm1); // z13 = tmp6 + tmp5;
+
+ psubw_r2r(mm0, mm2); // z10 = tmp6 - tmp5
+
+ psllw_i2r(2, mm2); // shift z10
+ movq_r2r(mm2, mm0); // copy z10
+
+ pmulhw_m2r(fix_184n261, mm2); // MULTIPLY( z12, FIX_1_847759065); /* 2*c2 */
+ movq_r2r(mm3, mm5); // copy tmp4
+
+ pmulhw_m2r(fix_n184, mm0); // MULTIPLY(z10, -FIX_1_847759065); /* 2*c2 */
+ paddw_r2r(mm4, mm3); // z11 = tmp4 + tmp7;
+
+ movq_r2r(mm3, mm6); // copy z11 /* phase 5 */
+ psubw_r2r(mm4, mm5); // z12 = tmp4 - tmp7;
+
+ psubw_r2r(mm1, mm6); // z11-z13
+ psllw_i2r(2, mm5); // shift z12
+
+ movq_m2r(*(idata+12), mm4); // load idata[DCTSIZE*6], even part
+ movq_r2r(mm5, mm7); // copy z12
+
+ pmulhw_m2r(fix_108n184, mm5); // MULT(z12, (FIX_1_08-FIX_1_84)) //- z5; /* 2*(c2-c6) */ even part
+ paddw_r2r(mm1, mm3); // tmp7 = z11 + z13;
+
+ //ok
+
+ /* Even part */
+ pmulhw_m2r(fix_184, mm7); // MULTIPLY(z10,(FIX_1_847759065 - FIX_2_613125930)) //+ z5; /* -2*(c2+c6) */
+ psllw_i2r(2, mm6);
+
+ movq_m2r(*(idata+4), mm1); // load idata[DCTSIZE*2]
+
+ paddw_r2r(mm5, mm0); // tmp10
+
+ paddw_r2r(mm7, mm2); // tmp12
+
+ pmulhw_m2r(fix_141, mm6); // tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+ psubw_r2r(mm3, mm2); // tmp6 = tmp12 - tmp7
+
+ movq_r2r(mm1, mm5); // copy tmp1
+ paddw_r2r(mm4, mm1); // tmp13= tmp1 + tmp3; /* phases 5-3 */
+
+ psubw_r2r(mm4, mm5); // tmp1-tmp3
+ psubw_r2r(mm2, mm6); // tmp5 = tmp11 - tmp6;
+
+ movq_r2m(mm1, *(wsptr)); // save tmp13 in workspace
+ psllw_i2r(2, mm5); // shift tmp1-tmp3
+
+ movq_m2r(*(idata), mm7); // load idata[DCTSIZE*0]
+ paddw_r2r(mm6, mm0); // tmp4 = tmp10 + tmp5;
+
+ pmulhw_m2r(fix_141, mm5); // MULTIPLY(tmp1 - tmp3, FIX_1_414213562)
+
+ movq_m2r(*(idata+8), mm4); // load idata[DCTSIZE*4]
+
+ psubw_r2r(mm1, mm5); // tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+ movq_r2m(mm0, *(wsptr+4)); // save tmp4 in workspace
+ movq_r2r(mm7, mm1); // copy tmp0 /* phase 3 */
+
+ movq_r2m(mm5, *(wsptr+2)); // save tmp12 in workspace
+ psubw_r2r(mm4, mm1); // tmp11 = tmp0 - tmp2;
+
+ paddw_r2r(mm4, mm7); // tmp10 = tmp0 + tmp2;
+ movq_r2r(mm1, mm5); // copy tmp11
+
+ paddw_m2r(*(wsptr+2), mm1); // tmp1 = tmp11 + tmp12;
+ movq_r2r(mm7, mm4); // copy tmp10 /* phase 2 */
+
+ paddw_m2r(*(wsptr), mm7); // tmp0 = tmp10 + tmp13;
+
+ psubw_m2r(*(wsptr), mm4); // tmp3 = tmp10 - tmp13;
+ movq_r2r(mm7, mm0); // copy tmp0
+
+ psubw_m2r(*(wsptr+2), mm5); // tmp2 = tmp11 - tmp12;
+ paddw_r2r(mm3, mm7); // wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+
+ psubw_r2r(mm3, mm0); // wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+
+ movq_r2m(mm7, *(wsptr)); // wsptr[DCTSIZE*0]
+ movq_r2r(mm1, mm3); // copy tmp1
+
+ movq_r2m(mm0, *(wsptr+14)); // wsptr[DCTSIZE*7]
+ paddw_r2r(mm2, mm1); // wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+
+ psubw_r2r(mm2, mm3); // wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+
+ movq_r2m(mm1, *(wsptr+2)); // wsptr[DCTSIZE*1]
+ movq_r2r(mm4, mm1); // copy tmp3
+
+ movq_r2m(mm3, *(wsptr+12)); // wsptr[DCTSIZE*6]
+
+ paddw_m2r(*(wsptr+4), mm4); // wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+
+ psubw_m2r(*(wsptr+4), mm1); // wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+ movq_r2m(mm4, *(wsptr+8));
+ movq_r2r(mm5, mm7); // copy tmp2
+
+ paddw_r2r(mm6, mm5); // wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5)
+
+ movq_r2m(mm1, *(wsptr+6));
+ psubw_r2r(mm6, mm7); // wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+
+ movq_r2m(mm5, *(wsptr+4));
+
+ movq_r2m(mm7, *(wsptr+10));
+
+/*****************************************************************/
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+/*****************************************************************/
+ /* Even part */
+
+ wsptr--;
+
+// tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+// tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+// tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+// tmp14 = ((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6]);
+ movq_m2r(*(wsptr), mm0); // wsptr[0,0],[0,1],[0,2],[0,3]
+
+ movq_m2r(*(wsptr+1), mm1); // wsptr[0,4],[0,5],[0,6],[0,7]
+ movq_r2r(mm0, mm2);
+
+ movq_m2r(*(wsptr+2), mm3); // wsptr[1,0],[1,1],[1,2],[1,3]
+ paddw_r2r(mm1, mm0); // wsptr[0,tmp10],[xxx],[0,tmp13],[xxx]
+
+ movq_m2r(*(wsptr+3), mm4); // wsptr[1,4],[1,5],[1,6],[1,7]
+ psubw_r2r(mm1, mm2); // wsptr[0,tmp11],[xxx],[0,tmp14],[xxx]
+
+ movq_r2r(mm0, mm6);
+ movq_r2r(mm3, mm5);
+
+ paddw_r2r(mm4, mm3); // wsptr[1,tmp10],[xxx],[1,tmp13],[xxx]
+ movq_r2r(mm2, mm1);
+
+ psubw_r2r(mm4, mm5); // wsptr[1,tmp11],[xxx],[1,tmp14],[xxx]
+ punpcklwd_r2r(mm3, mm0); // wsptr[0,tmp10],[1,tmp10],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+7), mm7); // wsptr[3,4],[3,5],[3,6],[3,7]
+ punpckhwd_r2r(mm3, mm6); // wsptr[0,tmp13],[1,tmp13],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+4), mm3); // wsptr[2,0],[2,1],[2,2],[2,3]
+ punpckldq_r2r(mm6, mm0); // wsptr[0,tmp10],[1,tmp10],[0,tmp13],[1,tmp13]
+
+ punpcklwd_r2r(mm5, mm1); // wsptr[0,tmp11],[1,tmp11],[xxx],[xxx]
+ movq_r2r(mm3, mm4);
+
+ movq_m2r(*(wsptr+6), mm6); // wsptr[3,0],[3,1],[3,2],[3,3]
+ punpckhwd_r2r(mm5, mm2); // wsptr[0,tmp14],[1,tmp14],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+5), mm5); // wsptr[2,4],[2,5],[2,6],[2,7]
+ punpckldq_r2r(mm2, mm1); // wsptr[0,tmp11],[1,tmp11],[0,tmp14],[1,tmp14]
+
+
+ paddw_r2r(mm5, mm3); // wsptr[2,tmp10],[xxx],[2,tmp13],[xxx]
+ movq_r2r(mm6, mm2);
+
+ psubw_r2r(mm5, mm4); // wsptr[2,tmp11],[xxx],[2,tmp14],[xxx]
+ paddw_r2r(mm7, mm6); // wsptr[3,tmp10],[xxx],[3,tmp13],[xxx]
+
+ movq_r2r(mm3, mm5);
+ punpcklwd_r2r(mm6, mm3); // wsptr[2,tmp10],[3,tmp10],[xxx],[xxx]
+
+ psubw_r2r(mm7, mm2); // wsptr[3,tmp11],[xxx],[3,tmp14],[xxx]
+ punpckhwd_r2r(mm6, mm5); // wsptr[2,tmp13],[3,tmp13],[xxx],[xxx]
+
+ movq_r2r(mm4, mm7);
+ punpckldq_r2r(mm5, mm3); // wsptr[2,tmp10],[3,tmp10],[2,tmp13],[3,tmp13]
+
+ punpcklwd_r2r(mm2, mm4); // wsptr[2,tmp11],[3,tmp11],[xxx],[xxx]
+
+ punpckhwd_r2r(mm2, mm7); // wsptr[2,tmp14],[3,tmp14],[xxx],[xxx]
+
+ punpckldq_r2r(mm7, mm4); // wsptr[2,tmp11],[3,tmp11],[2,tmp14],[3,tmp14]
+ movq_r2r(mm1, mm6);
+
+ //ok
+
+// mm0 = ;wsptr[0,tmp10],[1,tmp10],[0,tmp13],[1,tmp13]
+// mm1 = ;wsptr[0,tmp11],[1,tmp11],[0,tmp14],[1,tmp14]
+
+
+ movq_r2r(mm0, mm2);
+ punpckhdq_r2r(mm4, mm6); // wsptr[0,tmp14],[1,tmp14],[2,tmp14],[3,tmp14]
+
+ punpckldq_r2r(mm4, mm1); // wsptr[0,tmp11],[1,tmp11],[2,tmp11],[3,tmp11]
+ psllw_i2r(2, mm6);
+
+ pmulhw_m2r(fix_141, mm6);
+ punpckldq_r2r(mm3, mm0); // wsptr[0,tmp10],[1,tmp10],[2,tmp10],[3,tmp10]
+
+ punpckhdq_r2r(mm3, mm2); // wsptr[0,tmp13],[1,tmp13],[2,tmp13],[3,tmp13]
+ movq_r2r(mm0, mm7);
+
+// tmp0 = tmp10 + tmp13;
+// tmp3 = tmp10 - tmp13;
+ paddw_r2r(mm2, mm0); // [0,tmp0],[1,tmp0],[2,tmp0],[3,tmp0]
+ psubw_r2r(mm2, mm7); // [0,tmp3],[1,tmp3],[2,tmp3],[3,tmp3]
+
+// tmp12 = MULTIPLY(tmp14, FIX_1_414213562) - tmp13;
+ psubw_r2r(mm2, mm6); // wsptr[0,tmp12],[1,tmp12],[2,tmp12],[3,tmp12]
+// tmp1 = tmp11 + tmp12;
+// tmp2 = tmp11 - tmp12;
+ movq_r2r(mm1, mm5);
+
+ //OK
+
+ /* Odd part */
+
+// z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+// z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+// z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+// z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+ movq_m2r(*(wsptr), mm3); // wsptr[0,0],[0,1],[0,2],[0,3]
+ paddw_r2r(mm6, mm1); // [0,tmp1],[1,tmp1],[2,tmp1],[3,tmp1]
+
+ movq_m2r(*(wsptr+1), mm4); // wsptr[0,4],[0,5],[0,6],[0,7]
+ psubw_r2r(mm6, mm5); // [0,tmp2],[1,tmp2],[2,tmp2],[3,tmp2]
+
+ movq_r2r(mm3, mm6);
+ punpckldq_r2r(mm4, mm3); // wsptr[0,0],[0,1],[0,4],[0,5]
+
+ punpckhdq_r2r(mm6, mm4); // wsptr[0,6],[0,7],[0,2],[0,3]
+ movq_r2r(mm3, mm2);
+
+//Save tmp0 and tmp1 in wsptr
+ movq_r2m(mm0, *(wsptr)); // save tmp0
+ paddw_r2r(mm4, mm2); // wsptr[xxx],[0,z11],[xxx],[0,z13]
+
+
+//Continue with z10 --- z13
+ movq_m2r(*(wsptr+2), mm6); // wsptr[1,0],[1,1],[1,2],[1,3]
+ psubw_r2r(mm4, mm3); // wsptr[xxx],[0,z12],[xxx],[0,z10]
+
+ movq_m2r(*(wsptr+3), mm0); // wsptr[1,4],[1,5],[1,6],[1,7]
+ movq_r2r(mm6, mm4);
+
+ movq_r2m(mm1, *(wsptr+1)); // save tmp1
+ punpckldq_r2r(mm0, mm6); // wsptr[1,0],[1,1],[1,4],[1,5]
+
+ punpckhdq_r2r(mm4, mm0); // wsptr[1,6],[1,7],[1,2],[1,3]
+ movq_r2r(mm6, mm1);
+
+//Save tmp2 and tmp3 in wsptr
+ paddw_r2r(mm0, mm6); // wsptr[xxx],[1,z11],[xxx],[1,z13]
+ movq_r2r(mm2, mm4);
+
+//Continue with z10 --- z13
+ movq_r2m(mm5, *(wsptr+2)); // save tmp2
+ punpcklwd_r2r(mm6, mm2); // wsptr[xxx],[xxx],[0,z11],[1,z11]
+
+ psubw_r2r(mm0, mm1); // wsptr[xxx],[1,z12],[xxx],[1,z10]
+ punpckhwd_r2r(mm6, mm4); // wsptr[xxx],[xxx],[0,z13],[1,z13]
+
+ movq_r2r(mm3, mm0);
+ punpcklwd_r2r(mm1, mm3); // wsptr[xxx],[xxx],[0,z12],[1,z12]
+
+ movq_r2m(mm7, *(wsptr+3)); // save tmp3
+ punpckhwd_r2r(mm1, mm0); // wsptr[xxx],[xxx],[0,z10],[1,z10]
+
+ movq_m2r(*(wsptr+4), mm6); // wsptr[2,0],[2,1],[2,2],[2,3]
+ punpckhdq_r2r(mm2, mm0); // wsptr[0,z10],[1,z10],[0,z11],[1,z11]
+
+ movq_m2r(*(wsptr+5), mm7); // wsptr[2,4],[2,5],[2,6],[2,7]
+ punpckhdq_r2r(mm4, mm3); // wsptr[0,z12],[1,z12],[0,z13],[1,z13]
+
+ movq_m2r(*(wsptr+6), mm1); // wsptr[3,0],[3,1],[3,2],[3,3]
+ movq_r2r(mm6, mm4);
+
+ punpckldq_r2r(mm7, mm6); // wsptr[2,0],[2,1],[2,4],[2,5]
+ movq_r2r(mm1, mm5);
+
+ punpckhdq_r2r(mm4, mm7); // wsptr[2,6],[2,7],[2,2],[2,3]
+ movq_r2r(mm6, mm2);
+
+ movq_m2r(*(wsptr+7), mm4); // wsptr[3,4],[3,5],[3,6],[3,7]
+ paddw_r2r(mm7, mm6); // wsptr[xxx],[2,z11],[xxx],[2,z13]
+
+ psubw_r2r(mm7, mm2); // wsptr[xxx],[2,z12],[xxx],[2,z10]
+ punpckldq_r2r(mm4, mm1); // wsptr[3,0],[3,1],[3,4],[3,5]
+
+ punpckhdq_r2r(mm5, mm4); // wsptr[3,6],[3,7],[3,2],[3,3]
+ movq_r2r(mm1, mm7);
+
+ paddw_r2r(mm4, mm1); // wsptr[xxx],[3,z11],[xxx],[3,z13]
+ psubw_r2r(mm4, mm7); // wsptr[xxx],[3,z12],[xxx],[3,z10]
+
+ movq_r2r(mm6, mm5);
+ punpcklwd_r2r(mm1, mm6); // wsptr[xxx],[xxx],[2,z11],[3,z11]
+
+ punpckhwd_r2r(mm1, mm5); // wsptr[xxx],[xxx],[2,z13],[3,z13]
+ movq_r2r(mm2, mm4);
+
+ punpcklwd_r2r(mm7, mm2); // wsptr[xxx],[xxx],[2,z12],[3,z12]
+
+ punpckhwd_r2r(mm7, mm4); // wsptr[xxx],[xxx],[2,z10],[3,z10]
+
+ punpckhdq_r2r(mm6, mm4); /// wsptr[2,z10],[3,z10],[2,z11],[3,z11]
+
+ punpckhdq_r2r(mm5, mm2); // wsptr[2,z12],[3,z12],[2,z13],[3,z13]
+ movq_r2r(mm0, mm5);
+
+ punpckldq_r2r(mm4, mm0); // wsptr[0,z10],[1,z10],[2,z10],[3,z10]
+
+ punpckhdq_r2r(mm4, mm5); // wsptr[0,z11],[1,z11],[2,z11],[3,z11]
+ movq_r2r(mm3, mm4);
+
+ punpckhdq_r2r(mm2, mm4); // wsptr[0,z13],[1,z13],[2,z13],[3,z13]
+ movq_r2r(mm5, mm1);
+
+ punpckldq_r2r(mm2, mm3); // wsptr[0,z12],[1,z12],[2,z12],[3,z12]
+// tmp7 = z11 + z13; /* phase 5 */
+// tmp8 = z11 - z13; /* phase 5 */
+ psubw_r2r(mm4, mm1); // tmp8
+
+ paddw_r2r(mm4, mm5); // tmp7
+// tmp21 = MULTIPLY(tmp8, FIX_1_414213562); /* 2*c4 */
+ psllw_i2r(2, mm1);
+
+ psllw_i2r(2, mm0);
+
+ pmulhw_m2r(fix_141, mm1); // tmp21
+// tmp20 = MULTIPLY(z12, (FIX_1_082392200- FIX_1_847759065)) /* 2*(c2-c6) */
+// + MULTIPLY(z10, - FIX_1_847759065); /* 2*c2 */
+ psllw_i2r(2, mm3);
+ movq_r2r(mm0, mm7);
+
+ pmulhw_m2r(fix_n184, mm7);
+ movq_r2r(mm3, mm6);
+
+ movq_m2r(*(wsptr), mm2); // tmp0,final1
+
+ pmulhw_m2r(fix_108n184, mm6);
+// tmp22 = MULTIPLY(z10,(FIX_1_847759065 - FIX_2_613125930)) /* -2*(c2+c6) */
+// + MULTIPLY(z12, FIX_1_847759065); /* 2*c2 */
+ movq_r2r(mm2, mm4); // final1
+
+ pmulhw_m2r(fix_184n261, mm0);
+ paddw_r2r(mm5, mm2); // tmp0+tmp7,final1
+
+ pmulhw_m2r(fix_184, mm3);
+ psubw_r2r(mm5, mm4); // tmp0-tmp7,final1
+
+// tmp6 = tmp22 - tmp7; /* phase 2 */
+ psraw_i2r(3, mm2); // outptr[0,0],[1,0],[2,0],[3,0],final1
+
+ paddw_r2r(mm6, mm7); // tmp20
+ psraw_i2r(3, mm4); // outptr[0,7],[1,7],[2,7],[3,7],final1
+
+ paddw_r2r(mm0, mm3); // tmp22
+
+// tmp5 = tmp21 - tmp6;
+ psubw_r2r(mm5, mm3); // tmp6
+
+// tmp4 = tmp20 + tmp5;
+ movq_m2r(*(wsptr+1), mm0); // tmp1,final2
+ psubw_r2r(mm3, mm1); // tmp5
+
+ movq_r2r(mm0, mm6); // final2
+ paddw_r2r(mm3, mm0); // tmp1+tmp6,final2
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+
+// outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+// & RANGE_MASK]; final1
+
+
+// outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+// & RANGE_MASK]; final2
+ psubw_r2r(mm3, mm6); // tmp1-tmp6,final2
+ psraw_i2r(3, mm0); // outptr[0,1],[1,1],[2,1],[3,1]
+
+ psraw_i2r(3, mm6); // outptr[0,6],[1,6],[2,6],[3,6]
+
+ packuswb_r2r(mm4, mm0); // out[0,1],[1,1],[2,1],[3,1],[0,7],[1,7],[2,7],[3,7]
+
+ movq_m2r(*(wsptr+2), mm5); // tmp2,final3
+ packuswb_r2r(mm6, mm2); // out[0,0],[1,0],[2,0],[3,0],[0,6],[1,6],[2,6],[3,6]
+
+// outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+// & RANGE_MASK]; final3
+ paddw_r2r(mm1, mm7); // tmp4
+ movq_r2r(mm5, mm3);
+
+ paddw_r2r(mm1, mm5); // tmp2+tmp5
+ psubw_r2r(mm1, mm3); // tmp2-tmp5
+
+ psraw_i2r(3, mm5); // outptr[0,2],[1,2],[2,2],[3,2]
+
+ movq_m2r(*(wsptr+3), mm4); // tmp3,final4
+ psraw_i2r(3, mm3); // outptr[0,5],[1,5],[2,5],[3,5]
+
+
+
+// outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+// & RANGE_MASK]; final4
+ movq_r2r(mm4, mm6);
+ paddw_r2r(mm7, mm4); // tmp3+tmp4
+
+ psubw_r2r(mm7, mm6); // tmp3-tmp4
+ psraw_i2r(3, mm4); // outptr[0,4],[1,4],[2,4],[3,4]
+
+ // mov ecx, [dataptr]
+
+ psraw_i2r(3, mm6); // outptr[0,3],[1,3],[2,3],[3,3]
+
+ packuswb_r2r(mm4, mm5); // out[0,2],[1,2],[2,2],[3,2],[0,4],[1,4],[2,4],[3,4]
+
+ packuswb_r2r(mm3, mm6); // out[0,3],[1,3],[2,3],[3,3],[0,5],[1,5],[2,5],[3,5]
+ movq_r2r(mm2, mm4);
+
+ movq_r2r(mm5, mm7);
+ punpcklbw_r2r(mm0, mm2); // out[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1]
+
+ punpckhbw_r2r(mm0, mm4); // out[0,6],[0,7],[1,6],[1,7],[2,6],[2,7],[3,6],[3,7]
+ movq_r2r(mm2, mm1);
+
+ punpcklbw_r2r(mm6, mm5); // out[0,2],[0,3],[1,2],[1,3],[2,2],[2,3],[3,2],[3,3]
+
+ // add dataptr, 4
+
+ punpckhbw_r2r(mm6, mm7); // out[0,4],[0,5],[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]
+
+ punpcklwd_r2r(mm5, mm2); // out[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3]
+
+ // add ecx, output_col
+
+ movq_r2r(mm7, mm6);
+ punpckhwd_r2r(mm5, mm1); // out[2,0],[2,1],[2,2],[2,3],[3,0],[3,1],[3,2],[3,3]
+
+ movq_r2r(mm2, mm0);
+ punpcklwd_r2r(mm4, mm6); // out[0,4],[0,5],[0,6],[0,7],[1,4],[1,5],[1,6],[1,7]
+
+ // mov idata, [dataptr]
+
+ punpckldq_r2r(mm6, mm2); // out[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7]
+
+ // add dataptr, 4
+
+ movq_r2r(mm1, mm3);
+
+ // add idata, output_col
+
+ punpckhwd_r2r(mm4, mm7); // out[2,4],[2,5],[2,6],[2,7],[3,4],[3,5],[3,6],[3,7]
+
+ movq_r2m(mm2, *(dataptr));
+
+ punpckhdq_r2r(mm6, mm0); // out[1,0],[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7]
+
+ dataptr += rskip;
+ movq_r2m(mm0, *(dataptr));
+
+ punpckldq_r2r(mm7, mm1); // out[2,0],[2,1],[2,2],[2,3],[2,4],[2,5],[2,6],[2,7]
+ punpckhdq_r2r(mm7, mm3); // out[3,0],[3,1],[3,2],[3,3],[3,4],[3,5],[3,6],[3,7]
+
+ dataptr += rskip;
+ movq_r2m(mm1, *(dataptr));
+
+ dataptr += rskip;
+ movq_r2m(mm3, *(dataptr));
+
+/*******************************************************************/
+
+ wsptr += 8;
+
+/*******************************************************************/
+
+// tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+// tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+// tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+// tmp14 = ((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6]);
+ movq_m2r(*(wsptr), mm0); // wsptr[0,0],[0,1],[0,2],[0,3]
+
+ movq_m2r(*(wsptr+1), mm1); // wsptr[0,4],[0,5],[0,6],[0,7]
+ movq_r2r(mm0, mm2);
+
+ movq_m2r(*(wsptr+2), mm3); // wsptr[1,0],[1,1],[1,2],[1,3]
+ paddw_r2r(mm1, mm0); // wsptr[0,tmp10],[xxx],[0,tmp13],[xxx]
+
+ movq_m2r(*(wsptr+3), mm4); // wsptr[1,4],[1,5],[1,6],[1,7]
+ psubw_r2r(mm1, mm2); // wsptr[0,tmp11],[xxx],[0,tmp14],[xxx]
+
+ movq_r2r(mm0, mm6);
+ movq_r2r(mm3, mm5);
+
+ paddw_r2r(mm4, mm3); // wsptr[1,tmp10],[xxx],[1,tmp13],[xxx]
+ movq_r2r(mm2, mm1);
+
+ psubw_r2r(mm4, mm5); // wsptr[1,tmp11],[xxx],[1,tmp14],[xxx]
+ punpcklwd_r2r(mm3, mm0); // wsptr[0,tmp10],[1,tmp10],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+7), mm7); // wsptr[3,4],[3,5],[3,6],[3,7]
+ punpckhwd_r2r(mm3, mm6); // wsptr[0,tmp13],[1,tmp13],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+4), mm3); // wsptr[2,0],[2,1],[2,2],[2,3]
+ punpckldq_r2r(mm6, mm0); // wsptr[0,tmp10],[1,tmp10],[0,tmp13],[1,tmp13]
+
+ punpcklwd_r2r(mm5, mm1); // wsptr[0,tmp11],[1,tmp11],[xxx],[xxx]
+ movq_r2r(mm3, mm4);
+
+ movq_m2r(*(wsptr+6), mm6); // wsptr[3,0],[3,1],[3,2],[3,3]
+ punpckhwd_r2r(mm5, mm2); // wsptr[0,tmp14],[1,tmp14],[xxx],[xxx]
+
+ movq_m2r(*(wsptr+5), mm5); // wsptr[2,4],[2,5],[2,6],[2,7]
+ punpckldq_r2r(mm2, mm1); // wsptr[0,tmp11],[1,tmp11],[0,tmp14],[1,tmp14]
+
+ paddw_r2r(mm5, mm3); // wsptr[2,tmp10],[xxx],[2,tmp13],[xxx]
+ movq_r2r(mm6, mm2);
+
+ psubw_r2r(mm5, mm4); // wsptr[2,tmp11],[xxx],[2,tmp14],[xxx]
+ paddw_r2r(mm7, mm6); // wsptr[3,tmp10],[xxx],[3,tmp13],[xxx]
+
+ movq_r2r(mm3, mm5);
+ punpcklwd_r2r(mm6, mm3); // wsptr[2,tmp10],[3,tmp10],[xxx],[xxx]
+
+ psubw_r2r(mm7, mm2); // wsptr[3,tmp11],[xxx],[3,tmp14],[xxx]
+ punpckhwd_r2r(mm6, mm5); // wsptr[2,tmp13],[3,tmp13],[xxx],[xxx]
+
+ movq_r2r(mm4, mm7);
+ punpckldq_r2r(mm5, mm3); // wsptr[2,tmp10],[3,tmp10],[2,tmp13],[3,tmp13]
+
+ punpcklwd_r2r(mm2, mm4); // wsptr[2,tmp11],[3,tmp11],[xxx],[xxx]
+
+ punpckhwd_r2r(mm2, mm7); // wsptr[2,tmp14],[3,tmp14],[xxx],[xxx]
+
+ punpckldq_r2r(mm7, mm4); // wsptr[2,tmp11],[3,tmp11],[2,tmp14],[3,tmp14]
+ movq_r2r(mm1, mm6);
+
+ //OK
+
+// mm0 = ;wsptr[0,tmp10],[1,tmp10],[0,tmp13],[1,tmp13]
+// mm1 = ;wsptr[0,tmp11],[1,tmp11],[0,tmp14],[1,tmp14]
+
+ movq_r2r(mm0, mm2);
+ punpckhdq_r2r(mm4, mm6); // wsptr[0,tmp14],[1,tmp14],[2,tmp14],[3,tmp14]
+
+ punpckldq_r2r(mm4, mm1); // wsptr[0,tmp11],[1,tmp11],[2,tmp11],[3,tmp11]
+ psllw_i2r(2, mm6);
+
+ pmulhw_m2r(fix_141, mm6);
+ punpckldq_r2r(mm3, mm0); // wsptr[0,tmp10],[1,tmp10],[2,tmp10],[3,tmp10]
+
+ punpckhdq_r2r(mm3, mm2); // wsptr[0,tmp13],[1,tmp13],[2,tmp13],[3,tmp13]
+ movq_r2r(mm0, mm7);
+
+// tmp0 = tmp10 + tmp13;
+// tmp3 = tmp10 - tmp13;
+ paddw_r2r(mm2, mm0); // [0,tmp0],[1,tmp0],[2,tmp0],[3,tmp0]
+ psubw_r2r(mm2, mm7); // [0,tmp3],[1,tmp3],[2,tmp3],[3,tmp3]
+
+// tmp12 = MULTIPLY(tmp14, FIX_1_414213562) - tmp13;
+ psubw_r2r(mm2, mm6); // wsptr[0,tmp12],[1,tmp12],[2,tmp12],[3,tmp12]
+// tmp1 = tmp11 + tmp12;
+// tmp2 = tmp11 - tmp12;
+ movq_r2r(mm1, mm5);
+
+ //OK
+
+
+ /* Odd part */
+
+// z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+// z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+// z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+// z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+ movq_m2r(*(wsptr), mm3); // wsptr[0,0],[0,1],[0,2],[0,3]
+ paddw_r2r(mm6, mm1); // [0,tmp1],[1,tmp1],[2,tmp1],[3,tmp1]
+
+ movq_m2r(*(wsptr+1), mm4); // wsptr[0,4],[0,5],[0,6],[0,7]
+ psubw_r2r(mm6, mm5); // [0,tmp2],[1,tmp2],[2,tmp2],[3,tmp2]
+
+ movq_r2r(mm3, mm6);
+ punpckldq_r2r(mm4, mm3); // wsptr[0,0],[0,1],[0,4],[0,5]
+
+ punpckhdq_r2r(mm6, mm4); // wsptr[0,6],[0,7],[0,2],[0,3]
+ movq_r2r(mm3, mm2);
+
+//Save tmp0 and tmp1 in wsptr
+ movq_r2m(mm0, *(wsptr)); // save tmp0
+ paddw_r2r(mm4, mm2); // wsptr[xxx],[0,z11],[xxx],[0,z13]
+
+
+//Continue with z10 --- z13
+ movq_m2r(*(wsptr+2), mm6); // wsptr[1,0],[1,1],[1,2],[1,3]
+ psubw_r2r(mm4, mm3); // wsptr[xxx],[0,z12],[xxx],[0,z10]
+
+ movq_m2r(*(wsptr+3), mm0); // wsptr[1,4],[1,5],[1,6],[1,7]
+ movq_r2r(mm6, mm4);
+
+ movq_r2m(mm1, *(wsptr+1)); // save tmp1
+ punpckldq_r2r(mm0, mm6); // wsptr[1,0],[1,1],[1,4],[1,5]
+
+ punpckhdq_r2r(mm4, mm0); // wsptr[1,6],[1,7],[1,2],[1,3]
+ movq_r2r(mm6, mm1);
+
+//Save tmp2 and tmp3 in wsptr
+ paddw_r2r(mm0, mm6); // wsptr[xxx],[1,z11],[xxx],[1,z13]
+ movq_r2r(mm2, mm4);
+
+//Continue with z10 --- z13
+ movq_r2m(mm5, *(wsptr+2)); // save tmp2
+ punpcklwd_r2r(mm6, mm2); // wsptr[xxx],[xxx],[0,z11],[1,z11]
+
+ psubw_r2r(mm0, mm1); // wsptr[xxx],[1,z12],[xxx],[1,z10]
+ punpckhwd_r2r(mm6, mm4); // wsptr[xxx],[xxx],[0,z13],[1,z13]
+
+ movq_r2r(mm3, mm0);
+ punpcklwd_r2r(mm1, mm3); // wsptr[xxx],[xxx],[0,z12],[1,z12]
+
+ movq_r2m(mm7, *(wsptr+3)); // save tmp3
+ punpckhwd_r2r(mm1, mm0); // wsptr[xxx],[xxx],[0,z10],[1,z10]
+
+ movq_m2r(*(wsptr+4), mm6); // wsptr[2,0],[2,1],[2,2],[2,3]
+ punpckhdq_r2r(mm2, mm0); // wsptr[0,z10],[1,z10],[0,z11],[1,z11]
+
+ movq_m2r(*(wsptr+5), mm7); // wsptr[2,4],[2,5],[2,6],[2,7]
+ punpckhdq_r2r(mm4, mm3); // wsptr[0,z12],[1,z12],[0,z13],[1,z13]
+
+ movq_m2r(*(wsptr+6), mm1); // wsptr[3,0],[3,1],[3,2],[3,3]
+ movq_r2r(mm6, mm4);
+
+ punpckldq_r2r(mm7, mm6); // wsptr[2,0],[2,1],[2,4],[2,5]
+ movq_r2r(mm1, mm5);
+
+ punpckhdq_r2r(mm4, mm7); // wsptr[2,6],[2,7],[2,2],[2,3]
+ movq_r2r(mm6, mm2);
+
+ movq_m2r(*(wsptr+7), mm4); // wsptr[3,4],[3,5],[3,6],[3,7]
+ paddw_r2r(mm7, mm6); // wsptr[xxx],[2,z11],[xxx],[2,z13]
+
+ psubw_r2r(mm7, mm2); // wsptr[xxx],[2,z12],[xxx],[2,z10]
+ punpckldq_r2r(mm4, mm1); // wsptr[3,0],[3,1],[3,4],[3,5]
+
+ punpckhdq_r2r(mm5, mm4); // wsptr[3,6],[3,7],[3,2],[3,3]
+ movq_r2r(mm1, mm7);
+
+ paddw_r2r(mm4, mm1); // wsptr[xxx],[3,z11],[xxx],[3,z13]
+ psubw_r2r(mm4, mm7); // wsptr[xxx],[3,z12],[xxx],[3,z10]
+
+ movq_r2r(mm6, mm5);
+ punpcklwd_r2r(mm1, mm6); // wsptr[xxx],[xxx],[2,z11],[3,z11]
+
+ punpckhwd_r2r(mm1, mm5); // wsptr[xxx],[xxx],[2,z13],[3,z13]
+ movq_r2r(mm2, mm4);
+
+ punpcklwd_r2r(mm7, mm2); // wsptr[xxx],[xxx],[2,z12],[3,z12]
+
+ punpckhwd_r2r(mm7, mm4); // wsptr[xxx],[xxx],[2,z10],[3,z10]
+
+ punpckhdq_r2r(mm6, mm4); // wsptr[2,z10],[3,z10],[2,z11],[3,z11]
+
+ punpckhdq_r2r(mm5, mm2); // wsptr[2,z12],[3,z12],[2,z13],[3,z13]
+ movq_r2r(mm0, mm5);
+
+ punpckldq_r2r(mm4, mm0); // wsptr[0,z10],[1,z10],[2,z10],[3,z10]
+
+ punpckhdq_r2r(mm4, mm5); // wsptr[0,z11],[1,z11],[2,z11],[3,z11]
+ movq_r2r(mm3, mm4);
+
+ punpckhdq_r2r(mm2, mm4); // wsptr[0,z13],[1,z13],[2,z13],[3,z13]
+ movq_r2r(mm5, mm1);
+
+ punpckldq_r2r(mm2, mm3); // wsptr[0,z12],[1,z12],[2,z12],[3,z12]
+// tmp7 = z11 + z13; /* phase 5 */
+// tmp8 = z11 - z13; /* phase 5 */
+ psubw_r2r(mm4, mm1); // tmp8
+
+ paddw_r2r(mm4, mm5); // tmp7
+// tmp21 = MULTIPLY(tmp8, FIX_1_414213562); /* 2*c4 */
+ psllw_i2r(2, mm1);
+
+ psllw_i2r(2, mm0);
+
+ pmulhw_m2r(fix_141, mm1); // tmp21
+// tmp20 = MULTIPLY(z12, (FIX_1_082392200- FIX_1_847759065)) /* 2*(c2-c6) */
+// + MULTIPLY(z10, - FIX_1_847759065); /* 2*c2 */
+ psllw_i2r(2, mm3);
+ movq_r2r(mm0, mm7);
+
+ pmulhw_m2r(fix_n184, mm7);
+ movq_r2r(mm3, mm6);
+
+ movq_m2r(*(wsptr), mm2); // tmp0,final1
+
+ pmulhw_m2r(fix_108n184, mm6);
+// tmp22 = MULTIPLY(z10,(FIX_1_847759065 - FIX_2_613125930)) /* -2*(c2+c6) */
+// + MULTIPLY(z12, FIX_1_847759065); /* 2*c2 */
+ movq_r2r(mm2, mm4); // final1
+
+ pmulhw_m2r(fix_184n261, mm0);
+ paddw_r2r(mm5, mm2); // tmp0+tmp7,final1
+
+ pmulhw_m2r(fix_184, mm3);
+ psubw_r2r(mm5, mm4); // tmp0-tmp7,final1
+
+// tmp6 = tmp22 - tmp7; /* phase 2 */
+ psraw_i2r(3, mm2); // outptr[0,0],[1,0],[2,0],[3,0],final1
+
+ paddw_r2r(mm6, mm7); // tmp20
+ psraw_i2r(3, mm4); // outptr[0,7],[1,7],[2,7],[3,7],final1
+
+ paddw_r2r(mm0, mm3); // tmp22
+
+// tmp5 = tmp21 - tmp6;
+ psubw_r2r(mm5, mm3); // tmp6
+
+// tmp4 = tmp20 + tmp5;
+ movq_m2r(*(wsptr+1), mm0); // tmp1,final2
+ psubw_r2r(mm3, mm1); // tmp5
+
+ movq_r2r(mm0, mm6); // final2
+ paddw_r2r(mm3, mm0); // tmp1+tmp6,final2
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+// outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+// & RANGE_MASK]; final1
+
+
+// outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+// & RANGE_MASK]; final2
+ psubw_r2r(mm3, mm6); // tmp1-tmp6,final2
+ psraw_i2r(3, mm0); // outptr[0,1],[1,1],[2,1],[3,1]
+
+ psraw_i2r(3, mm6); // outptr[0,6],[1,6],[2,6],[3,6]
+
+ packuswb_r2r(mm4, mm0); // out[0,1],[1,1],[2,1],[3,1],[0,7],[1,7],[2,7],[3,7]
+
+ movq_m2r(*(wsptr+2), mm5); // tmp2,final3
+ packuswb_r2r(mm6, mm2); // out[0,0],[1,0],[2,0],[3,0],[0,6],[1,6],[2,6],[3,6]
+
+// outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+// & RANGE_MASK]; final3
+ paddw_r2r(mm1, mm7); // tmp4
+ movq_r2r(mm5, mm3);
+
+ paddw_r2r(mm1, mm5); // tmp2+tmp5
+ psubw_r2r(mm1, mm3); // tmp2-tmp5
+
+ psraw_i2r(3, mm5); // outptr[0,2],[1,2],[2,2],[3,2]
+
+ movq_m2r(*(wsptr+3), mm4); // tmp3,final4
+ psraw_i2r(3, mm3); // outptr[0,5],[1,5],[2,5],[3,5]
+
+
+
+// outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+// & RANGE_MASK];
+// outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+// & RANGE_MASK]; final4
+ movq_r2r(mm4, mm6);
+ paddw_r2r(mm7, mm4); // tmp3+tmp4
+
+ psubw_r2r(mm7, mm6); // tmp3-tmp4
+ psraw_i2r(3, mm4); // outptr[0,4],[1,4],[2,4],[3,4]
+
+ psraw_i2r(3, mm6); // outptr[0,3],[1,3],[2,3],[3,3]
+
+ /*
+ movq_r2m(mm4, *dummy);
+ fprintf(stderr, "3-4 %016llx\n", dummy);
+ movq_r2m(mm4, *dummy);
+ fprintf(stderr, "3+4 %016llx\n", dummy);
+ */
+
+
+ packuswb_r2r(mm4, mm5); // out[0,2],[1,2],[2,2],[3,2],[0,4],[1,4],[2,4],[3,4]
+
+ packuswb_r2r(mm3, mm6); // out[0,3],[1,3],[2,3],[3,3],[0,5],[1,5],[2,5],[3,5]
+ movq_r2r(mm2, mm4);
+
+ movq_r2r(mm5, mm7);
+ punpcklbw_r2r(mm0, mm2); // out[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1]
+
+ punpckhbw_r2r(mm0, mm4); // out[0,6],[0,7],[1,6],[1,7],[2,6],[2,7],[3,6],[3,7]
+ movq_r2r(mm2, mm1);
+
+ punpcklbw_r2r(mm6, mm5); // out[0,2],[0,3],[1,2],[1,3],[2,2],[2,3],[3,2],[3,3]
+
+ punpckhbw_r2r(mm6, mm7); // out[0,4],[0,5],[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]
+
+ punpcklwd_r2r(mm5, mm2); // out[0,0],[0,1],[0,2],[0,3],[1,0],[1,1],[1,2],[1,3]
+
+ movq_r2r(mm7, mm6);
+ punpckhwd_r2r(mm5, mm1); // out[2,0],[2,1],[2,2],[2,3],[3,0],[3,1],[3,2],[3,3]
+
+ movq_r2r(mm2, mm0);
+ punpcklwd_r2r(mm4, mm6); // out[0,4],[0,5],[0,6],[0,7],[1,4],[1,5],[1,6],[1,7]
+
+ punpckldq_r2r(mm6, mm2); // out[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7]
+
+ movq_r2r(mm1, mm3);
+
+ punpckhwd_r2r(mm4, mm7); // out[2,4],[2,5],[2,6],[2,7],[3,4],[3,5],[3,6],[3,7]
+
+ dataptr += rskip;
+ movq_r2m(mm2, *(dataptr));
+
+ punpckhdq_r2r(mm6, mm0); // out[1,0],[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7]
+
+ dataptr += rskip;
+ movq_r2m(mm0, *(dataptr));
+
+ punpckldq_r2r(mm7, mm1); // out[2,0],[2,1],[2,2],[2,3],[2,4],[2,5],[2,6],[2,7]
+
+ punpckhdq_r2r(mm7, mm3); // out[3,0],[3,1],[3,2],[3,3],[3,4],[3,5],[3,6],[3,7]
+
+ dataptr += rskip;
+ movq_r2m(mm1, *(dataptr));
+
+ dataptr += rskip;
+ movq_r2m(mm3, *(dataptr));
+
+#else
+ __s32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ __s32 tmp10, tmp11, tmp12, tmp13;
+ __s32 z5, z10, z11, z12, z13;
+ __s16 *inptr;
+ __s32 *wsptr;
+ __u8 *outptr;
+ int ctr;
+ __s32 dcval;
+ __s32 workspace[64];
+
+ inptr = data;
+ wsptr = workspace;
+ for (ctr = 8; ctr > 0; ctr--) {
+
+ if ((inptr[8] | inptr[16] | inptr[24] |
+ inptr[32] | inptr[40] | inptr[48] | inptr[56]) == 0) {
+ dcval = inptr[0];
+ wsptr[0] = dcval;
+ wsptr[8] = dcval;
+ wsptr[16] = dcval;
+ wsptr[24] = dcval;
+ wsptr[32] = dcval;
+ wsptr[40] = dcval;
+ wsptr[48] = dcval;
+ wsptr[56] = dcval;
+
+ inptr++;
+ wsptr++;
+ continue;
+ }
+
+ tmp0 = inptr[0];
+ tmp1 = inptr[16];
+ tmp2 = inptr[32];
+ tmp3 = inptr[48];
+
+ tmp10 = tmp0 + tmp2;
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3;
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ tmp4 = inptr[8];
+ tmp5 = inptr[24];
+ tmp6 = inptr[40];
+ tmp7 = inptr[56];
+
+ z13 = tmp6 + tmp5;
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13;
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562);
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065);
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5;
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5;
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[0] = (__s32) (tmp0 + tmp7);
+ wsptr[56] = (__s32) (tmp0 - tmp7);
+ wsptr[8] = (__s32) (tmp1 + tmp6);
+ wsptr[48] = (__s32) (tmp1 - tmp6);
+ wsptr[16] = (__s32) (tmp2 + tmp5);
+ wsptr[40] = (__s32) (tmp2 - tmp5);
+ wsptr[32] = (__s32) (tmp3 + tmp4);
+ wsptr[24] = (__s32) (tmp3 - tmp4);
+
+ inptr++;
+ wsptr++;
+ }
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++) {
+ outptr = &(odata[ctr*rskip]);
+
+ tmp10 = wsptr[0] + wsptr[4];
+ tmp11 = wsptr[0] - wsptr[4];
+
+ tmp13 = wsptr[2] + wsptr[6];
+ tmp12 = MULTIPLY(wsptr[2] - wsptr[6], FIX_1_414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562);
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065);
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5;
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5;
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ outptr[0] = RL(DESCALE(tmp0 + tmp7));
+ outptr[7] = RL(DESCALE(tmp0 - tmp7));
+ outptr[1] = RL(DESCALE(tmp1 + tmp6));
+ outptr[6] = RL(DESCALE(tmp1 - tmp6));
+ outptr[2] = RL(DESCALE(tmp2 + tmp5));
+ outptr[5] = RL(DESCALE(tmp2 - tmp5));
+ outptr[4] = RL(DESCALE(tmp3 + tmp4));
+ outptr[3] = RL(DESCALE(tmp3 - tmp4));
+
+ wsptr += 8;
+ }
+#endif
+}
+/*
+
+Main Routines
+
+This file contains most of the initialisation and control functions
+
+(C) Justin Schoeman 1998
+
+*/
+
+/*
+
+Private function
+
+Initialise all the cache-aliged data blocks
+
+*/
+
+void RTjpeg_init_data(void)
+{
+ unsigned long dptr;
+
+ dptr=(unsigned long)&(RTjpeg_alldata[0]);
+ dptr+=32;
+ dptr=dptr>>5;
+ dptr=dptr<<5; /* cache align data */
+
+ RTjpeg_block=(__s16 *)dptr;
+ dptr+=sizeof(__s16)*64;
+ RTjpeg_lqt=(__s32 *)dptr;
+ dptr+=sizeof(__s32)*64;
+ RTjpeg_cqt=(__s32 *)dptr;
+ dptr+=sizeof(__s32)*64;
+ RTjpeg_liqt=(__u32 *)dptr;
+ dptr+=sizeof(__u32)*64;
+ RTjpeg_ciqt=(__u32 *)dptr;
+}
+
+/*
+
+External Function
+
+Re-set quality factor
+
+Input: buf -> pointer to 128 ints for quant values store to pass back to
+ init_decompress.
+ Q -> quality factor (192=best, 32=worst)
+*/
+
+void RTjpeg_init_Q(__u8 Q)
+{
+ int i;
+ __u64 qual;
+
+ qual=(__u64)Q<<(32-7); /* 32 bit FP, 255=2, 0=0 */
+
+ for(i=0; i<64; i++)
+ {
+ RTjpeg_lqt[i]=(__s32)((qual/((__u64)RTjpeg_lum_quant_tbl[i]<<16))>>3);
+ if(RTjpeg_lqt[i]==0)RTjpeg_lqt[i]=1;
+ RTjpeg_cqt[i]=(__s32)((qual/((__u64)RTjpeg_chrom_quant_tbl[i]<<16))>>3);
+ if(RTjpeg_cqt[i]==0)RTjpeg_cqt[i]=1;
+ RTjpeg_liqt[i]=(1<<16)/(RTjpeg_lqt[i]<<3);
+ RTjpeg_ciqt[i]=(1<<16)/(RTjpeg_cqt[i]<<3);
+ RTjpeg_lqt[i]=((1<<16)/RTjpeg_liqt[i])>>3;
+ RTjpeg_cqt[i]=((1<<16)/RTjpeg_ciqt[i])>>3;
+ }
+
+ RTjpeg_lb8=0;
+ while(RTjpeg_liqt[RTjpeg_ZZ[++RTjpeg_lb8]]<=8);
+ RTjpeg_lb8--;
+ RTjpeg_cb8=0;
+ while(RTjpeg_ciqt[RTjpeg_ZZ[++RTjpeg_cb8]]<=8);
+ RTjpeg_cb8--;
+
+ RTjpeg_dct_init();
+ RTjpeg_idct_init();
+ RTjpeg_quant_init();
+}
+
+/*
+
+External Function
+
+Initialise compression.
+
+Input: buf -> pointer to 128 ints for quant values store to pass back to
+ init_decompress.
+ width -> width of image
+ height -> height of image
+ Q -> quality factor (192=best, 32=worst)
+
+*/
+
+void RTjpeg_init_compress(__u32 *buf, int width, int height, __u8 Q)
+{
+ int i;
+ __u64 qual;
+
+ RTjpeg_init_data();
+
+ RTjpeg_width=width;
+ RTjpeg_height=height;
+ RTjpeg_Ywidth = RTjpeg_width>>3;
+ RTjpeg_Ysize=width * height;
+ RTjpeg_Cwidth = RTjpeg_width>>4;
+ RTjpeg_Csize= (width>>1) * height;
+
+ qual=(__u64)Q<<(32-7); /* 32 bit FP, 255=2, 0=0 */
+
+ for(i=0; i<64; i++)
+ {
+ RTjpeg_lqt[i]=(__s32)((qual/((__u64)RTjpeg_lum_quant_tbl[i]<<16))>>3);
+ if(RTjpeg_lqt[i]==0)RTjpeg_lqt[i]=1;
+ RTjpeg_cqt[i]=(__s32)((qual/((__u64)RTjpeg_chrom_quant_tbl[i]<<16))>>3);
+ if(RTjpeg_cqt[i]==0)RTjpeg_cqt[i]=1;
+ RTjpeg_liqt[i]=(1<<16)/(RTjpeg_lqt[i]<<3);
+ RTjpeg_ciqt[i]=(1<<16)/(RTjpeg_cqt[i]<<3);
+ RTjpeg_lqt[i]=((1<<16)/RTjpeg_liqt[i])>>3;
+ RTjpeg_cqt[i]=((1<<16)/RTjpeg_ciqt[i])>>3;
+ }
+
+ RTjpeg_lb8=0;
+ while(RTjpeg_liqt[RTjpeg_ZZ[++RTjpeg_lb8]]<=8);
+ RTjpeg_lb8--;
+ RTjpeg_cb8=0;
+ while(RTjpeg_ciqt[RTjpeg_ZZ[++RTjpeg_cb8]]<=8);
+ RTjpeg_cb8--;
+
+ RTjpeg_dct_init();
+ RTjpeg_quant_init();
+
+ for(i=0; i<64; i++)
+ buf[i]=RTjpeg_liqt[i];
+ for(i=0; i<64; i++)
+ buf[64+i]=RTjpeg_ciqt[i];
+}
+
+void RTjpeg_init_decompress(__u32 *buf, int width, int height)
+{
+ int i;
+
+ RTjpeg_init_data();
+
+ RTjpeg_width=width;
+ RTjpeg_height=height;
+ RTjpeg_Ywidth = RTjpeg_width>>3;
+ RTjpeg_Ysize=width * height;
+ RTjpeg_Cwidth = RTjpeg_width>>4;
+ RTjpeg_Csize= (width>>1) * height;
+
+ for(i=0; i<64; i++)
+ {
+ RTjpeg_liqt[i]=buf[i];
+ RTjpeg_ciqt[i]=buf[i+64];
+ }
+
+ RTjpeg_lb8=0;
+ while(RTjpeg_liqt[RTjpeg_ZZ[++RTjpeg_lb8]]<=8);
+ RTjpeg_lb8--;
+ RTjpeg_cb8=0;
+ while(RTjpeg_ciqt[RTjpeg_ZZ[++RTjpeg_cb8]]<=8);
+ RTjpeg_cb8--;
+
+ RTjpeg_idct_init();
+
+// RTjpeg_color_init();
+}
+
+int RTjpeg_compressYUV420(__s8 *sp, unsigned char *bp)
+{
+ __s8 * sb;
+ register __s8 * bp1 = bp + (RTjpeg_width<<3);
+ register __s8 * bp2 = bp + RTjpeg_Ysize;
+ register __s8 * bp3 = bp2 + (RTjpeg_Csize>>1);
+ register int i, j, k;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ sb=sp;
+/* Y */
+ for(i=RTjpeg_height>>1; i; i-=8)
+ {
+ for(j=0, k=0; j<RTjpeg_width; j+=16, k+=8)
+ {
+ RTjpeg_dctY(bp+j, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp+j+8, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp1+j, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp1+j+8, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp2+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+
+ RTjpeg_dctY(bp3+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+
+ }
+ bp+=RTjpeg_width<<4;
+ bp1+=RTjpeg_width<<4;
+ bp2+=RTjpeg_width<<2;
+ bp3+=RTjpeg_width<<2;
+
+ }
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ return (sp-sb);
+}
+
+int RTjpeg_compressYUV422(__s8 *sp, unsigned char *bp)
+{
+ __s8 * sb;
+ register __s8 * bp2 = bp + RTjpeg_Ysize;
+ register __s8 * bp3 = bp2 + RTjpeg_Csize;
+ register int i, j, k;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ sb=sp;
+/* Y */
+ for(i=RTjpeg_height; i; i-=8)
+ {
+ for(j=0, k=0; j<RTjpeg_width; j+=16, k+=8)
+ {
+ RTjpeg_dctY(bp+j, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp+j+8, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+
+ RTjpeg_dctY(bp2+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+
+ RTjpeg_dctY(bp3+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+
+ }
+ bp+=RTjpeg_width<<3;
+ bp2+=RTjpeg_width<<2;
+ bp3+=RTjpeg_width<<2;
+
+ }
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ return (sp-sb);
+}
+
+int RTjpeg_compress8(__s8 *sp, unsigned char *bp)
+{
+ __s8 * sb;
+ int i, j;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+
+ sb=sp;
+/* Y */
+ for(i=0; i<RTjpeg_height; i+=8)
+ {
+ for(j=0; j<RTjpeg_width; j+=8)
+ {
+ RTjpeg_dctY(bp+j, RTjpeg_block, RTjpeg_width);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+ }
+ bp+=RTjpeg_width;
+ }
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ return (sp-sb);
+}
+
+void RTjpeg_decompressYUV422(__s8 *sp, __u8 *bp)
+{
+ register __s8 * bp2 = bp + RTjpeg_Ysize;
+ register __s8 * bp3 = bp2 + (RTjpeg_Csize);
+ int i, j,k;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+
+/* Y */
+ for(i=RTjpeg_height; i; i-=8)
+ {
+ for(k=0, j=0; j<RTjpeg_width; j+=16, k+=8) {
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp+j, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp+j+8, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_cb8, RTjpeg_ciqt);
+ RTjpeg_idct(bp2+k, RTjpeg_block, RTjpeg_width>>1);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_cb8, RTjpeg_ciqt);
+ RTjpeg_idct(bp3+k, RTjpeg_block, RTjpeg_width>>1);
+ }
+ }
+ bp+=RTjpeg_width<<3;
+ bp2+=RTjpeg_width<<2;
+ bp3+=RTjpeg_width<<2;
+ }
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+}
+
+void RTjpeg_decompressYUV420(__s8 *sp, __u8 *bp)
+{
+ register __s8 * bp1 = bp + (RTjpeg_width<<3);
+ register __s8 * bp2 = bp + RTjpeg_Ysize;
+ register __s8 * bp3 = bp2 + (RTjpeg_Csize>>1);
+ int i, j,k;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+
+/* Y */
+ for(i=RTjpeg_height>>1; i; i-=8)
+ {
+ for(k=0, j=0; j<RTjpeg_width; j+=16, k+=8) {
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp+j, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp+j+8, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp1+j, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp1+j+8, RTjpeg_block, RTjpeg_width);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_cb8, RTjpeg_ciqt);
+ RTjpeg_idct(bp2+k, RTjpeg_block, RTjpeg_width>>1);
+ }
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_cb8, RTjpeg_ciqt);
+ RTjpeg_idct(bp3+k, RTjpeg_block, RTjpeg_width>>1);
+ }
+ }
+ bp+=RTjpeg_width<<4;
+ bp1+=RTjpeg_width<<4;
+ bp2+=RTjpeg_width<<2;
+ bp3+=RTjpeg_width<<2;
+ }
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+}
+
+void RTjpeg_decompress8(__s8 *sp, __u8 *bp)
+{
+ int i, j;
+
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+
+/* Y */
+ for(i=0; i<RTjpeg_height; i+=8)
+ {
+ for(j=0; j<RTjpeg_width; j+=8)
+ if(*sp==-1)sp++;
+ else
+ {
+ sp+=RTjpeg_s2b(RTjpeg_block, sp, RTjpeg_lb8, RTjpeg_liqt);
+ RTjpeg_idct(bp+j, RTjpeg_block, RTjpeg_width);
+ }
+ bp+=RTjpeg_width<<3;
+ }
+}
+
+/*
+External Function
+
+Initialise additional data structures for motion compensation
+
+*/
+
+void RTjpeg_init_mcompress(void)
+{
+ unsigned long tmp;
+
+ if(!RTjpeg_old)
+ {
+ RTjpeg_old=malloc((4*RTjpeg_width*RTjpeg_height)+32);
+ tmp=(unsigned long)RTjpeg_old;
+ tmp+=32;
+ tmp=tmp>>5;
+ RTjpeg_old=(__s16 *)(tmp<<5);
+ }
+ if (!RTjpeg_old)
+ {
+ fprintf(stderr, "RTjpeg: Could not allocate memory\n");
+ exit(-1);
+ }
+ bzero(RTjpeg_old, ((4*RTjpeg_width*RTjpeg_height)));
+}
+
+#ifdef HAVE_LIBMMX
+
+int RTjpeg_bcomp(__s16 *old, mmx_t *mask)
+{
+ int i;
+ mmx_t *mold=(mmx_t *)old;
+ mmx_t *mblock=(mmx_t *)RTjpeg_block;
+ mmx_t result;
+ static mmx_t neg=(mmx_t)(unsigned long long)0xffffffffffffffffULL;
+
+ movq_m2r(*mask, mm7);
+ movq_m2r(neg, mm6);
+ pxor_r2r(mm5, mm5);
+
+ for(i=0; i<8; i++)
+ {
+ movq_m2r(*(mblock++), mm0);
+ movq_m2r(*(mblock++), mm2);
+ movq_m2r(*(mold++), mm1);
+ movq_m2r(*(mold++), mm3);
+ psubsw_r2r(mm1, mm0);
+ psubsw_r2r(mm3, mm2);
+ movq_r2r(mm0, mm1);
+ movq_r2r(mm2, mm3);
+ pcmpgtw_r2r(mm7, mm0);
+ pcmpgtw_r2r(mm7, mm2);
+ pxor_r2r(mm6, mm1);
+ pxor_r2r(mm6, mm3);
+ pcmpgtw_r2r(mm7, mm1);
+ pcmpgtw_r2r(mm7, mm3);
+ por_r2r(mm0, mm5);
+ por_r2r(mm2, mm5);
+ por_r2r(mm1, mm5);
+ por_r2r(mm3, mm5);
+ }
+ movq_r2m(mm5, result);
+
+ if(result.q)
+ {
+ if(!RTjpeg_mtest)
+ for(i=0; i<16; i++)((__u64 *)old)[i]=((__u64 *)RTjpeg_block)[i];
+ return 0;
+ }
+// printf(".");
+ return 1;
+}
+
+#else
+int RTjpeg_bcomp(__s16 *old, __u16 *mask)
+{
+ int i;
+
+ for(i=0; i<64; i++)
+ if(abs(old[i]-RTjpeg_block[i])>*mask)
+ {
+ if(!RTjpeg_mtest)
+ for(i=0; i<16; i++)((__u64 *)old)[i]=((__u64 *)RTjpeg_block)[i];
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+void RTjpeg_set_test(int i)
+{
+ RTjpeg_mtest=i;
+}
+
+int RTjpeg_mcompress(__s8 *sp, unsigned char *bp, __u16 lmask, __u16 cmask)
+{
+ __s8 * sb;
+ __s16 *block;
+ register __s8 * bp2;
+ register __s8 * bp3;
+ register int i, j, k;
+
+#ifdef HAVE_LIBMMX
+ emms();
+ RTjpeg_lmask=(mmx_t)(((__u64)lmask<<48)|((__u64)lmask<<32)|((__u64)lmask<<16)|lmask);
+ RTjpeg_cmask=(mmx_t)(((__u64)cmask<<48)|((__u64)cmask<<32)|((__u64)cmask<<16)|cmask);
+#else
+ RTjpeg_lmask=lmask;
+ RTjpeg_cmask=cmask;
+#endif
+
+ bp = bp - RTjpeg_width*0;
+ bp2 = bp + RTjpeg_Ysize-RTjpeg_width*0;
+ bp3 = bp2 + RTjpeg_Csize;
+
+ sb=sp;
+ block=RTjpeg_old;
+/* Y */
+ for(i=RTjpeg_height; i; i-=8)
+ {
+ for(j=0, k=0; j<RTjpeg_width; j+=16, k+=8)
+ {
+ RTjpeg_dctY(bp+j, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ if(RTjpeg_bcomp(block, &RTjpeg_lmask))
+ {
+ *((__u8 *)sp++)=255;
+ }
+ else sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+ block+=64;
+
+ RTjpeg_dctY(bp+j+8, RTjpeg_block, RTjpeg_Ywidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ if(RTjpeg_bcomp(block, &RTjpeg_lmask))
+ {
+ *((__u8 *)sp++)=255;
+ }
+ else sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+ block+=64;
+
+ RTjpeg_dctY(bp2+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ if(RTjpeg_bcomp(block, &RTjpeg_cmask))
+ {
+ *((__u8 *)sp++)=255;
+ }
+ else sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+ block+=64;
+
+ RTjpeg_dctY(bp3+k, RTjpeg_block, RTjpeg_Cwidth);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_cqt);
+ if(RTjpeg_bcomp(block, &RTjpeg_cmask))
+ {
+ *((__u8 *)sp++)=255;
+ }
+ else sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_cb8);
+ block+=64;
+
+ }
+ bp+=RTjpeg_width<<3;
+ bp2+=RTjpeg_width<<2;
+ bp3+=RTjpeg_width<<2;
+ }
+ //printf ("%d\n", block - RTjpeg_old);
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ return (sp-sb);
+}
+
+int RTjpeg_mcompress8(__s8 *sp, unsigned char *bp, __u16 lmask)
+{
+ __s8 * sb;
+ __s16 *block;
+ int i, j;
+
+#ifdef HAVE_LIBMMX
+ emms();
+ RTjpeg_lmask=(mmx_t)(((__u64)lmask<<48)|((__u64)lmask<<32)|((__u64)lmask<<16)|lmask);
+#else
+ RTjpeg_lmask=lmask;
+#endif
+
+
+ sb=sp;
+ block=RTjpeg_old;
+/* Y */
+ for(i=0; i<RTjpeg_height; i+=8)
+ {
+ for(j=0; j<RTjpeg_width; j+=8)
+ {
+ RTjpeg_dctY(bp+j, RTjpeg_block, RTjpeg_width);
+ RTjpeg_quant(RTjpeg_block, RTjpeg_lqt);
+ if(RTjpeg_bcomp(block, &RTjpeg_lmask))
+ {
+ *((__u8 *)sp++)=255;
+// printf("* %d ", sp[-1]);
+ } else sp+=RTjpeg_b2s(RTjpeg_block, sp, RTjpeg_lb8);
+ block+=64;
+ }
+ bp+=RTjpeg_width<<3;
+ }
+#ifdef HAVE_LIBMMX
+ emms();
+#endif
+ return (sp-sb);
+}
+
+void RTjpeg_color_init(void)
+{
+}
+
+#define KcrR 76284
+#define KcrG 53281
+#define KcbG 25625
+#define KcbB 132252
+#define Ky 76284
+
+void RTjpeg_yuv422rgb(__u8 *buf, __u8 *rgb)
+{
+ int tmp;
+ int i, j;
+ __s32 y, crR, crG, cbG, cbB;
+ __u8 *bufcr, *bufcb, *bufy, *bufoute;
+ int yskip;
+
+ yskip=RTjpeg_width;
+
+ bufcb=&buf[RTjpeg_width*RTjpeg_height];
+ bufcr=&buf[RTjpeg_width*RTjpeg_height+(RTjpeg_width*RTjpeg_height)/2];
+ bufy=&buf[0];
+ bufoute=rgb;
+
+ for(i=0; i<(RTjpeg_height); i++)
+ {
+ for(j=0; j<RTjpeg_width; j+=2)
+ {
+ crR=(*bufcr-128)*KcrR;
+ crG=(*(bufcr++)-128)*KcrG;
+ cbG=(*bufcb-128)*KcbG;
+ cbB=(*(bufcb++)-128)*KcbB;
+
+ y=(bufy[j]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+1]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ }
+ bufy+=yskip;
+ }
+}
+
+
+void RTjpeg_yuv420rgb(__u8 *buf, __u8 *rgb)
+{
+ int tmp;
+ int i, j;
+ __s32 y, crR, crG, cbG, cbB;
+ __u8 *bufcr, *bufcb, *bufy, *bufoute, *bufouto;
+ int oskip, yskip;
+
+ oskip=RTjpeg_width*3;
+ yskip=RTjpeg_width;
+
+ bufcb=&buf[RTjpeg_width*RTjpeg_height];
+ bufcr=&buf[RTjpeg_width*RTjpeg_height+(RTjpeg_width*RTjpeg_height)/4];
+ bufy=&buf[0];
+ bufoute=rgb;
+ bufouto=rgb+oskip;
+
+ for(i=0; i<(RTjpeg_height>>1); i++)
+ {
+ for(j=0; j<RTjpeg_width; j+=2)
+ {
+ crR=(*bufcr-128)*KcrR;
+ crG=(*(bufcr++)-128)*KcrG;
+ cbG=(*bufcb-128)*KcbG;
+ cbB=(*(bufcb++)-128)*KcbB;
+
+ y=(bufy[j]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+1]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+yskip]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+1+yskip]-16)*Ky;
+
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ }
+ bufoute+=oskip;
+ bufouto+=oskip;
+ bufy+=yskip<<1;
+ }
+}
+
+
+void RTjpeg_yuvrgb32(__u8 *buf, __u8 *rgb)
+{
+ int tmp;
+ int i, j;
+ __s32 y, crR, crG, cbG, cbB;
+ __u8 *bufcr, *bufcb, *bufy, *bufoute, *bufouto;
+ int oskip, yskip;
+
+ oskip=RTjpeg_width*4;
+ yskip=RTjpeg_width;
+
+ bufcb=&buf[RTjpeg_width*RTjpeg_height];
+ bufcr=&buf[RTjpeg_width*RTjpeg_height+(RTjpeg_width*RTjpeg_height)/2];
+ bufy=&buf[0];
+ bufoute=rgb;
+ bufouto=rgb+oskip;
+
+ for(i=0; i<(RTjpeg_height>>1); i++)
+ {
+ for(j=0; j<RTjpeg_width; j+=2)
+ {
+ crR=(*bufcr-128)*KcrR;
+ crG=(*(bufcr++)-128)*KcrG;
+ cbG=(*bufcb-128)*KcbG;
+ cbB=(*(bufcb++)-128)*KcbB;
+
+ y=(bufy[j]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ bufoute++;
+
+ y=(bufy[j+1]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ bufoute++;
+
+ y=(bufy[j+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ bufouto++;
+
+ y=(bufy[j+1+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ bufouto++;
+
+ }
+ bufoute+=oskip;
+ bufouto+=oskip;
+ bufy+=yskip<<1;
+ }
+}
+
+void RTjpeg_yuvrgb24(__u8 *buf, __u8 *rgb)
+{
+ int tmp;
+ int i, j;
+ __s32 y, crR, crG, cbG, cbB;
+ __u8 *bufcr, *bufcb, *bufy, *bufoute, *bufouto;
+ int oskip, yskip;
+
+ oskip=RTjpeg_width*3;
+ yskip=RTjpeg_width;
+
+ bufcb=&buf[RTjpeg_width*RTjpeg_height];
+ bufcr=&buf[RTjpeg_width*RTjpeg_height+(RTjpeg_width*RTjpeg_height)/4];
+ bufy=&buf[0];
+ bufoute=rgb;
+ bufouto=rgb+oskip;
+
+ for(i=0; i<(RTjpeg_height>>1); i++)
+ {
+ for(j=0; j<RTjpeg_width; j+=2)
+ {
+ crR=(*bufcr-128)*KcrR;
+ crG=(*(bufcr++)-128)*KcrG;
+ cbG=(*bufcb-128)*KcbG;
+ cbB=(*(bufcb++)-128)*KcbB;
+
+ y=(bufy[j]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+1]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufoute++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ y=(bufy[j+1+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ *(bufouto++)=(tmp>255)?255:((tmp<0)?0:tmp);
+
+ }
+ bufoute+=oskip;
+ bufouto+=oskip;
+ bufy+=yskip<<1;
+ }
+}
+
+void RTjpeg_yuvrgb16(__u8 *buf, __u8 *rgb)
+{
+ int tmp;
+ int i, j;
+ __s32 y, crR, crG, cbG, cbB;
+ __u8 *bufcr, *bufcb, *bufy, *bufoute, *bufouto;
+ int oskip, yskip;
+ unsigned char r, g, b;
+
+ oskip=RTjpeg_width*2;
+ yskip=RTjpeg_width;
+
+ bufcb=&buf[RTjpeg_width*RTjpeg_height];
+ bufcr=&buf[RTjpeg_width*RTjpeg_height+(RTjpeg_width*RTjpeg_height)/4];
+ bufy=&buf[0];
+ bufoute=rgb;
+ bufouto=rgb+oskip;
+
+ for(i=0; i<(RTjpeg_height>>1); i++)
+ {
+ for(j=0; j<RTjpeg_width; j+=2)
+ {
+ crR=(*bufcr-128)*KcrR;
+ crG=(*(bufcr++)-128)*KcrG;
+ cbG=(*bufcb-128)*KcbG;
+ cbB=(*(bufcb++)-128)*KcbB;
+
+ y=(bufy[j]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ b=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ g=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ r=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(int)((int)b >> 3);
+ tmp|=(int)(((int)g >> 2) << 5);
+ tmp|=(int)(((int)r >> 3) << 11);
+ *(bufoute++)=tmp&0xff;
+ *(bufoute++)=tmp>>8;
+
+
+ y=(bufy[j+1]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ b=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ g=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ r=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(int)((int)b >> 3);
+ tmp|=(int)(((int)g >> 2) << 5);
+ tmp|=(int)(((int)r >> 3) << 11);
+ *(bufoute++)=tmp&0xff;
+ *(bufoute++)=tmp>>8;
+
+ y=(bufy[j+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ b=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ g=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ r=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(int)((int)b >> 3);
+ tmp|=(int)(((int)g >> 2) << 5);
+ tmp|=(int)(((int)r >> 3) << 11);
+ *(bufouto++)=tmp&0xff;
+ *(bufouto++)=tmp>>8;
+
+ y=(bufy[j+1+yskip]-16)*Ky;
+
+ tmp=(y+cbB)>>16;
+ b=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y-crG-cbG)>>16;
+ g=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(y+crR)>>16;
+ r=(tmp>255)?255:((tmp<0)?0:tmp);
+ tmp=(int)((int)b >> 3);
+ tmp|=(int)(((int)g >> 2) << 5);
+ tmp|=(int)(((int)r >> 3) << 11);
+ *(bufouto++)=tmp&0xff;
+ *(bufouto++)=tmp>>8;
+
+ }
+ bufoute+=oskip;
+ bufouto+=oskip;
+ bufy+=yskip<<1;
+ }
+}
+
+void RTjpeg_yuvrgb8(__u8 *buf, __u8 *rgb)
+{
+ bcopy(buf, rgb, RTjpeg_width*RTjpeg_height);
+}
+
+void RTjpeg_double32(__u32 *buf)
+{
+ int i, j;
+
+ __u32 *iptr, *optr1, *optr2;
+
+ iptr=buf+(RTjpeg_width*RTjpeg_height)-1;
+ optr1=buf+(RTjpeg_width*RTjpeg_height*4)-1;
+ optr2=optr1-(2*RTjpeg_width);
+
+ for(i=0; i<RTjpeg_height; i++)
+ {
+ for(j=0; j<RTjpeg_width; j++)
+ {
+ *(optr1--)=*iptr;
+ *(optr1--)=*iptr;
+ *(optr2--)=*iptr;
+ *(optr2--)=*(iptr--);
+ }
+ optr2=optr2-2*RTjpeg_width;
+ optr1=optr1-2*RTjpeg_width;
+ }
+}
+
+void RTjpeg_double24(__u8 *buf)
+{
+}
+
+void RTjpeg_double16(__u16 *buf)
+{
+ int i, j;
+
+ __u16 *iptr, *optr1, *optr2;
+
+ iptr=buf+(RTjpeg_width*RTjpeg_height)-1;
+ optr1=buf+(RTjpeg_width*RTjpeg_height*4)-1;
+ optr2=optr1-(2*RTjpeg_width);
+
+ for(i=0; i<RTjpeg_height; i++)
+ {
+ for(j=0; j<RTjpeg_width; j++)
+ {
+ *(optr1--)=*iptr;
+ *(optr1--)=*iptr;
+ *(optr2--)=*iptr;
+ *(optr2--)=*(iptr--);
+ }
+ optr2=optr2-2*RTjpeg_width;
+ optr1=optr1-2*RTjpeg_width;
+ }
+}
+
+void RTjpeg_double8(__u8 *buf)
+{
+ int i, j;
+
+ __u8 *iptr, *optr1, *optr2;
+
+ iptr=buf+(RTjpeg_width*RTjpeg_height)-1;
+ optr1=buf+(RTjpeg_width*RTjpeg_height*4)-1;
+ optr2=optr1-(2*RTjpeg_width);
+
+ for(i=0; i<RTjpeg_height; i++)
+ {
+ for(j=0; j<RTjpeg_width; j++)
+ {
+ *(optr1--)=*iptr;
+ *(optr1--)=*iptr;
+ *(optr2--)=*iptr;
+ *(optr2--)=*(iptr--);
+ }
+ optr2=optr2-2*RTjpeg_width;
+ optr1=optr1-2*RTjpeg_width;
+ }
+}
+
diff --git a/gst/rtjpeg/RTjpeg.h b/gst/rtjpeg/RTjpeg.h
new file mode 100644
index 00000000..90e2a8d5
--- /dev/null
+++ b/gst/rtjpeg/RTjpeg.h
@@ -0,0 +1,53 @@
+/*
+ bttvgrab 0.15.4 [1999-03-23]
+ (c) 1998, 1999 by Joerg Walter <trouble@moes.pmnet.uni-oldenburg.de>
+ Maintained by: Joerg Walter
+ Current version at http://moes.pmnet.uni-oldenburg.de/bttvgrab/
+
+ 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file is a modified version of RTjpeg 0.1.2, (C) Justin Schoeman 1998
+*/
+
+#include <config.h>
+#include <inttypes.h>
+
+typedef uint8_t __u8;
+typedef uint32_t __u32;
+typedef int8_t __s8;
+typedef uint16_t __u16;
+
+extern void RTjpeg_init_Q(__u8 Q);
+extern void RTjpeg_init_compress(long unsigned int *buf, int width, int height, __u8 Q);
+extern void RTjpeg_init_decompress(long unsigned int *buf, int width, int height);
+extern int RTjpeg_compressYUV420(__s8 *sp, unsigned char *bp);
+extern int RTjpeg_compressYUV422(__s8 *sp, unsigned char *bp);
+extern void RTjpeg_decompressYUV420(__s8 *sp, __u8 *bp);
+extern void RTjpeg_decompressYUV422(__s8 *sp, __u8 *bp);
+extern int RTjpeg_compress8(__s8 *sp, unsigned char *bp);
+extern void RTjpeg_decompress8(__s8 *sp, __u8 *bp);
+
+extern void RTjpeg_init_mcompress(void);
+extern int RTjpeg_mcompress(__s8 *sp, unsigned char *bp, __u16 lmask, __u16 cmask);
+extern int RTjpeg_mcompress8(__s8 *sp, unsigned char *bp, __u16 lmask);
+extern void RTjpeg_set_test(int i);
+
+extern void RTjpeg_yuv420rgb(__u8 *buf, __u8 *rgb);
+extern void RTjpeg_yuv422rgb(__u8 *buf, __u8 *rgb);
+extern void RTjpeg_yuvrgb8(__u8 *buf, __u8 *rgb);
+extern void RTjpeg_yuvrgb16(__u8 *buf, __u8 *rgb);
+extern void RTjpeg_yuvrgb24(__u8 *buf, __u8 *rgb);
+extern void RTjpeg_yuvrgb32(__u8 *buf, __u8 *rgb);
+
diff --git a/gst/rtjpeg/gstrtjpeg.c b/gst/rtjpeg/gstrtjpeg.c
new file mode 100644
index 00000000..335914f6
--- /dev/null
+++ b/gst/rtjpeg/gstrtjpeg.c
@@ -0,0 +1,62 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+
+#include <gstrtjpegenc.h>
+#include <gstrtjpegdec.h>
+
+extern GstElementDetails gst_rtjpegenc_details;
+extern GstElementDetails gst_rtjpegdec_details;
+
+GstTypeDefinition rtjpegdefinition = {
+ "rtjpeg_video/rtjpeg",
+ "video/rtjpeg",
+ ".rtj",
+ NULL,
+};
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *enc, *dec;
+
+ gst_plugin_set_longname(plugin,"Justin Schoeman's RTjpeg codec and \
+conversion utilities");
+
+ /* create an elementfactory for the rtjpegenc element */
+ enc = gst_elementfactory_new("rtjpegenc",GST_TYPE_RTJPEGENC,
+ &rtjpegenc_details);
+ g_return_val_if_fail(enc != NULL, FALSE);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (enc));
+
+ /* create an elementfactory for the rtjpegdec element */
+ dec = gst_elementfactory_new("rtjpegdec",GST_TYPE_RTJPEGDEC,
+ &rtjpegdec_details);
+ g_return_val_if_fail(dec != NULL, FALSE);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (dec));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "rtjpeg",
+ plugin_init
+};
diff --git a/gst/rtjpeg/gstrtjpegdec.c b/gst/rtjpeg/gstrtjpegdec.c
new file mode 100644
index 00000000..f5dc5825
--- /dev/null
+++ b/gst/rtjpeg/gstrtjpegdec.c
@@ -0,0 +1,114 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+
+#include <gstrtjpegdec.h>
+
+
+
+/* elementfactory information */
+GstElementDetails gst_rtjpegdec_details = {
+ "RTjpeg decoder",
+ "Filter/Video/Decoder",
+ "Decodes video in RTjpeg format",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+/* GstRTJpegDec signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_QUALITY,
+};
+
+
+static void gst_rtjpegdec_class_init (GstRTJpegDecClass *klass);
+static void gst_rtjpegdec_init (GstRTJpegDec *rtjpegdec);
+
+static void gst_rtjpegdec_chain (GstPad *pad, GstBuffer *buf);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_rtjpegdec_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_rtjpegdec_get_type (void)
+{
+ static GType rtjpegdec_type = 0;
+
+ if (!rtjpegdec_type) {
+ static const GTypeInfo rtjpegdec_info = {
+ sizeof(GstRTJpegDecClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_rtjpegdec_class_init,
+ NULL,
+ NULL,
+ sizeof(GstRTJpegDec),
+ 0,
+ (GInstanceInitFunc)gst_rtjpegdec_init,
+ };
+ rtjpegdec_type = g_type_register_static(GST_TYPE_ELEMENT, "GstRTJpegDec", &rtjpegdec_info, 0);
+ }
+ return rtjpegdec_type;
+}
+
+static void
+gst_rtjpegdec_class_init (GstRTJpegDecClass *klass)
+{
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+}
+
+static void
+gst_rtjpegdec_init (GstRTJpegDec *rtjpegdec)
+{
+ rtjpegdec->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(rtjpegdec),rtjpegdec->sinkpad);
+ gst_pad_set_chain_function(rtjpegdec->sinkpad,gst_rtjpegdec_chain);
+ rtjpegdec->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_element_add_pad(GST_ELEMENT(rtjpegdec),rtjpegdec->srcpad);
+}
+
+static void
+gst_rtjpegdec_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstRTJpegDec *rtjpegdec;
+ guchar *data;
+ gulong size;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ rtjpegdec = GST_RTJPEGDEC (GST_OBJECT_PARENT (pad));
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ gst_info("would be encoding frame here\n");
+
+ gst_pad_push(rtjpegdec->srcpad,buf);
+}
diff --git a/gst/rtjpeg/gstrtjpegdec.h b/gst/rtjpeg/gstrtjpegdec.h
new file mode 100644
index 00000000..853bf345
--- /dev/null
+++ b/gst/rtjpeg/gstrtjpegdec.h
@@ -0,0 +1,71 @@
+/* Gnome-Streamer
+ * 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 __RTJPEGDEC_H__
+#define __RTJPEGDEC_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_RTJPEGDEC \
+ (gst_rtjpegdec_get_type())
+#define GST_RTJPEGDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTJPEGDEC,GstRTJpegDec))
+#define GST_RTJPEGDEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTJPEGDEC,GstRTJpegDec))
+#define GST_IS_RTJPEGDEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTJPEGDEC))
+#define GST_IS_RTJPEGDEC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTJPEGDEC)))
+
+typedef struct _GstRTJpegDec GstRTJpegDec;
+typedef struct _GstRTJpegDecClass GstRTJpegDecClass;
+
+struct _GstRTJpegDec {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gint width,height;
+ gint quality;
+ gint quant[128];
+
+};
+
+struct _GstRTJpegDecClass {
+ GstElementClass parent_class;
+};
+
+GType gst_rtjpegdec_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __RTJPEGDEC_H__ */
diff --git a/gst/rtjpeg/gstrtjpegenc.c b/gst/rtjpeg/gstrtjpegenc.c
new file mode 100644
index 00000000..68b1e843
--- /dev/null
+++ b/gst/rtjpeg/gstrtjpegenc.c
@@ -0,0 +1,112 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+
+#include <gstrtjpegenc.h>
+
+/* elementfactory information */
+GstElementDetails gst_rtjpegenc_details = {
+ "RTjpeg encoder",
+ "Filter/Video/Encoder",
+ "Encodes video in RTjpeg format",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+/* GstRTJpegEnc signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_QUALITY,
+};
+
+
+static void gst_rtjpegenc_class_init (GstRTJpegEncClass *klass);
+static void gst_rtjpegenc_init (GstRTJpegEnc *rtjpegenc);
+
+static void gst_rtjpegenc_chain (GstPad *pad, GstBuffer *buf);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_rtjpegenc_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_rtjpegenc_get_type (void)
+{
+ static GType rtjpegenc_type = 0;
+
+ if (!rtjpegenc_type) {
+ static const GTypeInfo rtjpegenc_info = {
+ sizeof(GstRTJpegEncClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_rtjpegenc_class_init,
+ NULL,
+ NULL,
+ sizeof(GstRTJpegEnc),
+ 0,
+ (GInstanceInitFunc)gst_rtjpegenc_init,
+ };
+ rtjpegenc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstRTJpegEnc", &rtjpegenc_info, 0);
+ }
+ return rtjpegenc_type;
+}
+
+static void
+gst_rtjpegenc_class_init (GstRTJpegEncClass *klass)
+{
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+}
+
+static void
+gst_rtjpegenc_init (GstRTJpegEnc *rtjpegenc)
+{
+ rtjpegenc->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(rtjpegenc),rtjpegenc->sinkpad);
+ gst_pad_set_chain_function(rtjpegenc->sinkpad,gst_rtjpegenc_chain);
+ rtjpegenc->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_element_add_pad(GST_ELEMENT(rtjpegenc),rtjpegenc->srcpad);
+}
+
+static void
+gst_rtjpegenc_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstRTJpegEnc *rtjpegenc;
+ guchar *data;
+ gulong size;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ rtjpegenc = GST_RTJPEGENC (GST_OBJECT_PARENT (pad));
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ gst_info("would be encoding frame here\n");
+
+ gst_pad_push(rtjpegenc->srcpad,buf);
+}
diff --git a/gst/rtjpeg/gstrtjpegenc.h b/gst/rtjpeg/gstrtjpegenc.h
new file mode 100644
index 00000000..837616ab
--- /dev/null
+++ b/gst/rtjpeg/gstrtjpegenc.h
@@ -0,0 +1,72 @@
+/* Gnome-Streamer
+ * 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 __RTJPEGENC_H__
+#define __RTJPEGENC_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+#include "RTjpeg.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_RTJPEGENC \
+ (gst_rtjpegenc_get_type())
+#define GST_RTJPEGENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTJPEGENC,GstRTJpegEnc))
+#define GST_RTJPEGENC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTJPEGENC,GstRTJpegEnc))
+#define GST_IS_RTJPEGENC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTJPEGENC))
+#define GST_IS_RTJPEGENC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTJPEGENC))
+
+typedef struct _GstRTJpegEnc GstRTJpegEnc;
+typedef struct _GstRTJpegEncClass GstRTJpegEncClass;
+
+struct _GstRTJpegEnc {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gint width,height;
+ gint quality;
+ gint quant[128];
+};
+
+struct _GstRTJpegEncClass {
+ GstElementClass parent_class;
+};
+
+GType gst_rtjpegenc_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __RTJPEGENC_H__ */
diff --git a/gst/smooth/.gitignore b/gst/smooth/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/smooth/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/smooth/Makefile.am b/gst/smooth/Makefile.am
new file mode 100644
index 00000000..f4856a14
--- /dev/null
+++ b/gst/smooth/Makefile.am
@@ -0,0 +1,8 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstsmooth.la
+
+libgstsmooth_la_SOURCES = gstsmooth.c
+libgstsmooth_la_CFLAGS = -O3 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GST_CFLAGS)
+
+noinst_HEADERS = gstsmooth.h
diff --git a/gst/smooth/gstsmooth.c b/gst/smooth/gstsmooth.c
new file mode 100644
index 00000000..5f1f507c
--- /dev/null
+++ b/gst/smooth/gstsmooth.c
@@ -0,0 +1,362 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <string.h>
+#include <gstsmooth.h>
+
+
+static GstElementDetails smooth_details = {
+ "Smooth effect",
+ "Filter/Effect",
+ "apply a smooth filter to an image",
+ VERSION,
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2000",
+};
+
+
+/* Smooth signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_ACTIVE,
+ ARG_TOLERANCE,
+ ARG_FILTERSIZE,
+ ARG_LUM_ONLY
+};
+
+GST_PADTEMPLATE_FACTORY (smooth_src_factory,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "smooth_src",
+ "video/raw",
+ "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
+ )
+)
+
+GST_PADTEMPLATE_FACTORY (smooth_sink_factory,
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "smooth_src",
+ "video/raw",
+ "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("I420"))
+ )
+)
+
+static void gst_smooth_class_init (GstSmoothClass *klass);
+static void gst_smooth_init (GstSmooth *smooth);
+
+static void gst_smooth_chain (GstPad *pad, GstBuffer *buf);
+static void smooth_filter (unsigned char* dest, unsigned char* src,
+ int width, int height, int tolerance, int filtersize);
+
+static void gst_smooth_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_smooth_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_smooth_signals[LAST_SIGNAL] = { 0 };
+
+static GstPadNegotiateReturn
+smooth_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstSmooth* filter = GST_SMOOTH (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy (pad, filter->sinkpad, caps);
+}
+
+static GstPadNegotiateReturn
+smooth_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstSmooth* filter = GST_SMOOTH (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy (pad, filter->srcpad, caps);
+}
+
+GType
+gst_smooth_get_type (void)
+{
+ static GType smooth_type = 0;
+
+ if (!smooth_type) {
+ static const GTypeInfo smooth_info = {
+ sizeof(GstSmoothClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_smooth_class_init,
+ NULL,
+ NULL,
+ sizeof(GstSmooth),
+ 0,
+ (GInstanceInitFunc)gst_smooth_init,
+ };
+ smooth_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSmooth", &smooth_info, 0);
+ }
+ return smooth_type;
+}
+
+static void
+gst_smooth_class_init (GstSmoothClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ACTIVE,
+ g_param_spec_boolean("active","active","active",
+ TRUE,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TOLERANCE,
+ g_param_spec_int("tolerance","tolerance","tolerance",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FILTERSIZE,
+ g_param_spec_int("filtersize","filtersize","filtersize",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+
+ gobject_class->set_property = gst_smooth_set_property;
+ gobject_class->get_property = gst_smooth_get_property;
+
+}
+
+static void
+gst_smooth_newcaps (GstPad *pad, GstCaps *caps)
+{
+ GstSmooth *filter;
+
+ filter = GST_SMOOTH (gst_pad_get_parent (pad));
+
+ filter->width = gst_caps_get_int (caps, "width");
+ filter->height = gst_caps_get_int (caps, "height");
+}
+
+static void
+gst_smooth_init (GstSmooth *smooth)
+{
+ smooth->sinkpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (smooth_sink_factory), "sink");
+ gst_pad_set_negotiate_function (smooth->sinkpad, smooth_negotiate_sink);
+ gst_pad_set_newcaps_function (smooth->sinkpad, gst_smooth_newcaps);
+ gst_pad_set_chain_function (smooth->sinkpad, gst_smooth_chain);
+ gst_element_add_pad (GST_ELEMENT (smooth), smooth->sinkpad);
+
+ smooth->srcpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (smooth_src_factory), "src");
+ gst_pad_set_negotiate_function (smooth->srcpad, smooth_negotiate_src);
+ gst_element_add_pad (GST_ELEMENT (smooth), smooth->srcpad);
+
+ smooth->active = TRUE;
+ smooth->tolerance = 8;
+ smooth->filtersize = 3;
+ smooth->lum_only = TRUE;
+}
+
+static void
+smooth_filter (unsigned char* dest, unsigned char* src, int width, int height, int tolerance, int filtersize)
+{
+ int refval, aktval, upperval, lowerval, numvalues, sum;
+ int x, y, fx, fy, fy1, fy2, fx1, fx2;
+ unsigned char *srcp = src;
+
+ fy1 = 0;
+ fy2 = MIN(filtersize+1, height) * width;
+
+ for(y = 0; y < height; y++)
+ {
+ if (y>(filtersize+1)) fy1 += width;
+ if (y<height-(filtersize+1)) fy2 += width;
+
+ for(x = 0; x < width; x++)
+ {
+ refval = *src;
+ upperval = refval + tolerance;
+ lowerval = refval - tolerance;
+
+ numvalues = 1;
+ sum = refval;
+
+ fx1 = MAX(x-filtersize, 0) + fy1;
+ fx2 = MIN(x+filtersize+1, width) + fy1;
+
+ for (fy = fy1; fy<fy2; fy+=width)
+ {
+ for (fx = fx1; fx<fx2; fx++)
+ {
+ aktval = srcp[fx];
+ if ((lowerval-aktval)*(upperval-aktval)<0)
+ {
+ numvalues ++;
+ sum += aktval;
+ }
+ } //for fx
+ fx1 += width;
+ fx2 += width;
+ } //for fy
+
+ src++;
+ *dest++ = sum/numvalues;
+ }
+ }
+}
+
+static void
+gst_smooth_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstSmooth *smooth;
+ guchar *data;
+ gulong size;
+ GstBuffer *outbuf;
+ gint lumsize, chromsize;
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ smooth = GST_SMOOTH (GST_OBJECT_PARENT (pad));
+
+ if (!smooth->active) {
+ gst_pad_push(smooth->srcpad,buf);
+ return;
+ }
+
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ GST_DEBUG (0,"smooth: have buffer of %d\n", GST_BUFFER_SIZE (buf));
+
+ outbuf = gst_buffer_new();
+ GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (buf));
+ GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf);
+
+ lumsize = smooth->width*smooth->height;
+ chromsize = lumsize/4;
+
+ smooth_filter (GST_BUFFER_DATA (outbuf), data, smooth->width, smooth->height,
+ smooth->tolerance, smooth->filtersize);
+ if (!smooth->lum_only) {
+ smooth_filter (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, smooth->width/2, smooth->height/2,
+ smooth->tolerance, smooth->filtersize/2);
+ smooth_filter (GST_BUFFER_DATA (outbuf)+lumsize+chromsize, data+lumsize+chromsize, smooth->width/2,
+ smooth->height/2, smooth->tolerance, smooth->filtersize/2);
+ }
+ else {
+ memcpy (GST_BUFFER_DATA (outbuf)+lumsize, data+lumsize, chromsize*2);
+ }
+
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+
+ gst_buffer_unref (buf);
+
+ gst_pad_push (smooth->srcpad, outbuf);
+}
+
+static void
+gst_smooth_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstSmooth *smooth;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SMOOTH(object));
+ smooth = GST_SMOOTH(object);
+
+ switch (prop_id) {
+ case ARG_ACTIVE:
+ smooth->active = g_value_get_boolean (value);
+ break;
+ case ARG_TOLERANCE:
+ smooth->tolerance = g_value_get_int (value);
+ break;
+ case ARG_FILTERSIZE:
+ smooth->filtersize = g_value_get_int (value);
+ break;
+ case ARG_LUM_ONLY:
+ smooth->lum_only = g_value_get_boolean (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_smooth_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstSmooth *smooth;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SMOOTH(object));
+ smooth = GST_SMOOTH(object);
+
+ switch (prop_id) {
+ case ARG_ACTIVE:
+ g_value_set_boolean (value, smooth->active);
+ break;
+ case ARG_TOLERANCE:
+ g_value_set_int (value, smooth->tolerance);
+ break;
+ case ARG_FILTERSIZE:
+ g_value_set_int (value, smooth->filtersize);
+ break;
+ case ARG_LUM_ONLY:
+ g_value_set_boolean (value, smooth->lum_only);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("smooth",GST_TYPE_SMOOTH,
+ &smooth_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (smooth_sink_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (smooth_src_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "smooth",
+ plugin_init
+};
+
diff --git a/gst/smooth/gstsmooth.h b/gst/smooth/gstsmooth.h
new file mode 100644
index 00000000..239e074f
--- /dev/null
+++ b/gst/smooth/gstsmooth.h
@@ -0,0 +1,75 @@
+/* Gnome-Streamer
+ * 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_SMOOTH_H__
+#define __GST_SMOOTH_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_SMOOTH \
+ (gst_smooth_get_type())
+#define GST_SMOOTH(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOOTH,GstSmooth))
+#define GST_SMOOTH_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOOTH,GstSmooth))
+#define GST_IS_SMOOTH(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOOTH))
+#define GST_IS_SMOOTH_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOOTH))
+
+typedef struct _GstSmooth GstSmooth;
+typedef struct _GstSmoothClass GstSmoothClass;
+
+struct _GstSmooth {
+ GstElement element;
+
+ int format;
+ int width;
+ int height;
+
+ gboolean active;
+ int tolerance;
+ int filtersize;
+ gboolean lum_only;
+
+ GstPad *sinkpad,*srcpad;
+};
+
+struct _GstSmoothClass {
+ GstElementClass parent_class;
+};
+
+GType gst_smooth_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_SMOOTH_H__ */
diff --git a/gst/spectrum/.gitignore b/gst/spectrum/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/spectrum/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/spectrum/Makefile.am b/gst/spectrum/Makefile.am
new file mode 100644
index 00000000..476c3fd1
--- /dev/null
+++ b/gst/spectrum/Makefile.am
@@ -0,0 +1,10 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstspectrum.la
+
+libgstspectrum_la_SOURCES = gstspectrum.c fix_fft.c
+libgstspectrum_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstspectrum.h
+
+EXTRA_DIST = README
diff --git a/gst/spectrum/README b/gst/spectrum/README
new file mode 100644
index 00000000..87555712
--- /dev/null
+++ b/gst/spectrum/README
@@ -0,0 +1,5 @@
+This is a simple, rather lame spectrum analyzer made from the fix_fft.c
+code, as found I think in xmms-0.9.1 (the 75-wide output sounds like xmms
+to me), which is actually written by other people (see fix_fft.c for
+credits). It worked last time I had GiST working, which was a while ago.
+Yes, GiST is not included here yet, it will be in 0.1.0.
diff --git a/gst/spectrum/fix_fft.c b/gst/spectrum/fix_fft.c
new file mode 100644
index 00000000..ecd70303
--- /dev/null
+++ b/gst/spectrum/fix_fft.c
@@ -0,0 +1,452 @@
+/* fix_fft.c - Fixed-point Fast Fourier Transform */
+/*
+ fix_fft() perform FFT or inverse FFT
+ window() applies a Hanning window to the (time) input
+ fix_loud() calculates the loudness of the signal, for
+ each freq point. Result is an integer array,
+ units are dB (values will be negative).
+ iscale() scale an integer value by (numer/denom).
+ fix_mpy() perform fixed-point multiplication.
+ Sinewave[1024] sinewave normalized to 32767 (= 1.0).
+ Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB.
+ Low_pass Low-pass filter, cutoff at sample_freq / 4.
+
+ All data are fixed-point short integers, in which
+ -32768 to +32768 represent -1.0 to +1.0. Integer arithmetic
+ is used for speed, instead of the more natural floating-point.
+
+ For the forward FFT (time -> freq), fixed scaling is
+ performed to prevent arithmetic overflow, and to map a 0dB
+ sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
+ coefficients; the one in the lower half is reported as 0dB
+ by fix_loud(). The return value is always 0.
+
+ For the inverse FFT (freq -> time), fixed scaling cannot be
+ done, as two 0dB coefficients would sum to a peak amplitude of
+ 64K, overflowing the 32k range of the fixed-point integers.
+ Thus, the fix_fft() routine performs variable scaling, and
+ returns a value which is the number of bits LEFT by which
+ the output must be shifted to get the actual amplitude
+ (i.e. if fix_fft() returns 3, each value of fr[] and fi[]
+ must be multiplied by 8 (2**3) for proper scaling.
+ Clearly, this cannot be done within the fixed-point short
+ integers. In practice, if the result is to be used as a
+ filter, the scale_shift can usually be ignored, as the
+ result will be approximately correctly normalized as is.
+
+ TURBO C, any memory model; uses inline assembly for speed
+ and for carefully-scaled arithmetic.
+
+ Written by: Tom Roberts 11/8/89
+ Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com
+
+ Timing on a Macintosh PowerBook 180.... (using Symantec C6.0)
+ fix_fft (1024 points) 8 ticks
+ fft (1024 points - Using SANE) 112 Ticks
+ fft (1024 points - Using FPU) 11
+
+ */
+
+#define fixed short
+
+/* FIX_MPY() - fixed-point multiplication macro.
+ This macro is a statement, not an expression (uses asm).
+ BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST.
+ args are all of type fixed.
+ Scaling ensures that 32767*32767 = 32767. */
+
+#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15
+
+#define N_WAVE 1024 /* dimension of Sinewave[] */
+#define LOG2_N_WAVE 10 /* log2(N_WAVE) */
+#define N_LOUD 100 /* dimension of Loudampl[] */
+
+extern fixed gst_spectrum_Sinewave[N_WAVE]; /* placed at end of this file for clarity */
+extern fixed gst_spectrum_Loudampl[N_LOUD];
+static int gst_spectrum_db_from_ampl(fixed re, fixed im);
+static fixed gst_spectrum_fix_mpy(fixed a, fixed b);
+
+/*
+ fix_fft() - perform fast Fourier transform.
+
+ if n>0 FFT is done, if n<0 inverse FFT is done
+ fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT.
+ size of data = 2**m
+ set inverse to 0=dft, 1=idft
+ */
+int gst_spectrum_fix_fft(fixed fr[], fixed fi[], int m, int inverse) {
+ int mr, nn, i, j, l, k, istep, n, scale, shift;
+ fixed qr, qi, tr, ti, wr, wi, t;
+
+ n = 1 << m;
+
+ if (n > N_WAVE)
+ return -1;
+
+ mr = 0;
+ nn = n - 1;
+ scale = 0;
+
+ /* decimation in time - re-order data */
+ for (m = 1; m <= nn; ++m)
+ {
+ l = n;
+ do
+ {
+ l >>= 1;
+ }
+ while (mr + l > nn);
+ mr = (mr & (l - 1)) + l;
+
+ if (mr <= m)
+ continue;
+ tr = fr[m];
+ fr[m] = fr[mr];
+ fr[mr] = tr;
+ ti = fi[m];
+ fi[m] = fi[mr];
+ fi[mr] = ti;
+ }
+
+ l = 1;
+ k = LOG2_N_WAVE - 1;
+ while (l < n)
+ {
+ if (inverse)
+ {
+ /* variable scaling, depending upon data */
+ shift = 0;
+ for (i = 0; i < n; ++i)
+ {
+ j = fr[i];
+ if (j < 0)
+ j = -j;
+ m = fi[i];
+ if (m < 0)
+ m = -m;
+ if (j > 16383 || m > 16383)
+ {
+ shift = 1;
+ break;
+ }
+ }
+ if (shift)
+ ++scale;
+ }
+ else
+ {
+ /* fixed scaling, for proper normalization -
+ there will be log2(n) passes, so this
+ results in an overall factor of 1/n,
+ distributed to maximize arithmetic accuracy. */
+ shift = 1;
+ }
+ /* it may not be obvious, but the shift will be performed
+ on each data point exactly once, during this pass. */
+ istep = l << 1;
+ for (m = 0; m < l; ++m)
+ {
+ j = m << k;
+ /* 0 <= j < N_WAVE/2 */
+ wr = gst_spectrum_Sinewave[j + N_WAVE / 4];
+ wi = -gst_spectrum_Sinewave[j];
+ if (inverse)
+ wi = -wi;
+ if (shift)
+ {
+ wr >>= 1;
+ wi >>= 1;
+ }
+ for (i = m; i < n; i += istep)
+ {
+ j = i + l;
+ tr = gst_spectrum_fix_mpy(wr, fr[j]) -
+ gst_spectrum_fix_mpy(wi, fi[j]);
+ ti = gst_spectrum_fix_mpy(wr, fi[j]) +
+ gst_spectrum_fix_mpy(wi, fr[j]);
+ qr = fr[i];
+ qi = fi[i];
+ if (shift)
+ {
+ qr >>= 1;
+ qi >>= 1;
+ }
+ fr[j] = qr - tr;
+ fi[j] = qi - ti;
+ fr[i] = qr + tr;
+ fi[i] = qi + ti;
+ }
+ }
+ --k;
+ l = istep;
+ }
+
+ return scale;
+}
+
+/* window() - apply a Hanning window */
+void gst_spectrum_window(fixed fr[], int n) {
+ int i, j, k;
+
+ j = N_WAVE / n;
+ n >>= 1;
+ for (i = 0, k = N_WAVE / 4; i < n; ++i, k += j)
+ FIX_MPY(fr[i], fr[i], 16384 - (gst_spectrum_Sinewave[k] >> 1));
+ n <<= 1;
+ for (k -= j; i < n; ++i, k -= j)
+ FIX_MPY(fr[i], fr[i], 16384 - (gst_spectrum_Sinewave[k] >> 1));
+}
+
+/* fix_loud() - compute loudness of freq-vis components.
+ n should be ntot/2, where ntot was passed to fix_fft();
+ 6 dB is added to account for the omitted alias components.
+ scale_shift should be the result of fix_fft(), if the time-series
+ was obtained from an inverse FFT, 0 otherwise.
+ loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD.
+ */
+void gst_spectrum_fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift) {
+ int i, max;
+
+ max = 0;
+ if (scale_shift > 0)
+ max = 10;
+ scale_shift = (scale_shift + 1) * 6;
+
+ for (i = 0; i < n; ++i)
+ {
+ loud[i] = gst_spectrum_db_from_ampl(fr[i], fi[i]) + scale_shift;
+ if (loud[i] > max)
+ loud[i] = max;
+ }
+}
+
+/* db_from_ampl() - find loudness (in dB) from
+ the complex amplitude.
+ */
+int gst_spectrum_db_from_ampl(fixed re, fixed im) {
+ static long loud2[N_LOUD] =
+ {0};
+ long v;
+ int i;
+
+ if (loud2[0] == 0)
+ {
+ loud2[0] = (long) gst_spectrum_Loudampl[0] * (long) gst_spectrum_Loudampl[0];
+ for (i = 1; i < N_LOUD; ++i)
+ {
+ v = (long) gst_spectrum_Loudampl[i] * (long) gst_spectrum_Loudampl[i];
+ loud2[i] = v;
+ loud2[i - 1] = (loud2[i - 1] + v) / 2;
+ }
+ }
+
+ v = (long) re *(long) re + (long) im *(long) im;
+
+ for (i = 0; i < N_LOUD; ++i)
+ if (loud2[i] <= v)
+ break;
+
+ return (-i);
+}
+
+/*
+ fix_mpy() - fixed-point multiplication
+ */
+fixed gst_spectrum_fix_mpy(fixed a, fixed b) {
+ FIX_MPY(a, a, b);
+ return a;
+}
+
+/*
+ iscale() - scale an integer value by (numer/denom)
+ */
+int gst_spectrum_iscale(int value, int numer, int denom) {
+ return (long) value *(long) numer / (long) denom;
+}
+
+/*
+ fix_dot() - dot product of two fixed arrays
+ */
+fixed gst_spectrum_fix_dot(fixed * hpa, fixed * pb, int n) {
+ fixed *pa;
+ long sum;
+ register fixed a, b;
+ unsigned int seg, off;
+
+/* seg = FP_SEG(hpa);
+ off = FP_OFF(hpa);
+ seg += off>>4;
+ off &= 0x000F;
+ pa = MK_FP(seg,off);
+ */
+ sum = 0L;
+ while (n--)
+ {
+ a = *pa++;
+ b = *pb++;
+ FIX_MPY(a, a, b);
+ sum += a;
+ }
+
+ if (sum > 0x7FFF)
+ sum = 0x7FFF;
+ else if (sum < -0x7FFF)
+ sum = -0x7FFF;
+
+ return (fixed) sum;
+
+}
+
+#if N_WAVE != 1024
+ERROR:N_WAVE != 1024
+#endif
+fixed gst_spectrum_Sinewave[1024] = {
+ 0, 201, 402, 603, 804, 1005, 1206, 1406,
+ 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011,
+ 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608,
+ 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195,
+ 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766,
+ 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319,
+ 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849,
+ 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353,
+ 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827,
+ 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268,
+ 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672,
+ 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036,
+ 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357,
+ 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631,
+ 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855,
+ 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027,
+ 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143,
+ 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201,
+ 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198,
+ 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132,
+ 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001,
+ 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802,
+ 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534,
+ 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195,
+ 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783,
+ 30851, 30918, 30984, 31049,
+ 31113, 31175, 31236, 31297,
+ 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735,
+ 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097,
+ 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382,
+ 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588,
+ 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717,
+ 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766,
+ 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736,
+ 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628,
+ 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441,
+ 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176,
+ 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833,
+ 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413,
+ 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918,
+ 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349,
+ 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706,
+ 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992,
+ 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208,
+ 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355,
+ 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437,
+ 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456,
+ 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413,
+ 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311,
+ 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153,
+ 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942,
+ 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680,
+ 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371,
+ 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017,
+ 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623,
+ 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191,
+ 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724,
+ 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227,
+ 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703,
+ 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156,
+ 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589,
+ 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006,
+ 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411,
+ 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808,
+ 1607, 1406, 1206, 1005, 804, 603, 402, 201,
+ 0, -201, -402, -603, -804, -1005, -1206, -1406,
+ -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011,
+ -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608,
+ -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195,
+ -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766,
+ -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319,
+ -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849,
+ -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
+ -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
+ -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
+ -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
+ -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
+ -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
+ -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
+ -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
+ -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
+ -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
+ -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
+ -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
+ -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
+ -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
+ -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
+ -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
+ -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
+ -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
+ -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
+ -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
+ -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
+ -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
+ -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
+ -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
+ -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
+ -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
+ -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
+ -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
+ -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
+ -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
+ -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
+ -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
+ -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
+ -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
+ -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
+ -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
+ -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
+ -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
+ -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
+ -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
+ -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
+ -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
+ -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
+ -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
+ -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
+ -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
+ -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
+ -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
+ -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
+ -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
+ -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703,
+ -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156,
+ -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589,
+ -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006,
+ -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411,
+ -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808,
+ -1607, -1406, -1206, -1005, -804, -603, -402, -201,
+};
+
+#if N_LOUD != 100
+ERROR:N_LOUD != 100
+#endif
+fixed gst_spectrum_Loudampl[100] = {
+ 32767, 29203, 26027, 23197, 20674, 18426, 16422, 14636,
+ 13044, 11626, 10361, 9234, 8230, 7335, 6537, 5826,
+ 5193, 4628, 4125, 3676, 3276, 2920, 2602, 2319,
+ 2067, 1842, 1642, 1463, 1304, 1162, 1036, 923,
+ 823, 733, 653, 582, 519, 462, 412, 367,
+ 327, 292, 260, 231, 206, 184, 164, 146,
+ 130, 116, 103, 92, 82, 73, 65, 58,
+ 51, 46, 41, 36, 32, 29, 26, 23,
+ 20, 18, 16, 14, 13, 11, 10, 9,
+ 8, 7, 6, 5, 5, 4, 4, 3,
+ 3, 2, 2, 2, 2, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
diff --git a/gst/spectrum/gstspectrum.c b/gst/spectrum/gstspectrum.c
new file mode 100644
index 00000000..0821545c
--- /dev/null
+++ b/gst/spectrum/gstspectrum.c
@@ -0,0 +1,242 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <string.h>
+
+#include "gstspectrum.h"
+
+static GstElementDetails gst_spectrum_details = {
+ "Spectrum analyzer",
+ "Filter/Analysis",
+ "Run an FFT on the audio signal, output spectrum data",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+
+static GstTypeDefinition spectrumdefinition = {
+ "spectrum_spectrum_raw",
+ "spectrum/raw",
+ NULL,
+ NULL,
+};
+
+
+/* Spectrum signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_WIDTH,
+};
+
+
+static void gst_spectrum_class_init (GstSpectrumClass *klass);
+static void gst_spectrum_init (GstSpectrum *spectrum);
+
+static void gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static void gst_spectrum_chain (GstPad *pad, GstBuffer *buf);
+
+#define fixed short
+int gst_spectrum_fix_fft(fixed fr[], fixed fi[], int m, int inverse);
+void gst_spectrum_fix_loud(fixed loud[], fixed fr[], fixed fi[], int n, int scale_shift);
+void gst_spectrum_window(fixed fr[], int n);
+
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_spectrum_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_spectrum_get_type (void)
+{
+ static GType spectrum_type = 0;
+
+ if (!spectrum_type) {
+ static const GTypeInfo spectrum_info = {
+ sizeof(GstSpectrumClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_spectrum_class_init,
+ NULL,
+ NULL,
+ sizeof(GstSpectrum),
+ 0,
+ (GInstanceInitFunc)gst_spectrum_init,
+ };
+ spectrum_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSpectrum", &spectrum_info, 0);
+ }
+ return spectrum_type;
+}
+
+static void
+gst_spectrum_class_init (GstSpectrumClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
+ g_param_spec_int("width","width","width",
+ G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
+
+ gobject_class->set_property = gst_spectrum_set_property;
+}
+
+static void
+gst_spectrum_init (GstSpectrum *spectrum)
+{
+ spectrum->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->sinkpad);
+ gst_pad_set_chain_function(spectrum->sinkpad,gst_spectrum_chain);
+ spectrum->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_element_add_pad(GST_ELEMENT(spectrum),spectrum->srcpad);
+
+ spectrum->width = 75;
+}
+
+static void
+gst_spectrum_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstSpectrum *spectrum;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SPECTRUM(object));
+ spectrum = GST_SPECTRUM(object);
+
+ switch (prop_id) {
+ case ARG_WIDTH:
+ spectrum->width = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_spectrum_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstSpectrum *spectrum;
+ gint spec_base, spec_len;
+ gint16 *re, *im, *loud;
+ gint16 *samples;
+ gint samplecount,step,pos,i;
+ guchar *spect;
+ GstBuffer *newbuf;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ spectrum = GST_SPECTRUM (GST_OBJECT_PARENT (pad));
+
+ /* first deal with audio metadata */
+// FIXME
+// if (buf->meta) {
+// if (spectrum->meta != NULL) {
+// /* FIXME: need to unref the old metadata so it goes away */
+// }
+// /* we just make a copy of the pointer */
+// spectrum->meta = (MetaAudioRaw *)(buf->data);
+// /* FIXME: now we have to ref the metadata so it does go away */
+// }
+
+ //g_return_if_fail(spectrum->meta != NULL);
+
+ //samplecount = GST_BUFFER_SIZE(buf) /
+ // (spectrum->meta->channels * sizeof(gint16));
+// samples = (gint16 *)g_malloc(buf->datasize);
+// g_return_if_fail(samples != NULL);
+// memcpy(samples,(gint16
+//*)GST_BUFFER_DATA(buf),GST_BUFFER_DATASIZE(buf));
+// gst_buffer_unref(buf);
+ samples = (gint16 *)GST_BUFFER_DATA(buf);
+
+// return;
+// spec_base = (gint) (log(samplecount) / log(2));
+// if (spec_base > 10) spec_base = 10;
+// spec_len = (gint) pow(2, spec_base);
+ spec_base = 8;
+ spec_len = 1024;
+
+ im = g_malloc(spec_len * sizeof(gint16));
+ g_return_if_fail(im != NULL);
+ loud = g_malloc(spec_len * sizeof(gint16));
+ g_return_if_fail(loud != NULL);
+
+ memset(im,0,spec_len * sizeof(gint16));
+ //if (spectrum->meta->channels == 2) {
+ re = g_malloc(spec_len * sizeof(gint16));
+ for (i=0;i<spec_len;i++)
+ re[i] = (samples[(i*2)] + samples[(i*2)+1]) >> 1;
+ //} else
+ // re = samples;
+ gst_spectrum_window(re,spec_len);
+ gst_spectrum_fix_fft(re,im,spec_base,FALSE);
+ gst_spectrum_fix_loud(loud,re,im,spec_len,0);
+ if (re != samples) g_free(re);
+ g_free(im);
+ step = spec_len / (spectrum->width*2);
+ spect = (guchar *)g_malloc(spectrum->width);
+ for (i=0,pos=0;i<spectrum->width;i++,pos += step) {
+ if (loud[pos] > -60)
+ spect[i] = (loud[pos] + 60) / 2;
+ else
+ spect[i] = 0;
+// if (spect[i] > 15);
+// spect[i] = 15;
+ }
+ g_free(loud);
+ gst_buffer_unref(buf);
+// g_free(samples);
+
+ newbuf = gst_buffer_new();
+ g_return_if_fail(newbuf != NULL);
+ GST_BUFFER_DATA(newbuf) = spect;
+ GST_BUFFER_SIZE(newbuf) = spectrum->width;
+
+ gst_pad_push(spectrum->srcpad,newbuf);
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the spectrum element */
+ factory = gst_elementfactory_new ("spectrum",GST_TYPE_SPECTRUM,
+ &gst_spectrum_details);
+ g_return_val_if_fail (factory != NULL, FALSE);
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "spectrum",
+ plugin_init
+};
diff --git a/gst/spectrum/gstspectrum.h b/gst/spectrum/gstspectrum.h
new file mode 100644
index 00000000..f7a395ec
--- /dev/null
+++ b/gst/spectrum/gstspectrum.h
@@ -0,0 +1,67 @@
+/* Gnome-Streamer
+ * 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_SPECTRUM_H__
+#define __GST_SPECTRUM_H__
+
+
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_SPECTRUM \
+ (gst_spectrum_get_type())
+#define GST_SPECTRUM(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPECTRUM,GstSpectrum))
+#define GST_SPECTRUM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPECTRUM,GstSpectrum))
+#define GST_IS_SPECTRUM(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPECTRUM))
+#define GST_IS_SPECTRUM_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPECTRUM))
+
+typedef struct _GstSpectrum GstSpectrum;
+typedef struct _GstSpectrumClass GstSpectrumClass;
+
+struct _GstSpectrum {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gint width;
+};
+
+struct _GstSpectrumClass {
+ GstElementClass parent_class;
+};
+
+GType gst_spectrum_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_SPECTRUM_H__ */
diff --git a/gst/speed/Makefile.am b/gst/speed/Makefile.am
new file mode 100644
index 00000000..35aed207
--- /dev/null
+++ b/gst/speed/Makefile.am
@@ -0,0 +1,8 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstspeed.la
+
+libgstspeed_la_SOURCES = gstspeed.c
+libgstspeed_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gstspeed.h filter.func
diff --git a/gst/speed/filter.func b/gst/speed/filter.func
new file mode 100644
index 00000000..89429528
--- /dev/null
+++ b/gst/speed/filter.func
@@ -0,0 +1,66 @@
+/* -*- Mode: c; c-basic-offset: 2 -*- */
+ _FORMAT *in_data, *out_data;
+
+ /* get a buffer here so that we can have something to interpolate
+ * against for the first few samples if speed < 0.5 */
+ in_data = (_FORMAT*) GST_BUFFER_DATA(in);
+ nin = GST_BUFFER_SIZE(in)/sizeof(_FORMAT);
+ lower = in_data[0];
+ i_float = 0.5 * (speed - 1.0);
+ i = i_float + 1.0; /* ciel(i_float) for ints */
+
+ do {
+ speed = filter->speed; /* update this, it might have changed */
+
+ if (filter->srcpool) {
+ out = gst_buffer_new_from_pool(filter->srcpool, 0, 0);
+ out_data = (_FORMAT*) GST_BUFFER_DATA(out);
+ } else {
+ out = gst_buffer_new();
+ GST_BUFFER_DATA(out) = (gchar*) g_new(_FORMAT,SPEED_BUFSIZE/sizeof(_FORMAT));
+ GST_BUFFER_SIZE(out) = SPEED_BUFSIZE;
+ out_data = (_FORMAT*) GST_BUFFER_DATA(out);
+ }
+ nout = GST_BUFFER_SIZE(out) / sizeof(_FORMAT);
+
+ for (j=0; j<nout; j++) {
+ /* index of upper bounds of interpolation for
+ * new sample, got it by trial&error on the chalkboard */
+ i_float += speed;
+ i = i_float + 1.0; /* ciel(i_float) for ints */
+
+ while (i >= nin) {
+ i = i % nin;
+ i_float = i_float - nin;
+ lower = in_data[nin-1];
+ gst_buffer_unref(in);
+ in = gst_pad_pull (filter->sinkpad);
+
+ while (GST_IS_EVENT(in)) {
+ switch (GST_EVENT_TYPE(in)) {
+ case GST_EVENT_EOS:
+ gst_element_set_state((GstElement*)filter, GST_STATE_PAUSED);
+ gst_pad_push(filter->srcpad, in);
+ return;
+ default:
+ gst_pad_push(filter->srcpad, in);
+ in = gst_pad_pull (filter->sinkpad);
+ }
+ }
+
+ in_data = (_FORMAT*) GST_BUFFER_DATA(in);
+ nin = GST_BUFFER_SIZE(in) / sizeof(_FORMAT);
+ }
+
+ if (i>0)
+ lower = in_data[i-1];
+
+ interp = i_float - floor(i_float);
+
+ out_data[j] = lower*(1-interp) + in_data[i]*interp;
+
+ lower = in_data[i];
+ }
+
+ gst_pad_push(filter->srcpad, out);
+ } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element));
diff --git a/gst/speed/gstspeed.c b/gst/speed/gstspeed.c
new file mode 100644
index 00000000..51811227
--- /dev/null
+++ b/gst/speed/gstspeed.c
@@ -0,0 +1,347 @@
+/* -*- c-basic-offset: 2 -*-
+ * GStreamer
+ * Copyright (C) 1999-2001 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.
+ */
+
+#include <string.h>
+#include <gst/gst.h>
+#include <math.h>
+#include <libs/audio/gstaudio.h>
+#include "gstspeed.h"
+
+/* buffer size to make if no bufferpool is available, must be divisible by
+ * sizeof(gfloat) */
+#define SPEED_BUFSIZE 4096
+/* number of buffers to allocate per chunk in sink buffer pool */
+#define SPEED_NUMBUF 6
+
+static GstElementDetails speed_details = {
+ "Speed",
+ "Filter/Effect",
+ "Set speed/pitch on audio/raw streams (resampler)",
+ VERSION,
+ "Andy Wingo <apwingo@eos.ncsu.edu>",
+ "(C) 2001"
+};
+
+
+/* Filter signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_SILENT,
+ ARG_SPEED
+};
+
+static GstPadTemplate*
+speed_sink_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template) {
+ template = gst_padtemplate_new
+ ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ gst_caps_append(gst_caps_new ("sink_int", "audio/raw",
+ GST_AUDIO_INT_MONO_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("sink_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS)),
+ NULL);
+ }
+ return template;
+}
+
+static GstPadTemplate*
+speed_src_factory (void)
+{
+ static GstPadTemplate *template = NULL;
+
+ if (!template)
+ template = gst_padtemplate_new
+ ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ gst_caps_append (gst_caps_new ("src_float", "audio/raw",
+ GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS),
+ gst_caps_new ("src_int", "audio/raw",
+ GST_AUDIO_INT_MONO_PAD_TEMPLATE_PROPS)),
+ NULL);
+
+ return template;
+}
+
+static GstBufferPool*
+speed_sink_get_bufferpool (GstPad *pad)
+{
+ GstSpeed *filter;
+
+ filter = GST_SPEED (gst_pad_get_parent(pad));
+
+ return filter->sinkpool;
+}
+
+static void speed_class_init (GstSpeedClass *klass);
+static void speed_init (GstSpeed *filter);
+
+static void speed_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void speed_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static gint speed_parse_caps (GstSpeed *filter, GstCaps *caps);
+
+static void speed_loop (GstElement *element);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_filter_signals[LAST_SIGNAL] = { 0 };
+
+static GstPadNegotiateReturn
+speed_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstSpeed* filter = GST_SPEED (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (speed_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->sinkpad,caps);
+}
+
+static GstPadNegotiateReturn
+speed_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+{
+ GstSpeed* filter = GST_SPEED (gst_pad_get_parent (pad));
+
+ if (*caps==NULL)
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ if (speed_parse_caps(filter, *caps))
+ return GST_PAD_NEGOTIATE_FAIL;
+
+ return gst_pad_negotiate_proxy(pad,filter->srcpad,caps);
+}
+
+static gint
+speed_parse_caps (GstSpeed *filter, GstCaps *caps)
+{
+ const gchar *format;
+
+ g_return_val_if_fail(filter!=NULL,-1);
+ g_return_val_if_fail(caps!=NULL,-1);
+
+ format = gst_caps_get_string(caps, "format");
+
+ filter->rate = gst_caps_get_int (caps, "rate");
+ filter->channels = gst_caps_get_int (caps, "channels");
+
+ if (strcmp(format, "int")==0) {
+ filter->format = GST_SPEED_FORMAT_INT;
+ filter->width = gst_caps_get_int (caps, "width");
+ filter->depth = gst_caps_get_int (caps, "depth");
+ filter->law = gst_caps_get_int (caps, "law");
+ filter->endianness = gst_caps_get_int (caps, "endianness");
+ filter->is_signed = gst_caps_get_int (caps, "signed");
+ if (!filter->silent) {
+ g_print ("Speed : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("Speed : format int, bit width %d, endianness %d, signed %s\n",
+ filter->width, filter->endianness, filter->is_signed ? "yes" : "no");
+ }
+ } else if (strcmp(format, "float")==0) {
+ filter->format = GST_SPEED_FORMAT_FLOAT;
+ filter->layout = gst_caps_get_string(caps, "layout");
+ filter->intercept = gst_caps_get_float(caps, "intercept");
+ filter->slope = gst_caps_get_float(caps, "slope");
+ if (!filter->silent) {
+ g_print ("Speed : channels %d, rate %d\n",
+ filter->channels, filter->rate);
+ g_print ("Speed : format float, layout %s, intercept %f, slope %f\n",
+ filter->layout, filter->intercept, filter->slope);
+ }
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+GType
+gst_speed_get_type(void) {
+ static GType speed_type = 0;
+
+ if (!speed_type) {
+ static const GTypeInfo speed_info = {
+ sizeof(GstSpeedClass), NULL,
+ NULL,
+ (GClassInitFunc)speed_class_init,
+ NULL,
+ NULL,
+ sizeof(GstSpeed),
+ 0,
+ (GInstanceInitFunc)speed_init,
+ };
+ speed_type = g_type_register_static(GST_TYPE_ELEMENT, "GstSpeed", &speed_info, 0);
+ }
+ return speed_type;
+}
+
+static void
+speed_class_init (GstSpeedClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SILENT,
+ g_param_spec_boolean("silent","silent","silent",
+ TRUE,G_PARAM_READWRITE)); // CHECKME
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SPEED,
+ g_param_spec_float("speed","speed","speed",
+ 0.1,40.0,1.0,G_PARAM_READWRITE));
+
+ gobject_class->set_property = speed_set_property;
+ gobject_class->get_property = speed_get_property;
+}
+
+static void
+speed_init (GstSpeed *filter)
+{
+ filter->sinkpad = gst_pad_new_from_template(speed_sink_factory (),"sink");
+ gst_pad_set_negotiate_function(filter->sinkpad,speed_negotiate_sink);
+ gst_pad_set_bufferpool_function (filter->sinkpad, speed_sink_get_bufferpool);
+ filter->srcpad = gst_pad_new_from_template(speed_src_factory (),"src");
+ gst_pad_set_negotiate_function(filter->srcpad,speed_negotiate_src);
+
+ gst_element_add_pad(GST_ELEMENT(filter),filter->sinkpad);
+ gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
+ gst_element_set_loop_function(GST_ELEMENT(filter),speed_loop);
+ filter->silent = FALSE;
+ filter->speed = 1.0;
+
+ filter->sinkpool = gst_buffer_pool_get_default(SPEED_BUFSIZE,
+ SPEED_NUMBUF);
+}
+
+static void
+speed_loop (GstElement *element)
+{
+ GstSpeed *filter = GST_SPEED(element);
+ GstBuffer *in, *out;
+ guint i, j, nin, nout;
+ gfloat interp, speed, lower, i_float;
+
+ g_return_if_fail(filter != NULL);
+ g_return_if_fail(GST_IS_SPEED(filter));
+
+ filter->srcpool = gst_pad_get_bufferpool(filter->srcpad);
+
+ i = j = 0;
+ speed = filter->speed;
+
+ in = gst_pad_pull(filter->sinkpad);
+
+ /* this is a bit nasty, but hey, it's what you've got to do to keep the same
+ * algorithm and multiple data types in c. */
+ if (filter->format==GST_SPEED_FORMAT_FLOAT) {
+#define _FORMAT gfloat
+#include "filter.func"
+#undef _FORMAT
+ } else if (filter->format==GST_SPEED_FORMAT_INT && filter->width==16) {
+#define _FORMAT gint16
+#include "filter.func"
+#undef _FORMAT
+ } else if (filter->format==GST_SPEED_FORMAT_INT && filter->width==8) {
+#define _FORMAT gint8
+#include "filter.func"
+#undef _FORMAT
+ }
+}
+
+static void
+speed_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstSpeed *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SPEED(object));
+ filter = GST_SPEED(object);
+
+ switch (prop_id)
+ {
+ case ARG_SILENT:
+ filter->silent = g_value_get_boolean (value);
+ break;
+ case ARG_SPEED:
+ filter->speed = g_value_get_float (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+speed_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstSpeed *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SPEED(object));
+ filter = GST_SPEED(object);
+
+ switch (prop_id) {
+ case ARG_SILENT:
+ g_value_set_boolean (value, filter->silent);
+ break;
+ case ARG_SPEED:
+ g_value_set_float (value, filter->speed);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("speed",GST_TYPE_SPEED,
+ &speed_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, speed_src_factory ());
+ gst_elementfactory_add_padtemplate (factory, speed_sink_factory ());
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "speed",
+ plugin_init
+};
diff --git a/gst/speed/gstspeed.h b/gst/speed/gstspeed.h
new file mode 100644
index 00000000..530a9dc8
--- /dev/null
+++ b/gst/speed/gstspeed.h
@@ -0,0 +1,106 @@
+/* -*- c-basic-offset: 2 -*-
+ * 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_SPEED_H__
+#define __GST_SPEED_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+// #include <gst/meta/audioraw.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_SPEED \
+ (gst_speed_get_type())
+#define GST_SPEED(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPEED,GstSpeed))
+#define GST_SPEED_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstSpeed))
+#define GST_IS_SPEED(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPEED))
+#define GST_IS_SPEED_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPEED))
+
+typedef struct _GstSpeed GstSpeed;
+typedef struct _GstSpeedClass GstSpeedClass;
+typedef enum _GstSpeedFormat GstSpeedFormat;
+
+enum _GstSpeedFormat {
+ GST_SPEED_FORMAT_INT,
+ GST_SPEED_FORMAT_FLOAT
+};
+
+struct _GstSpeed {
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+ GstBufferPool *sinkpool, *srcpool;
+
+ gboolean silent;
+
+ gfloat speed;
+
+ /* the next three are valid for both int and float */
+
+ GstSpeedFormat format;
+
+ guint rate;
+
+ guint channels;
+
+ /* the next five are valid only for format==GST_SPEED_FORMAT_INT */
+
+ guint width;
+
+ guint depth;
+
+ guint endianness;
+
+ guint law;
+
+ gboolean is_signed;
+
+ /* the next three are valid only for format==GST_SPEED_FORMAT_FLOAT */
+
+ const gchar *layout;
+
+ gfloat slope;
+
+ gfloat intercept;
+};
+
+struct _GstSpeedClass {
+ GstElementClass parent_class;
+};
+
+GType gst_speed_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_SPEED_H__ */
diff --git a/gst/stereo/.gitignore b/gst/stereo/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/stereo/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/stereo/Makefile.am b/gst/stereo/Makefile.am
new file mode 100644
index 00000000..69e18c72
--- /dev/null
+++ b/gst/stereo/Makefile.am
@@ -0,0 +1,10 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgststereo.la
+
+libgststereo_la_SOURCES = gststereo.c
+libgststereo_la_CFLAGS = $(GST_CFLAGS)
+
+noinst_HEADERS = gststereo.h
+
+EXTRA_DIST = README
diff --git a/gst/stereo/README b/gst/stereo/README
new file mode 100644
index 00000000..a61e66ae
--- /dev/null
+++ b/gst/stereo/README
@@ -0,0 +1,3 @@
+This effect is borrowed from xmms-0.6.1, though I mangled it so badly in
+the process of copying it over that the xmms people probably won't want
+any credit for it ;-)
diff --git a/gst/stereo/gststereo.c b/gst/stereo/gststereo.c
new file mode 100644
index 00000000..622dd5d4
--- /dev/null
+++ b/gst/stereo/gststereo.c
@@ -0,0 +1,226 @@
+/* Gnome-Streamer
+ * 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.
+ */
+
+#include <gststereo.h>
+
+
+static GstElementDetails stereo_details = {
+ "Stereo effect",
+ "Filter/Effect",
+ "Muck with the stereo signal, enhance it's 'stereo-ness'",
+ VERSION,
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "(C) 1999",
+};
+
+
+/* Stereo signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_ACTIVE,
+ ARG_STEREO
+};
+
+
+static void gst_stereo_class_init (GstStereoClass *klass);
+static void gst_stereo_init (GstStereo *stereo);
+
+static void gst_stereo_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_stereo_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static void gst_stereo_chain (GstPad *pad, GstBuffer *buf);
+
+static GstElementClass *parent_class = NULL;
+//static guint gst_stereo_signals[LAST_SIGNAL] = { 0 };
+
+GType
+gst_stereo_get_type(void) {
+ static GType stereo_type = 0;
+
+ if (!stereo_type) {
+ static const GTypeInfo stereo_info = {
+ sizeof(GstStereoClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_stereo_class_init,
+ NULL,
+ NULL,
+ sizeof(GstStereo),
+ 0,
+ (GInstanceInitFunc)gst_stereo_init,
+ };
+ stereo_type = g_type_register_static(GST_TYPE_ELEMENT, "GstStereo", &stereo_info, 0);
+ }
+ return stereo_type;
+}
+
+static void
+gst_stereo_class_init (GstStereoClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ACTIVE,
+ g_param_spec_int("active","active","active",
+ G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_STEREO,
+ g_param_spec_float("stereo","stereo","stereo",
+ 0.0,1.0,0.0,G_PARAM_READWRITE)); // CHECKME
+
+ gobject_class->set_property = gst_stereo_set_property;
+ gobject_class->get_property = gst_stereo_get_property;
+}
+
+static void
+gst_stereo_init (GstStereo *stereo)
+{
+ stereo->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+ gst_element_add_pad(GST_ELEMENT(stereo),stereo->sinkpad);
+ gst_pad_set_chain_function(stereo->sinkpad,gst_stereo_chain);
+ stereo->srcpad = gst_pad_new("src",GST_PAD_SRC);
+ gst_element_add_pad(GST_ELEMENT(stereo),stereo->srcpad);
+
+ stereo->active = FALSE;
+ stereo->stereo = 2.5;
+}
+
+static void
+gst_stereo_chain (GstPad *pad,GstBuffer *buf)
+{
+ GstStereo *stereo;
+ gint16 *data;
+ gint samples;
+ gint i;
+ gdouble avg,ldiff,rdiff,tmp,mul;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ stereo = GST_STEREO(GST_OBJECT_PARENT (pad));
+ g_return_if_fail(stereo != NULL);
+ g_return_if_fail(GST_IS_STEREO(stereo));
+
+// FIXME
+// if (buf->meta)
+// memcpy(&stereo->meta,buf->meta,sizeof(stereo->meta));
+
+ if (stereo->active) {
+
+ //if (stereo->meta.channels == 2 && stereo->meta.format == AFMT_S16_LE) {
+ data = (gint16 *)GST_BUFFER_DATA(buf);
+ samples = GST_BUFFER_SIZE(buf) / 2;
+ mul = stereo->stereo;
+ for (i = 0; i < samples / 2; i += 2) {
+ avg = (data[i] + data[i + 1]) / 2;
+ ldiff = data[i] - avg;
+ rdiff = data[i + 1] - avg;
+
+ tmp = avg + ldiff * mul;
+ if (tmp < -32768)
+ tmp = -32768;
+ if (tmp > 32767)
+ tmp = 32767;
+ data[i] = tmp;
+
+ tmp = avg + rdiff * mul;
+ if (tmp < -32768)
+ tmp = -32768;
+ if (tmp > 32767)
+ tmp = 32767;
+ data[i + 1] = tmp;
+ }
+ //}
+ }
+
+ gst_pad_push(stereo->srcpad,buf);
+}
+
+static void
+gst_stereo_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstStereo *stereo;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_STEREO(object));
+ stereo = GST_STEREO(object);
+
+ switch (prop_id) {
+ case ARG_ACTIVE:
+ stereo->active = g_value_get_int (value);
+ break;
+ case ARG_STEREO:
+ stereo->stereo = g_value_get_float (value) * 10.0;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_stereo_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstStereo *stereo;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_STEREO(object));
+ stereo = GST_STEREO(object);
+
+ switch (prop_id) {
+ case ARG_ACTIVE:
+ g_value_set_int (value, stereo->active);
+ break;
+ case ARG_STEREO:
+ g_value_set_float (value, stereo->stereo / 10.0);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ factory = gst_elementfactory_new("stereo",GST_TYPE_STEREO,
+ &stereo_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "stereo",
+ plugin_init
+};
+
diff --git a/gst/stereo/gststereo.h b/gst/stereo/gststereo.h
new file mode 100644
index 00000000..f775f850
--- /dev/null
+++ b/gst/stereo/gststereo.h
@@ -0,0 +1,68 @@
+/* Gnome-Streamer
+ * 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_STEREO_H__
+#define __GST_STEREO_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_STEREO \
+ (gst_stereo_get_type())
+#define GST_STEREO(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STEREO,GstStereo))
+#define GST_STEREO_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STEREO,GstStereo))
+#define GST_IS_STEREO(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STEREO))
+#define GST_IS_STEREO_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STEREO))
+
+typedef struct _GstStereo GstStereo;
+typedef struct _GstStereoClass GstStereoClass;
+
+struct _GstStereo {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gint8 active;
+ gfloat stereo;
+};
+
+struct _GstStereoClass {
+ GstElementClass parent_class;
+};
+
+GType gst_stereo_get_type(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_STEREO_H__ */