Bring synaesthesia to next century.

Do proper size negotiation. Change engine API to allow resizes. Small cleanups elsewhere.
This commit is contained in:
Stefan Kost 2009-01-24 23:27:08 +02:00
parent d798fa10c9
commit 8ebd13a681
4 changed files with 131 additions and 105 deletions

View file

@ -38,7 +38,6 @@
#include "gstsynaesthesia.h"
/* elementfactory information */
static const GstElementDetails gst_synaesthesia_details =
GST_ELEMENT_DETAILS ("Synaesthesia",
@ -79,7 +78,7 @@ static GstFlowReturn gst_synaesthesia_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn
gst_synaesthesia_change_state (GstElement * element, GstStateChange transition);
static GstCaps *gst_synaesthesia_src_getcaps (GstPad * pad);
static gboolean gst_synaesthesia_src_negotiate (GstSynaesthesia * synaesthesia);
static gboolean gst_synaesthesia_src_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_synaesthesia_sink_setcaps (GstPad * pad, GstCaps * caps);
@ -157,8 +156,6 @@ gst_synaesthesia_init (GstSynaesthesia * synaesthesia)
synaesthesia->srcpad =
gst_pad_new_from_static_template (&gst_synaesthesia_src_template, "src");
gst_pad_set_getcaps_function (synaesthesia->srcpad,
GST_DEBUG_FUNCPTR (gst_synaesthesia_src_getcaps));
gst_pad_set_setcaps_function (synaesthesia->srcpad,
GST_DEBUG_FUNCPTR (gst_synaesthesia_src_setcaps));
gst_element_add_pad (GST_ELEMENT (synaesthesia), synaesthesia->srcpad);
@ -166,8 +163,8 @@ gst_synaesthesia_init (GstSynaesthesia * synaesthesia)
synaesthesia->adapter = gst_adapter_new ();
/* reset the initial video state */
synaesthesia->width = SYNAES_WIDTH;
synaesthesia->height = SYNAES_HEIGHT;
synaesthesia->width = 320;
synaesthesia->height = 200;
synaesthesia->fps_n = 25; /* desired frame rate */
synaesthesia->fps_d = 1;
synaesthesia->frame_duration = -1;
@ -178,10 +175,6 @@ gst_synaesthesia_init (GstSynaesthesia * synaesthesia)
synaesthesia->next_ts = GST_CLOCK_TIME_NONE;
/* FIXME: the size is currently ignored by the engine. It should
* not be, and also there should be a way to change the size later.
* We also need API to negotiate the spf (samples_per_frame)
* we can supply. */
synaesthesia->si =
synaesthesia_new (synaesthesia->width, synaesthesia->height);
}
@ -265,33 +258,52 @@ wrong_rate:
}
}
static GstCaps *
gst_synaesthesia_src_getcaps (GstPad * pad)
static gboolean
gst_synaesthesia_src_negotiate (GstSynaesthesia * synaesthesia)
{
GstSynaesthesia *synaesthesia;
GstCaps *caps;
const GstCaps *templcaps;
gint i;
GstCaps *othercaps, *target, *intersect;
GstStructure *structure;
const GstCaps *templ;
synaesthesia = GST_SYNAESTHESIA (gst_pad_get_parent (pad));
templcaps = gst_pad_get_pad_template_caps (pad);
caps = gst_caps_copy (templcaps);
templ = gst_pad_get_pad_template_caps (synaesthesia->srcpad);
for (i = 0; i < gst_caps_get_size (caps); i++) {
GstStructure *structure = gst_caps_get_structure (caps, i);
GST_DEBUG_OBJECT (synaesthesia, "performing negotiation");
gst_structure_set (structure,
"width", G_TYPE_INT, synaesthesia->width,
"height", G_TYPE_INT, synaesthesia->height,
"framerate", GST_TYPE_FRACTION, synaesthesia->fps_n,
synaesthesia->fps_d, NULL);
/* see what the peer can do */
othercaps = gst_pad_peer_get_caps (synaesthesia->srcpad);
if (othercaps) {
intersect = gst_caps_intersect (othercaps, templ);
gst_caps_unref (othercaps);
if (gst_caps_is_empty (intersect))
goto no_format;
target = gst_caps_copy_nth (intersect, 0);
gst_caps_unref (intersect);
} else {
target = gst_caps_ref ((GstCaps *) templ);
}
gst_object_unref (synaesthesia);
structure = gst_caps_get_structure (target, 0);
gst_structure_fixate_field_nearest_int (structure, "width",
synaesthesia->width);
gst_structure_fixate_field_nearest_int (structure, "height",
synaesthesia->height);
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
synaesthesia->fps_n, synaesthesia->fps_d);
GST_DEBUG ("final caps are %" GST_PTR_FORMAT, caps);
GST_DEBUG ("final caps are %" GST_PTR_FORMAT, target);
return caps;
gst_pad_set_caps (synaesthesia->srcpad, target);
gst_caps_unref (target);
return TRUE;
no_format:
{
gst_caps_unref (intersect);
return FALSE;
}
}
static gboolean
@ -312,23 +324,22 @@ gst_synaesthesia_src_setcaps (GstPad * pad, GstCaps * caps)
goto missing_caps_details;
}
if ((w != SYNAES_WIDTH) || (h != SYNAES_HEIGHT))
goto wrong_resolution;
synaesthesia->width = w;
synaesthesia->height = h;
synaesthesia->fps_n = num;
synaesthesia->fps_d = denom;
synaesthesia_resize (synaesthesia->si, synaesthesia->width,
synaesthesia->height);
synaesthesia->frame_duration = gst_util_uint64_scale_int (GST_SECOND,
synaesthesia->fps_d, synaesthesia->fps_n);
synaesthesia->spf = gst_util_uint64_scale_int (synaesthesia->rate,
synaesthesia->fps_d, synaesthesia->fps_n);
/* FIXME: the size is currently ignored by the engine. see comment above */
synaesthesia_close (synaesthesia->si);
synaesthesia->si =
synaesthesia_new (synaesthesia->width, synaesthesia->height);
GST_DEBUG_OBJECT (synaesthesia, "dimension %dx%d, framerate %d/%d, spf %d",
synaesthesia->width, synaesthesia->height,
synaesthesia->fps_n, synaesthesia->fps_d, synaesthesia->spf);
done:
gst_object_unref (synaesthesia);
@ -341,14 +352,6 @@ missing_caps_details:
res = FALSE;
goto done;
}
wrong_resolution:
{
GST_WARNING_OBJECT (synaesthesia,
"unsupported resolution: %d x %d (wanted %d x %d)", w, h, SYNAES_WIDTH,
SYNAES_HEIGHT);
res = FALSE;
goto done;
}
}
static GstFlowReturn
@ -360,7 +363,7 @@ gst_synaesthesia_chain (GstPad * pad, GstBuffer * buffer)
synaesthesia = GST_SYNAESTHESIA (gst_pad_get_parent (pad));
GST_DEBUG ("chainfunc called");
GST_LOG ("chainfunc called");
/* resync on DISCONT */
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
@ -369,16 +372,8 @@ gst_synaesthesia_chain (GstPad * pad, GstBuffer * buffer)
}
if (GST_PAD_CAPS (synaesthesia->srcpad) == NULL) {
GstCaps *target;
GST_DEBUG ("fixating");
if ((target = gst_synaesthesia_src_getcaps (synaesthesia->srcpad))) {
gst_pad_set_caps (synaesthesia->srcpad, target);
gst_caps_unref (target);
} else {
GST_DEBUG ("no caps on srcpad");
if (!gst_synaesthesia_src_negotiate (synaesthesia))
return GST_FLOW_NOT_NEGOTIATED;
}
}
/* Match timestamps from the incoming audio */
@ -388,15 +383,11 @@ gst_synaesthesia_chain (GstPad * pad, GstBuffer * buffer)
gst_adapter_push (synaesthesia->adapter, buffer);
/* this is what we want */
bytesperread = SYNAES_SAMPLES * synaesthesia->channels * sizeof (gint16);
/* FIXME: what about:
bytesperread = MAX (SYNAES_SAMPLES, synaesthesia->spf) * synaesthesia->channels * sizeof (gint16);
*/
bytesperread = MAX (FFT_BUFFER_SIZE, synaesthesia->spf) * synaesthesia->channels * sizeof (gint16);
/* this is what we have */
avail = gst_adapter_available (synaesthesia->adapter);
while (avail >
MAX (bytesperread,
synaesthesia->spf * synaesthesia->channels * sizeof (gint16))) {
while (avail > bytesperread) {
const guint16 *data =
(const guint16 *) gst_adapter_peek (synaesthesia->adapter,
bytesperread);
@ -405,7 +396,7 @@ gst_synaesthesia_chain (GstPad * pad, GstBuffer * buffer)
guint i;
/* deinterleave */
for (i = 0; i < SYNAES_SAMPLES; i++) {
for (i = 0; i < FFT_BUFFER_SIZE; i++) {
synaesthesia->datain[0][i] = *data++;
synaesthesia->datain[1][i] = *data++;
}

View file

@ -29,17 +29,11 @@
#include "synaescope.h"
G_BEGIN_DECLS
#define SYNAES_SAMPLES 512
#define SYNAES_WIDTH 320
#define SYNAES_HEIGHT 200
#define GST_TYPE_SYNAESTHESIA (gst_synaesthesia_get_type())
#define GST_SYNAESTHESIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYNAESTHESIA,GstSynaesthesia))
#define GST_SYNAESTHESIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYNAESTHESIA,GstSynaesthesiaClass))
#define GST_IS_SYNAESTHESIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYNAESTHESIA))
#define GST_IS_SYNAESTHESIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYNAESTHESIA))
typedef struct _GstSynaesthesia GstSynaesthesia;
typedef struct _GstSynaesthesiaClass GstSynaesthesiaClass;
@ -59,7 +53,7 @@ struct _GstSynaesthesia
guint bps; /* bytes per sample */
guint spf; /* samples per video frame */
gint16 datain[2][SYNAES_SAMPLES];
gint16 datain[2][FFT_BUFFER_SIZE];
/* video state */
gint fps_n, fps_d;
@ -83,5 +77,4 @@ struct _GstSynaesthesiaClass
GType gst_synaesthesia_get_type (void);
G_END_DECLS
#endif /* __GST_SYNAESTHESIA_H__ */

View file

@ -47,11 +47,6 @@
#define SCOPE_BG_GREEN 0
#define SCOPE_BG_BLUE 0
#define FFT_BUFFER_SIZE_LOG 9
#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG)
#define syn_width 320
#define syn_height 200
#define brightMin 200
#define brightMax 2000
#define brightDec 10
@ -65,10 +60,14 @@
/* Instance data */
struct syn_instance
{
/* options */
unsigned int resx, resy;
int autobrightness; /* Whether to use automatic brightness adjust */
unsigned int brightFactor;
unsigned char output[syn_width * syn_height * 2];
guint32 display[syn_width * syn_height];
/* data */
unsigned char *output;
guint32 *display;
gint16 pcmt_l[FFT_BUFFER_SIZE];
gint16 pcmt_r[FFT_BUFFER_SIZE];
gint16 pcm_l[FFT_BUFFER_SIZE];
@ -92,14 +91,14 @@ static void synaes_fft (double *x, double *y);
static void synaescope_coreGo (syn_instance * si);
static inline void
addPixel (unsigned char *output, int x, int y, int br1, int br2)
addPixel (syn_instance * si, int x, int y, int br1, int br2)
{
unsigned char *p;
if (x < 0 || x >= syn_width || y < 0 || y >= syn_height)
if (G_UNLIKELY (x < 0 || x >= si->resx || y < 0 || y >= si->resy))
return;
p = output + x * 2 + y * syn_width * 2;
p = si->output + x * 2 + y * si->resx * 2;
if (p[0] < 255 - br1)
p[0] += br1;
else
@ -161,7 +160,7 @@ synaescope_coreGo (syn_instance * si)
/* Asger Alstrupt's optimized 32 bit fade */
/* (alstrup@diku.dk) */
ptr = (guint32 *) si->output;
end = (guint32 *) (si->output + syn_width * syn_height * 2);
end = (guint32 *) (si->output + si->resx * si->resy * 2);
do {
/*Bytewize version was: *(ptr++) -= *ptr+(*ptr>>1)>>4; */
if (*ptr) {
@ -181,22 +180,22 @@ synaescope_coreGo (syn_instance * si)
ptr++;
} while (ptr < end);
heightFactor = FFT_BUFFER_SIZE / 2 / syn_height + 1;
heightFactor = FFT_BUFFER_SIZE / 2 / si->resy + 1;
actualHeight = FFT_BUFFER_SIZE / 2 / heightFactor;
heightAdd = (syn_height + actualHeight) >> 1;
heightAdd = (si->resy + actualHeight) >> 1;
/* Correct for window size */
brightFactor2 = (si->brightFactor / 65536.0 / FFT_BUFFER_SIZE) *
sqrt (actualHeight * syn_width / (320.0 * 200.0));
sqrt (actualHeight * si->resx / (320.0 * 200.0));
brtot = 0;
for (i = 1; i < FFT_BUFFER_SIZE / 2; i++) {
/*int h = (int)( corr_r[i]*280 / (corr_l[i]+corr_r[i]+0.0001)+20 ); */
if (si->corr_l[i] > 0 || si->corr_r[i] > 0) {
int h =
(int) (si->corr_r[i] * syn_width / (si->corr_l[i] + si->corr_r[i]));
(int) (si->corr_r[i] * si->resx / (si->corr_l[i] + si->corr_r[i]));
/* int h = (int)( syn_width - 1 ); */
/* int h = (int)( si->resx - 1 ); */
int br1, br2, br =
(int) ((si->corr_l[i] + si->corr_r[i]) * i * brightFactor2);
int px = h, py = heightAdd - i / heightFactor;
@ -212,19 +211,19 @@ synaescope_coreGo (syn_instance * si)
br2 = 0;
else if (br2 > 255)
br2 = 255;
/*unsigned char *p = output+ h*2+(164-((i<<8)>>FFT_BUFFER_SIZE_LOG))*(syn_width*2); */
/*unsigned char *p = output+ h*2+(164-((i<<8)>>FFT_BUFFER_SIZE_LOG))*(si->resx*2); */
if (px < 30 || py < 30 || px > syn_width - 30 || py > syn_height - 30) {
addPixel (si->output, px, py, br1, br2);
if (px < 30 || py < 30 || px > si->resx - 30 || py > si->resy - 30) {
addPixel (si, px, py, br1, br2);
for (j = 1; br1 > 0 || br2 > 0;
j++, br1 = scaleDown[br1], br2 = scaleDown[br2]) {
addPixel (si->output, px + j, py, br1, br2);
addPixel (si->output, px, py + j, br1, br2);
addPixel (si->output, px - j, py, br1, br2);
addPixel (si->output, px, py - j, br1, br2);
addPixel (si, px + j, py, br1, br2);
addPixel (si, px, py + j, br1, br2);
addPixel (si, px - j, py, br1, br2);
addPixel (si, px, py - j, br1, br2);
}
} else {
unsigned char *p = si->output + px * 2 + py * syn_width * 2, *p1 =
unsigned char *p = si->output + px * 2 + py * si->resx * 2, *p1 =
p, *p2 = p, *p3 = p, *p4 = p;
addPixelFast (p, br1, br2);
for (; br1 > 0 || br2 > 0; br1 = scaleDown[br1], br2 = scaleDown[br2]) {
@ -232,9 +231,9 @@ synaescope_coreGo (syn_instance * si)
addPixelFast (p1, br1, br2);
p2 -= 2;
addPixelFast (p2, br1, br2);
p3 += syn_width * 2;
p3 += si->resx * 2;
addPixelFast (p3, br1, br2);
p4 -= syn_width * 2;
p4 -= si->resx * 2;
addPixelFast (p4, br1, br2);
}
}
@ -274,7 +273,7 @@ synaescope32 (syn_instance * si)
synaescope_coreGo (si);
outptr = si->output;
for (i = 0; i < syn_width * syn_height; i++) {
for (i = 0; i < si->resx * si->resy; i++) {
si->display[i] = colEq[(outptr[0] >> 4) + (outptr[1] & 0xf0)];
outptr += 2;
}
@ -326,7 +325,7 @@ synaes_fft (double *x, double *y)
}
static void
synaescope_set_data (syn_instance * si, gint16 data[2][512])
synaescope_set_data (syn_instance * si, gint16 data[2][FFT_BUFFER_SIZE])
{
int i;
gint16 *newset_l = si->pcmt_l;
@ -340,7 +339,7 @@ synaescope_set_data (syn_instance * si, gint16 data[2][512])
guint32 *
synaesthesia_update (syn_instance * si, gint16 data[2][512])
synaesthesia_update (syn_instance * si, gint16 data[2][FFT_BUFFER_SIZE])
{
synaescope_set_data (si, data);
synaescope32 (si);
@ -390,8 +389,38 @@ synaesthesia_init ()
inited = 1;
}
gboolean
synaesthesia_resize (syn_instance * si, guint resx, guint resy)
{
unsigned char *output = NULL;
guint32 *display = NULL;
/* FIXME: FFT_BUFFER_SIZE is reated to resy, right now we get black borders on
* top and below
*/
output = g_try_new (unsigned char, 2 * resx * resy);
display = g_try_new (guint32, resx * resy);
if (!output || !display)
goto Error;
g_free (si->output);
g_free (si->display);
si->resx = resx;
si->resy = resy;
si->output = output;
si->display = display;
return TRUE;
Error:
g_free (output);
g_free (display);
return FALSE;
}
syn_instance *
synaesthesia_new (guint32 resx, guint32 resy)
synaesthesia_new (guint resx, guint resy)
{
syn_instance *si;
@ -399,11 +428,14 @@ synaesthesia_new (guint32 resx, guint32 resy)
if (si == NULL)
return NULL;
if (!synaesthesia_resize (si, resx, resy)) {
g_free (si);
return NULL;
}
si->autobrightness = 1; /* Whether to use automatic brightness adjust */
si->brightFactor = 400;
/* FIXME: Make the width and height configurable? */
return si;
}
@ -412,5 +444,8 @@ synaesthesia_close (syn_instance * si)
{
g_return_if_fail (si != NULL);
g_free (si->output);
g_free (si->display);
g_free (si);
}

View file

@ -23,11 +23,18 @@
#include <glib.h>
/* FIXME: we should set this automatically based on height */
#define FFT_BUFFER_SIZE_LOG 10
#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG)
typedef struct syn_instance syn_instance;
void synaesthesia_init ();
syn_instance *synaesthesia_new (guint32 resx, guint32 resy);
void synaesthesia_close (syn_instance *si);
guint32 * synaesthesia_update (syn_instance *si, gint16 data [2][512]);
syn_instance *synaesthesia_new (guint resx, guint resy);
void synaesthesia_close (syn_instance * si);
gboolean synaesthesia_resize (syn_instance * si, guint resx, guint resy);
guint32 *synaesthesia_update (syn_instance * si,
gint16 data[2][FFT_BUFFER_SIZE]);
#endif