AG_GST_DEFAULT_ELEMENTS
dnl *** plug-ins to include ***
- fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
+dnl Non ported plugins (non-dependant, then dependant)
+dnl Make sure you have a space before and after all plugins
+GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
+ autoconvert camerabin cdxaparse coloreffects \
+ dccp debugutils dtmf faceoverlay festival \
- musepack musicbrainz nas neon ofa openal rsvg schro sdl sndfile soundtouch spandsp timidity \
++ fieldanalysis freeverb freeze frei0r gaudieffects geometrictransform h264parse \
+ hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
+ kate liveadder legacyresample librfb mpegdemux mpegtsmux \
+ mpegpsmux mpegvideoparse mve mxf mythtv nsf nuvdemux \
+ patchdetect pcapparse pnm rawparse real removesilence rtpmux rtpvp8 scaletempo \
+ sdi segmentclip siren speed subenc stereo tta videofilters \
+ videomaxrate videomeasure videoparsers videosignal vmnc \
+ decklink fbdev linsys shm vcd \
+ voaacenc apexsink bz2 camerabin2 cdaudio celt cog curl dc1394 dirac directfb dts resindvd \
+ gsettings gsm jp2k ladspa modplug mpeg2enc mplex mimic \
++ musepack musicbrainz nas neon ofa openal rsvg schro sdl smooth sndfile soundtouch spandsp timidity \
+ wildmidi xvid "
+AC_SUBST(GST_PLUGINS_NONPORTED)
dnl these are all the gst plug-ins, compilable without additional libs
AG_GST_CHECK_PLUGIN(adpcmdec)
size = 0;
}
- samples =
- opus_packet_get_samples_per_frame (data,
- dec->sample_rate) * opus_packet_get_nb_frames (data, size);
- GST_DEBUG ("bandwidth %d", opus_packet_get_bandwidth (data));
- GST_DEBUG ("samples %d", samples);
+ if (data) {
+ samples =
+ opus_packet_get_samples_per_frame (data,
+ dec->sample_rate) * opus_packet_get_nb_frames (data, size);
+ packet_size = samples * dec->n_channels * 2;
+ GST_DEBUG_OBJECT (dec, "bandwidth %d", opus_packet_get_bandwidth (data));
+ GST_DEBUG_OBJECT (dec, "samples %d", samples);
+ } else {
+ /* use maximum size (120 ms) as we do now know in advance how many samples
+ will be returned */
+ samples = 120 * dec->sample_rate / 1000;
+ }
- packet_size = samples * dec->n_channels * 2;
-
- res = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec),
- GST_BUFFER_OFFSET_NONE, packet_size,
- GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dec)), &outbuf);
- if (res != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (dec, "buf alloc flow: %s", gst_flow_get_name (res));
- return res;
+ packet_size = samples * dec->n_channels * 2;
+ outbuf = gst_buffer_new_and_alloc (packet_size);
+ if (!outbuf) {
+ goto buffer_failed;
}
- out_data = (gint16 *) GST_BUFFER_DATA (outbuf);
+ out_data = (gint16 *) gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE);
- GST_LOG_OBJECT (dec, "decoding %d samples, in size %u", samples, size);
-
n = opus_decode (dec->state, data, size, out_data, samples, 0);
+ gst_buffer_unmap (buf, data, size);
+ gst_buffer_unmap (outbuf, out_data, out_size);
if (n < 0) {
GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL));
return GST_FLOW_ERROR;
if (size1 != size2)
return FALSE;
- return !memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2), size1);
+ data1 = gst_buffer_map (buf1, NULL, NULL, GST_MAP_READ);
+ res = gst_buffer_memcmp (buf2, 0, data1, size1) == 0;
+ gst_buffer_unmap (buf1, data1, size1);
+
+ return res;
}
- static gboolean
- gst_opus_dec_is_header (GstBuffer * buf, const char *magic, guint magic_size)
- {
- guint8 *data;
- gsize size;
- gboolean ret;
-
- data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
- if (!data)
- return FALSE;
- ret = (size >= magic_size && !memcmp (magic, data, magic_size));
- gst_buffer_unmap (buf, data, size);
- return ret;
- }
-
static GstFlowReturn
gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
{
return id;
}
- #define FORMAT_STR GST_AUDIO_NE(S16)
+ #define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type())
+ static GType
+ gst_opus_enc_frame_size_get_type (void)
+ {
+ static const GEnumValue values[] = {
+ {2, "2.5", "2.5"},
+ {5, "5", "5"},
+ {10, "10", "10"},
+ {20, "20", "20"},
+ {40, "40", "40"},
+ {60, "60", "60"},
+ {0, NULL, NULL}
+ };
+ static volatile GType id = 0;
+ if (g_once_init_enter ((gsize *) & id)) {
+ GType _id;
+
+ _id = g_enum_register_static ("GstOpusEncFrameSize", values);
+
+ g_once_init_leave ((gsize *) & id, _id);
+ }
+
+ return id;
+ }
+
++#define FORMAT_STR GST_AUDIO_NE(S16)
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage",
"Loss percentage", "Packet loss percentage", 0, 100,
DEFAULT_PACKET_LOSS_PERCENT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_PLAYING));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size",
+ "Max payload size", "Maximum payload size in bytes", 2, 1275,
+ DEFAULT_MAX_PAYLOAD_SIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_PLAYING));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize);
+
+ GST_DEBUG_CATEGORY_INIT (opusenc_debug, "opusenc", 0, "Opus encoder");
}
static void
{
guint8 *bdata, *data, *mdata = NULL;
gsize bsize, size;
- gsize bytes;
+ gsize bytes = enc->frame_samples * enc->n_channels * 2;
- gsize bytes_per_packet =
- (enc->bitrate * enc->frame_samples / enc->sample_rate + 4) / 8;
gint ret = GST_FLOW_OK;
- if (G_LIKELY (buf)) {
- bdata = GST_BUFFER_DATA (buf);
- bsize = GST_BUFFER_SIZE (buf);
- if (G_UNLIKELY (bsize % bytes)) {
- GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
-
- size = ((bsize / bytes) + 1) * bytes;
- mdata = g_malloc0 (size);
- memcpy (mdata, bdata, bsize);
- bdata = NULL;
- data = mdata;
- } else {
- data = bdata;
- size = bsize;
- }
- } else {
- GST_DEBUG_OBJECT (enc, "nothing to drain");
- goto done;
- }
-
- return ret;
- }
-
- static GstFlowReturn
- gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
- {
- guint8 *bdata, *data, *mdata = NULL;
- gsize bsize, size;
- gsize bytes = enc->frame_samples * enc->n_channels * 2;
- gsize bytes_per_packet =
- (enc->bitrate * enc->frame_samples / enc->sample_rate + 4) / 8;
- gint ret = GST_FLOW_OK;
+ g_mutex_lock (enc->property_lock);
- bytes = enc->frame_samples * enc->n_channels * 2;
if (G_LIKELY (buf)) {
- bdata = GST_BUFFER_DATA (buf);
- bsize = GST_BUFFER_SIZE (buf);
+ bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+
if (G_UNLIKELY (bsize % bytes)) {
GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
goto done;
}
-
while (size) {
- gint outsize;
+ gint encoded_size;
+ unsigned char *out_data;
+ gsize out_size;
GstBuffer *outbuf;
- outbuf = gst_buffer_new_and_alloc (bytes_per_packet);
- ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc),
- GST_BUFFER_OFFSET_NONE, enc->max_payload_size,
- GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf);
-
- if (GST_FLOW_OK != ret)
++ outbuf = gst_buffer_new_and_alloc (enc->max_payload_size);
+ if (!outbuf)
goto done;
- GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes) to %d bytes",
- enc->frame_samples, bytes, bytes_per_packet);
+ GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
+ enc->frame_samples);
- outsize =
+ out_data = gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE);
+ encoded_size =
opus_encode (enc->state, (const gint16 *) data, enc->frame_samples,
- out_data, bytes_per_packet);
- GST_BUFFER_DATA (outbuf), enc->max_payload_size);
++ out_data, enc->max_payload_size);
+ gst_buffer_unmap (outbuf, out_data, out_size);
- if (outsize < 0) {
- GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize);
+ if (encoded_size < 0) {
+ GST_ERROR_OBJECT (enc, "Encoding failed: %d", encoded_size);
ret = GST_FLOW_ERROR;
goto done;
- } else if (encoded_size != bytes_per_packet) {
- } else if (outsize > enc->max_payload_size) {
++ } else if (encoded_size > enc->max_payload_size) {
GST_WARNING_OBJECT (enc,
- "Encoded size %d is different from %d bytes per packet", encoded_size,
- bytes_per_packet);
+ "Encoded size %d is higher than max payload size (%d bytes)",
+ outsize, enc->max_payload_size);
ret = GST_FLOW_ERROR;
goto done;
}
done:
+ if (bdata)
+ gst_buffer_unmap (buf, bdata, bsize);
+ g_mutex_unlock (enc->property_lock);
+
if (mdata)
g_free (mdata);
gst_opus_parse_start (GstBaseParse * base)
{
GstOpusParse *parse = GST_OPUS_PARSE (base);
- GstCaps *caps;
+ caps = gst_caps_new_empty_simple ("audio/x-opus");
+ gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (parse)), caps);
+ gst_caps_unref (caps);
+
+ parse->header_sent = FALSE;
+ parse->next_ts = 0;
+
+ return TRUE;
+ }
+
+ static gboolean
+ gst_opus_parse_stop (GstBaseParse * base)
+ {
+ GstOpusParse *parse = GST_OPUS_PARSE (base);
+
+ g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL);
+ parse->headers = NULL;
+
+ parse->header_sent = FALSE;
+
return TRUE;
}
parse = GST_OPUS_PARSE (base);
- data = GST_BUFFER_DATA (frame->buffer);
- size = GST_BUFFER_SIZE (frame->buffer);
+ data = gst_buffer_map (frame->buffer, &size, NULL, GST_MAP_READ);
GST_DEBUG_OBJECT (parse, "Checking for frame, %u bytes in buffer", size);
- if (size < 4) {
- GST_DEBUG_OBJECT (parse, "Too small");
- goto beach;
- }
- packet_size = GST_READ_UINT32_BE (data);
- GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
- if (packet_size > MAX_PAYLOAD_BYTES) {
- GST_DEBUG_OBJECT (parse, "Too large");
- goto beach;
+
+ /* check for headers */
+ is_idheader = gst_opus_header_is_header (frame->buffer, "OpusHead", 8);
+ is_commentheader = gst_opus_header_is_header (frame->buffer, "OpusTags", 8);
+ is_header = is_idheader || is_commentheader;
+
+ if (!is_header) {
+ /* Next, check if there's an Opus packet there */
+ nframes =
+ opus_packet_parse (data, size, &toc, frames, frame_sizes,
+ &payload_offset);
}
- if (packet_size > size - 4) {
- GST_DEBUG_OBJECT (parse, "Truncated");
- goto beach;
+
+ if (!is_header && nframes < 0) {
+ /* Then, check for the test vector framing */
+ GST_DEBUG_OBJECT (parse,
+ "No Opus packet found, trying test vector framing");
+ if (size < 4) {
+ GST_DEBUG_OBJECT (parse, "Too small");
+ goto beach;
+ }
+ packet_size = GST_READ_UINT32_BE (data);
+ GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
+ if (packet_size > MAX_PAYLOAD_BYTES) {
+ GST_DEBUG_OBJECT (parse, "Too large");
+ goto beach;
+ }
+ if (packet_size > size - 4) {
+ GST_DEBUG_OBJECT (parse, "Truncated");
+ goto beach;
+ }
+ nframes =
+ opus_packet_parse (data + 8, packet_size, &toc, frames, frame_sizes,
+ &payload_offset);
+ if (nframes < 0) {
+ GST_DEBUG_OBJECT (parse, "No test vector framing either");
+ goto beach;
+ }
+
+ packet_offset = 8;
+ data += packet_offset;
}
- channels = opus_packet_get_nb_channels (data + 8);
- bandwidth = opus_packet_get_bandwidth (data + 8);
- if (channels < 0 || bandwidth < 0) {
- GST_DEBUG_OBJECT (parse, "It looked like a packet, but it is not");
- goto beach;
+ if (!parse->header_sent) {
+ GstCaps *caps;
+
+ /* Opus streams can decode to 1 or 2 channels, so use the header
+ value if we have one, or 2 otherwise */
+ if (is_idheader) {
+ channels = data[9];
+ } else {
+ channels = 2;
+ }
+
+ g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL);
+ parse->headers = NULL;
+
+ gst_opus_header_create_caps (&caps, &parse->headers, channels, 0, NULL);
+
+ gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
+
+ parse->header_sent = TRUE;
}
- GST_DEBUG_OBJECT (parse, "Got Opus packet, %d bytes");
+ if (is_header) {
+ *skip = 0;
+ *frame_size = size;
+ } else {
+ *skip = packet_offset;
+ *frame_size = payload_offset;
+ }
- *skip = 8;
- *frame_size = packet_size;
+ GST_DEBUG_OBJECT (parse, "Got Opus packet at offset %d, %d bytes", *skip,
+ *frame_size);
ret = TRUE;
beach:
+ gst_buffer_unmap (frame->buffer, data, size);
return ret;
}
+
+ /* Adapted copy of the one in gstoggstream.c... */
+ static guint64
+ packet_duration_opus (const guint8 * data, size_t len)
+ {
+ static const guint64 durations[32] = {
+ 10000, 20000, 40000, 60000, /* Silk NB */
+ 10000, 20000, 40000, 60000, /* Silk MB */
+ 10000, 20000, 40000, 60000, /* Silk WB */
+ 10000, 20000, /* Hybrid SWB */
+ 10000, 20000, /* Hybrid FB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ 2500, 5000, 10000, 20000, /* CELT NB */
+ };
+
+ gint64 duration;
+ gint64 frame_duration;
+ gint nframes;
+ guint8 toc;
+
+ if (len < 1)
+ return 0;
+
+ toc = data[0];
+
+ frame_duration = durations[toc >> 3] * 1000;
+ switch (toc & 3) {
+ case 0:
+ nframes = 1;
+ break;
+ case 1:
+ nframes = 2;
+ break;
+ case 2:
+ nframes = 2;
+ break;
+ case 3:
+ if (len < 2) {
+ GST_WARNING ("Code 3 Opus packet has less than 2 bytes");
+ return 0;
+ }
+ nframes = data[1] & 63;
+ break;
+ }
+
+ duration = nframes * frame_duration;
+ if (duration > 120 * GST_MSECOND) {
+ GST_WARNING ("Opus packet duration > 120 ms, invalid");
+ return 0;
+ }
+ GST_LOG ("Opus packet: frame size %.1f ms, %d frames, duration %.1f ms",
+ frame_duration / 1000000.f, nframes, duration / 1000000.f);
+ return duration;
+ }
+
+ static GstFlowReturn
+ gst_opus_parse_parse_frame (GstBaseParse * base, GstBaseParseFrame * frame)
+ {
+ guint64 duration;
+ GstOpusParse *parse;
+
+ parse = GST_OPUS_PARSE (base);
+
+ if (gst_opus_header_is_header (frame->buffer, "OpusHead", 8)
+ || gst_opus_header_is_header (frame->buffer, "OpusTags", 8)) {
+ GST_BUFFER_TIMESTAMP (frame->buffer) = 0;
+ GST_BUFFER_DURATION (frame->buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_OFFSET_END (frame->buffer) = GST_CLOCK_TIME_NONE;
+ GST_BUFFER_OFFSET (frame->buffer) = GST_CLOCK_TIME_NONE;
+ return GST_FLOW_OK;
+ }
+
+ GST_BUFFER_TIMESTAMP (frame->buffer) = parse->next_ts;
+
+ duration =
+ packet_duration_opus (GST_BUFFER_DATA (frame->buffer),
+ GST_BUFFER_SIZE (frame->buffer));
+ parse->next_ts += duration;
+
+ GST_BUFFER_DURATION (frame->buffer) = duration;
+ GST_BUFFER_OFFSET_END (frame->buffer) =
+ gst_util_uint64_scale (parse->next_ts, 48000, GST_SECOND);
+ GST_BUFFER_OFFSET (frame->buffer) = parse->next_ts;
+
+ return GST_FLOW_OK;
+ }
/* Push all pending events that arrived before this frame */
for (l = base_video_decoder->base_video_codec.frames; l; l = l->next) {
- GstVideoFrame *tmp = l->data;
+ GstVideoFrameState *tmp = l->data;
if (tmp->events) {
- GList *k;
-
- for (k = g_list_last (tmp->events); k; k = k->prev)
- events = g_list_prepend (events, k->data);
- g_list_free (tmp->events);
+ events = tmp->events;
tmp->events = NULL;
}
/**
* gst_base_video_decoder_get_max_decode_time:
* @base_video_decoder: a #GstBaseVideoDecoder
- * @frame: a #GstVideoFrame
+ * @frame: a #GstVideoFrameState
*
* Determines maximum possible decoding time for @frame that will
- * allow it to decode and arrive in time (as determined by QoS messages).
+ * allow it to decode and arrive in time (as determined by QoS events).
* In particular, a negative result means decoding in time is no longer possible
* and should therefore occur as soon/skippy as possible.
*
GST_DEBUG_CATEGORY_STATIC (wave_scope_debug);
#define GST_CAT_DEFAULT wave_scope_debug
- static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * scope,
- GstBuffer * audio, GstBuffer * video);
+ enum
+ {
+ PROP_0,
+ PROP_STYLE
+ };
+
+ enum
+ {
+ STYLE_DOTS = 0,
+ STYLE_LINES,
+ NUM_STYLES
+ };
+
+ #define GST_TYPE_WAVE_SCOPE_STYLE (gst_wave_scope_style_get_type ())
+ static GType
+ gst_wave_scope_style_get_type (void)
+ {
+ static GType gtype = 0;
+
+ if (gtype == 0) {
+ static const GEnumValue values[] = {
+ {STYLE_DOTS, "draw dots (default)", "dots"},
+ {STYLE_LINES, "draw lines", "lines"},
+ {0, NULL, NULL}
+ };
+ gtype = g_enum_register_static ("GstWaveScopeStyle", values);
+ }
+ return gtype;
+ }
+
+ static void gst_wave_scope_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+ static void gst_wave_scope_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+ static void render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata,
+ gint16 * adata, guint num_samples);
+ static void render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata,
+ gint16 * adata, guint num_samples);
+
+ static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * base,
+ GstBuffer * audio, GstBuffer * video);
-
-GST_BOILERPLATE (GstWaveScope, gst_wave_scope, GstBaseAudioVisualizer,
- GST_TYPE_BASE_AUDIO_VISUALIZER);
-
-static void
-gst_wave_scope_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
- "Visualization",
- "Simple waveform oscilloscope", "Stefan Kost <ensonic@users.sf.net>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_wave_scope_src_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_wave_scope_sink_template));
-}
+G_DEFINE_TYPE (GstWaveScope, gst_wave_scope, GST_TYPE_BASE_AUDIO_VISUALIZER);
static void
gst_wave_scope_class_init (GstWaveScopeClass * g_class)
{
- GstElementClass *element_class = (GstElementClass *) g_class;
+ GObjectClass *gobject_class = (GObjectClass *) g_class;
++ GstElementClass *gstelement_class = (GstElementClass *) g_class;
GstBaseAudioVisualizerClass *scope_class =
(GstBaseAudioVisualizerClass *) g_class;
- gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
- "Visualization",
- "Simple waveform oscilloscope", "Stefan Kost <ensonic@users.sf.net>");
+ gobject_class->set_property = gst_wave_scope_set_property;
+ gobject_class->get_property = gst_wave_scope_get_property;
+
- scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
-
+ g_object_class_install_property (gobject_class, PROP_STYLE,
+ g_param_spec_enum ("style", "drawing style",
+ "Drawing styles for the wave form display.",
+ GST_TYPE_WAVE_SCOPE_STYLE, STYLE_DOTS,
+ G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
- gst_element_class_add_pad_template (element_class,
++ gst_element_class_set_details_simple (gstelement_class,
++ "Waveform oscilloscope", "Visualization", "Simple waveform oscilloscope",
++ "Stefan Kost <ensonic@users.sf.net>");
++
++ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_wave_scope_src_template));
- gst_element_class_add_pad_template (element_class,
++ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_wave_scope_sink_template));
+
+ scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
}
static void
guint w = scope->width;
/* draw dots */
- num_samples = asize / (scope->channels * sizeof (gint16));
- dx = (gfloat) scope->width / (gfloat) num_samples;
+ dx = (gfloat) w / (gfloat) num_samples;
dy = scope->height / 65536.0;
oy = scope->height / 2;
- s = 0;
- for (i = 0; i < num_samples; i++) {
- x = (guint) ((gfloat) i * dx);
- for (c = 0; c < scope->channels; c++) {
- y = (guint) (oy + (gfloat) adata[s++] * dy);
- off = (y * w) + x;
- vdata[off] = 0x00FFFFFF;
+ for (c = 0; c < channels; c++) {
+ s = c;
+ for (i = 0; i < num_samples; i++) {
+ x = (guint) ((gfloat) i * dx);
+ y = (guint) (oy + (gfloat) adata[s] * dy);
+ s += channels;
+ draw_dot (vdata, x, y, w, 0x00FFFFFF);
}
}
- guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video);
- gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio);
+ }
+
+ static void
+ render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata,
+ guint num_samples)
+ {
+ gint channels = scope->channels;
+ guint i, c, s, x, y, oy;
+ gfloat dx, dy;
+ guint w = scope->width;
+ gint x2, y2;
+
+ /* draw lines */
+ dx = (gfloat) w / (gfloat) num_samples;
+ dy = scope->height / 65536.0;
+ oy = scope->height / 2;
+ for (c = 0; c < channels; c++) {
+ s = c;
+ x2 = 0;
+ y2 = (guint) (oy + (gfloat) adata[s] * dy);
+ for (i = 1; i < num_samples; i++) {
+ x = (guint) ((gfloat) i * dx);
+ y = (guint) (oy + (gfloat) adata[s] * dy);
+ s += channels;
+ draw_line (vdata, x2, x, y2, y, w, 0x00FFFFFF);
+ x2 = x;
+ y2 = y;
+ }
+ }
+ }
+
+ static gboolean
+ gst_wave_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio,
+ GstBuffer * video)
+ {
+ GstWaveScope *scope = GST_WAVE_SCOPE (base);
- num_samples = GST_BUFFER_SIZE (audio) / (base->channels * sizeof (gint16));
++ guint32 *vdata;
++ gsize asize;
++ gint16 *adata;
+ guint num_samples;
+
++ adata = gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
++ vdata = gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
++
++ num_samples = asize / (base->channels * sizeof (gint16));
+ scope->process (base, vdata, adata, num_samples);
++
+ gst_buffer_unmap (video, vdata, -1);
+ gst_buffer_unmap (audio, adata, -1);
++
return TRUE;
}