Initial revision

Original commit message from CVS:
Initial revision
This commit is contained in:
Andy Wingo 2001-12-22 23:26:33 +00:00
parent e5d9d6e2a5
commit ad6ed7da2d
69 changed files with 12465 additions and 0 deletions

7
gst/chart/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

4
gst/chart/Makefile.am Normal file
View file

@ -0,0 +1,4 @@
filterdir = $(libdir)/gst
filter_LTLIBRARIES = libchart.la
libchart_la_SOURCES = gstchart.c
libchart_la_CFLAGS = $(GST_CFLAGS)

456
gst/chart/gstchart.c Normal file
View file

@ -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
};

7
gst/deinterlace/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -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

View file

@ -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
};

View file

@ -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__ */

9
gst/flx/Makefile.am Normal file
View file

@ -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

94
gst/flx/flx_color.c Normal file
View file

@ -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;
}

43
gst/flx/flx_color.h Normal file
View file

@ -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);

136
gst/flx/flx_fmt.h Normal file
View file

@ -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__ */

644
gst/flx/gstflxdec.c Normal file
View file

@ -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
};

79
gst/flx/gstflxdec.h Normal file
View file

@ -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__ */

7
gst/mpeg1sys/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

13
gst/mpeg1sys/Makefile.am Normal file
View file

@ -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)

482
gst/mpeg1sys/buffer.c Normal file
View file

@ -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;
}

141
gst/mpeg1sys/buffer.h Normal file
View file

@ -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__ */

View file

@ -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
};

View file

@ -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__ */

140
gst/mpeg1sys/main.h Normal file
View file

@ -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

290
gst/mpeg1sys/systems.c Normal file
View file

@ -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);
}
}

7
gst/mpeg2sub/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

18
gst/mpeg2sub/Makefile.am Normal file
View file

@ -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

324
gst/mpeg2sub/Notes.txt Normal file
View file

@ -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>

443
gst/mpeg2sub/gstmpeg2subt.c Normal file
View file

@ -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
};

View file

@ -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__ */

View file

@ -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?

12
gst/mpegaudioparse/README Normal file
View file

@ -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.

View file

@ -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
};

View file

@ -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
};

View file

@ -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__ */

7
gst/passthrough/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -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 =

View file

@ -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;
}

View file

@ -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
};

View file

@ -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__ */

View file

@ -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

View file

@ -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));

View file

@ -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
};

View file

@ -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__ */

7
gst/rtjpeg/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

8
gst/rtjpeg/Makefile.am Normal file
View file

@ -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

12
gst/rtjpeg/README Normal file
View file

@ -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.

3434
gst/rtjpeg/RTjpeg.c Normal file

File diff suppressed because it is too large Load diff

53
gst/rtjpeg/RTjpeg.h Normal file
View file

@ -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);

62
gst/rtjpeg/gstrtjpeg.c Normal file
View file

@ -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
};

114
gst/rtjpeg/gstrtjpegdec.c Normal file
View file

@ -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);
}

71
gst/rtjpeg/gstrtjpegdec.h Normal file
View file

@ -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__ */

112
gst/rtjpeg/gstrtjpegenc.c Normal file
View file

@ -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);
}

72
gst/rtjpeg/gstrtjpegenc.h Normal file
View file

@ -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__ */

7
gst/smooth/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

8
gst/smooth/Makefile.am Normal file
View file

@ -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

362
gst/smooth/gstsmooth.c Normal file
View file

@ -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
};

75
gst/smooth/gstsmooth.h Normal file
View file

@ -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__ */

7
gst/spectrum/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

10
gst/spectrum/Makefile.am Normal file
View file

@ -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

5
gst/spectrum/README Normal file
View file

@ -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.

452
gst/spectrum/fix_fft.c Normal file
View file

@ -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,
};

242
gst/spectrum/gstspectrum.c Normal file
View file

@ -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
};

View file

@ -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__ */

8
gst/speed/Makefile.am Normal file
View file

@ -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

66
gst/speed/filter.func Normal file
View file

@ -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));

347
gst/speed/gstspeed.c Normal file
View file

@ -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
};

106
gst/speed/gstspeed.h Normal file
View file

@ -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__ */

7
gst/stereo/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

10
gst/stereo/Makefile.am Normal file
View file

@ -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

3
gst/stereo/README Normal file
View file

@ -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 ;-)

226
gst/stereo/gststereo.c Normal file
View file

@ -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
};

68
gst/stereo/gststereo.h Normal file
View file

@ -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__ */