From 8ebd13a68161e261c050e47cf7aab7d066ad3bed Mon Sep 17 00:00:00 2001 From: Stefan Kost Date: Sat, 24 Jan 2009 23:27:08 +0200 Subject: [PATCH] Bring synaesthesia to next century. Do proper size negotiation. Change engine API to allow resizes. Small cleanups elsewhere. --- gst/synaesthesia/gstsynaesthesia.c | 115 +++++++++++++---------------- gst/synaesthesia/gstsynaesthesia.h | 9 +-- gst/synaesthesia/synaescope.c | 99 +++++++++++++++++-------- gst/synaesthesia/synaescope.h | 13 +++- 4 files changed, 131 insertions(+), 105 deletions(-) diff --git a/gst/synaesthesia/gstsynaesthesia.c b/gst/synaesthesia/gstsynaesthesia.c index 1d166f0714..27ad4fd185 100644 --- a/gst/synaesthesia/gstsynaesthesia.c +++ b/gst/synaesthesia/gstsynaesthesia.c @@ -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++; } diff --git a/gst/synaesthesia/gstsynaesthesia.h b/gst/synaesthesia/gstsynaesthesia.h index 78ab69863f..dd63e56158 100644 --- a/gst/synaesthesia/gstsynaesthesia.h +++ b/gst/synaesthesia/gstsynaesthesia.h @@ -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__ */ diff --git a/gst/synaesthesia/synaescope.c b/gst/synaesthesia/synaescope.c index 64016c0a61..da38ce003a 100644 --- a/gst/synaesthesia/synaescope.c +++ b/gst/synaesthesia/synaescope.c @@ -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); } diff --git a/gst/synaesthesia/synaescope.h b/gst/synaesthesia/synaescope.h index d480dcdbfc..456f720334 100644 --- a/gst/synaesthesia/synaescope.h +++ b/gst/synaesthesia/synaescope.h @@ -23,11 +23,18 @@ #include +/* 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