1 /* GStreamer
2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2005 Wim Taymans <wim@fluendo.com>
5 * 2007 Andy Wingo <wingo at pobox.com>
6 * 2008 Sebastian Dröge <slomo@circular-chaos.rg>
7 *
8 * interleave.c: interleave samples, mostly based on adder.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 /* TODO:
27 * - handle caps changes
28 * - handle more queries/events
29 */
30
31 /**
32 * SECTION:element-interleave
33 * @title: interleave
34 * @see_also: deinterleave
35 *
36 * Merges separate mono inputs into one interleaved stream.
37 *
38 * This element handles all raw floating point sample formats and all signed integer sample formats. The first
39 * caps on one of the sinkpads will set the caps of the output so usually an audioconvert element should be
40 * placed before every sinkpad of interleave.
41 *
42 * It's possible to change the number of channels while the pipeline is running by adding or removing
43 * some of the request pads but this will change the caps of the output buffers. Changing the input
44 * caps is _not_ supported yet.
45 *
46 * The channel number of every sinkpad in the out can be retrieved from the "channel" property of the pad.
47 *
48 * ## Example launch line
49 * |[
50 * gst-launch-1.0 filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2" ! deinterleave name=d interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav d.src_0 ! queue ! audioconvert ! i.sink_1 d.src_1 ! queue ! audioconvert ! i.sink_0
51 * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
52 * then interleaves the channels again to a WAV file with the channels
53 * exchanged.
54 * |[
55 * gst-launch-1.0 interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1,channel-mask=(bitmask)0x1" ! queue ! i.sink_0 filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1,channel-mask=(bitmask)0x2" ! queue ! i.sink_1
56 * ]| Interleaves two Mono WAV files to a single Stereo WAV file. Having
57 * channel-masks defined in the sink pads ensures a sane mapping of the mono
58 * streams into the stereo stream. NOTE: the proper way to map channels in
59 * code is by using the channel-positions property of the interleave element.
60 *
61 */
62
63 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
64 * with newer GLib versions (>= 2.31.0) */
65 #define GLIB_DISABLE_DEPRECATION_WARNINGS
66
67 #ifdef HAVE_CONFIG_H
68 # include "config.h"
69 #endif
70
71 #include <gst/gst.h>
72 #include <string.h>
73 #include "gstinterleaveelements.h"
74 #include "interleave.h"
75
76 #include <gst/audio/audio.h>
77 #include <gst/audio/audio-enumtypes.h>
78
79 GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug);
80 #define GST_CAT_DEFAULT gst_interleave_debug
81
82 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
83 GST_PAD_SINK,
84 GST_PAD_REQUEST,
85 GST_STATIC_CAPS ("audio/x-raw, "
86 "rate = (int) [ 1, MAX ], "
87 "channels = (int) 1, "
88 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
89 "layout = (string) {non-interleaved, interleaved}")
90 );
91
92 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
93 GST_PAD_SRC,
94 GST_PAD_ALWAYS,
95 GST_STATIC_CAPS ("audio/x-raw, "
96 "rate = (int) [ 1, MAX ], "
97 "channels = (int) [ 1, MAX ], "
98 "format = (string) " GST_AUDIO_FORMATS_ALL ", "
99 "layout = (string) interleaved")
100 );
101
102 #define MAKE_FUNC(type) \
103 static void interleave_##type (guint##type *out, guint##type *in, \
104 guint stride, guint nframes) \
105 { \
106 gint i; \
107 \
108 for (i = 0; i < nframes; i++) { \
109 *out = in[i]; \
110 out += stride; \
111 } \
112 }
113
114 MAKE_FUNC (8);
115 MAKE_FUNC (16);
116 MAKE_FUNC (32);
117 MAKE_FUNC (64);
118
119 static void
interleave_24(guint8 * out,guint8 * in,guint stride,guint nframes)120 interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
121 {
122 gint i;
123
124 for (i = 0; i < nframes; i++) {
125 memcpy (out, in, 3);
126 out += stride * 3;
127 in += 3;
128 }
129 }
130
131 typedef struct
132 {
133 GstPad parent;
134 guint channel;
135 } GstInterleavePad;
136
137 enum
138 {
139 PROP_PAD_0,
140 PROP_PAD_CHANNEL
141 };
142
143 static void gst_interleave_pad_class_init (GstPadClass * klass);
144
145 #define GST_TYPE_INTERLEAVE_PAD (gst_interleave_pad_get_type())
146 #define GST_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_CAST((pad),GST_TYPE_INTERLEAVE_PAD,GstInterleavePad))
147 #define GST_INTERLEAVE_PAD_CAST(pad) ((GstInterleavePad *) pad)
148 #define GST_IS_INTERLEAVE_PAD(pad) (G_TYPE_CHECK_INSTANCE_TYPE((pad),GST_TYPE_INTERLEAVE_PAD))
149 static GType
gst_interleave_pad_get_type(void)150 gst_interleave_pad_get_type (void)
151 {
152 static GType type = 0;
153
154 if (G_UNLIKELY (type == 0)) {
155 type = g_type_register_static_simple (GST_TYPE_PAD,
156 g_intern_static_string ("GstInterleavePad"), sizeof (GstPadClass),
157 (GClassInitFunc) gst_interleave_pad_class_init,
158 sizeof (GstInterleavePad), NULL, 0);
159 }
160 return type;
161 }
162
163 static void
gst_interleave_pad_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)164 gst_interleave_pad_get_property (GObject * object,
165 guint prop_id, GValue * value, GParamSpec * pspec)
166 {
167 GstInterleavePad *self = GST_INTERLEAVE_PAD (object);
168
169 switch (prop_id) {
170 case PROP_PAD_CHANNEL:
171 g_value_set_uint (value, self->channel);
172 break;
173 default:
174 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
175 break;
176 }
177 }
178
179 static void
gst_interleave_pad_class_init(GstPadClass * klass)180 gst_interleave_pad_class_init (GstPadClass * klass)
181 {
182 GObjectClass *gobject_class = (GObjectClass *) klass;
183
184 gobject_class->get_property = gst_interleave_pad_get_property;
185
186 g_object_class_install_property (gobject_class,
187 PROP_PAD_CHANNEL,
188 g_param_spec_uint ("channel",
189 "Channel number",
190 "Number of the channel of this pad in the output", 0, G_MAXUINT, 0,
191 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
192 }
193
194 #define gst_interleave_parent_class parent_class
195 G_DEFINE_TYPE (GstInterleave, gst_interleave, GST_TYPE_ELEMENT);
196 GST_ELEMENT_REGISTER_DEFINE (interleave, "interleave",
197 GST_RANK_NONE, gst_interleave_get_type ());
198
199 enum
200 {
201 PROP_0,
202 PROP_CHANNEL_POSITIONS,
203 PROP_CHANNEL_POSITIONS_FROM_INPUT
204 };
205
206 static void gst_interleave_set_property (GObject * object,
207 guint prop_id, const GValue * value, GParamSpec * pspec);
208 static void gst_interleave_get_property (GObject * object,
209 guint prop_id, GValue * value, GParamSpec * pspec);
210
211 static GstPad *gst_interleave_request_new_pad (GstElement * element,
212 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
213 static void gst_interleave_release_pad (GstElement * element, GstPad * pad);
214
215 static GstStateChangeReturn gst_interleave_change_state (GstElement * element,
216 GstStateChange transition);
217
218 static gboolean gst_interleave_src_query (GstPad * pad, GstObject * parent,
219 GstQuery * query);
220
221 static gboolean gst_interleave_src_event (GstPad * pad, GstObject * parent,
222 GstEvent * event);
223
224 static gboolean gst_interleave_sink_event (GstCollectPads * pads,
225 GstCollectData * data, GstEvent * event, gpointer user_data);
226 static gboolean gst_interleave_sink_query (GstCollectPads * pads,
227 GstCollectData * data, GstQuery * query, gpointer user_data);
228
229 static gboolean gst_interleave_sink_setcaps (GstInterleave * self,
230 GstPad * pad, const GstCaps * caps, const GstAudioInfo * info);
231
232 static GstCaps *gst_interleave_sink_getcaps (GstPad * pad, GstInterleave * self,
233 GstCaps * filter);
234
235 static GstFlowReturn gst_interleave_collected (GstCollectPads * pads,
236 GstInterleave * self);
237
238 static void
gst_interleave_finalize(GObject * object)239 gst_interleave_finalize (GObject * object)
240 {
241 GstInterleave *self = GST_INTERLEAVE (object);
242
243 if (self->collect) {
244 gst_object_unref (self->collect);
245 self->collect = NULL;
246 }
247
248 if (self->channel_positions
249 && self->channel_positions != self->input_channel_positions) {
250 g_value_array_free (self->channel_positions);
251 self->channel_positions = NULL;
252 }
253
254 if (self->input_channel_positions) {
255 g_value_array_free (self->input_channel_positions);
256 self->input_channel_positions = NULL;
257 }
258
259 gst_caps_replace (&self->sinkcaps, NULL);
260
261 G_OBJECT_CLASS (parent_class)->finalize (object);
262 }
263
264 static gint
compare_positions(gconstpointer a,gconstpointer b,gpointer user_data)265 compare_positions (gconstpointer a, gconstpointer b, gpointer user_data)
266 {
267 const gint i = *(const gint *) a;
268 const gint j = *(const gint *) b;
269 const gint *pos = (const gint *) user_data;
270
271 if (pos[i] < pos[j])
272 return -1;
273 else if (pos[i] > pos[j])
274 return 1;
275 else
276 return 0;
277 }
278
279 static gboolean
gst_interleave_channel_positions_to_mask(GValueArray * positions,gint default_ordering_map[64],guint64 * mask)280 gst_interleave_channel_positions_to_mask (GValueArray * positions,
281 gint default_ordering_map[64], guint64 * mask)
282 {
283 gint i;
284 guint channels;
285 GstAudioChannelPosition *pos;
286 gboolean ret;
287
288 channels = positions->n_values;
289 pos = g_new (GstAudioChannelPosition, channels);
290
291 for (i = 0; i < channels; i++) {
292 GValue *val;
293
294 val = g_value_array_get_nth (positions, i);
295 pos[i] = g_value_get_enum (val);
296 }
297
298 /* sort the default ordering map according to the position order */
299 for (i = 0; i < channels; i++) {
300 default_ordering_map[i] = i;
301 }
302 g_qsort_with_data (default_ordering_map, channels,
303 sizeof (*default_ordering_map), compare_positions, pos);
304
305 ret = gst_audio_channel_positions_to_mask (pos, channels, FALSE, mask);
306 g_free (pos);
307
308 return ret;
309 }
310
311 static void
gst_interleave_set_channel_positions(GstInterleave * self,GstStructure * s)312 gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
313 {
314 if (self->channels <= 64 &&
315 self->channel_positions != NULL &&
316 self->channels == self->channel_positions->n_values) {
317 if (!gst_interleave_channel_positions_to_mask (self->channel_positions,
318 self->default_channels_ordering_map, &self->channel_mask)) {
319 GST_WARNING_OBJECT (self, "Invalid channel positions, using NONE");
320 self->channel_mask = 0;
321 }
322 } else {
323 self->channel_mask = 0;
324 if (self->channels <= 64) {
325 GST_WARNING_OBJECT (self, "Using NONE channel positions");
326 }
327 }
328 gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, self->channel_mask,
329 NULL);
330 }
331
332 static void
gst_interleave_send_stream_start(GstInterleave * self)333 gst_interleave_send_stream_start (GstInterleave * self)
334 {
335 GST_OBJECT_LOCK (self);
336 if (self->send_stream_start) {
337 gchar s_id[32];
338
339 self->send_stream_start = FALSE;
340 GST_OBJECT_UNLOCK (self);
341
342 /* stream-start (FIXME: create id based on input ids) */
343 g_snprintf (s_id, sizeof (s_id), "interleave-%08x", g_random_int ());
344 gst_pad_push_event (self->src, gst_event_new_stream_start (s_id));
345 } else {
346 GST_OBJECT_UNLOCK (self);
347 }
348 }
349
350 static void
gst_interleave_class_init(GstInterleaveClass * klass)351 gst_interleave_class_init (GstInterleaveClass * klass)
352 {
353 GstElementClass *gstelement_class;
354 GObjectClass *gobject_class;
355
356 gobject_class = G_OBJECT_CLASS (klass);
357 gstelement_class = GST_ELEMENT_CLASS (klass);
358
359 GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0,
360 "interleave element");
361
362 gst_element_class_set_static_metadata (gstelement_class, "Audio interleaver",
363 "Filter/Converter/Audio",
364 "Folds many mono channels into one interleaved audio stream",
365 "Andy Wingo <wingo at pobox.com>, "
366 "Sebastian Dröge <slomo@circular-chaos.org>");
367
368 gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
369 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
370
371 /* Reference GstInterleavePad class to have the type registered from
372 * a threadsafe context
373 */
374 g_type_class_ref (GST_TYPE_INTERLEAVE_PAD);
375
376 gobject_class->finalize = gst_interleave_finalize;
377 gobject_class->set_property = gst_interleave_set_property;
378 gobject_class->get_property = gst_interleave_get_property;
379
380 /**
381 * GstInterleave:channel-positions
382 *
383 * Channel positions: This property controls the channel positions
384 * that are used on the src caps. The number of elements should be
385 * the same as the number of sink pads and the array should contain
386 * a valid list of channel positions. The n-th element of the array
387 * is the position of the n-th sink pad.
388 *
389 * These channel positions will only be used if they're valid and the
390 * number of elements is the same as the number of channels. If this
391 * is not given a NONE layout will be used.
392 *
393 */
394 g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
395 g_param_spec_value_array ("channel-positions", "Channel positions",
396 "Channel positions used on the output",
397 g_param_spec_enum ("channel-position", "Channel position",
398 "Channel position of the n-th input",
399 GST_TYPE_AUDIO_CHANNEL_POSITION,
400 GST_AUDIO_CHANNEL_POSITION_NONE,
401 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
402 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
403
404 /**
405 * GstInterleave:channel-positions-from-input
406 *
407 * Channel positions from input: If this property is set to %TRUE the channel
408 * positions will be taken from the input caps if valid channel positions for
409 * the output can be constructed from them. If this is set to %TRUE setting the
410 * channel-positions property overwrites this property again.
411 *
412 */
413 g_object_class_install_property (gobject_class,
414 PROP_CHANNEL_POSITIONS_FROM_INPUT,
415 g_param_spec_boolean ("channel-positions-from-input",
416 "Channel positions from input",
417 "Take channel positions from the input", TRUE,
418 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
419
420 gstelement_class->request_new_pad =
421 GST_DEBUG_FUNCPTR (gst_interleave_request_new_pad);
422 gstelement_class->release_pad =
423 GST_DEBUG_FUNCPTR (gst_interleave_release_pad);
424 gstelement_class->change_state =
425 GST_DEBUG_FUNCPTR (gst_interleave_change_state);
426 }
427
428 static void
gst_interleave_init(GstInterleave * self)429 gst_interleave_init (GstInterleave * self)
430 {
431 self->src = gst_pad_new_from_static_template (&src_template, "src");
432
433 gst_pad_set_query_function (self->src,
434 GST_DEBUG_FUNCPTR (gst_interleave_src_query));
435 gst_pad_set_event_function (self->src,
436 GST_DEBUG_FUNCPTR (gst_interleave_src_event));
437
438 gst_element_add_pad (GST_ELEMENT (self), self->src);
439
440 self->collect = gst_collect_pads_new ();
441 gst_collect_pads_set_function (self->collect,
442 (GstCollectPadsFunction) gst_interleave_collected, self);
443
444 self->input_channel_positions = g_value_array_new (0);
445 self->channel_positions_from_input = TRUE;
446 self->channel_positions = self->input_channel_positions;
447 }
448
449 static void
gst_interleave_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)450 gst_interleave_set_property (GObject * object, guint prop_id,
451 const GValue * value, GParamSpec * pspec)
452 {
453 GstInterleave *self = GST_INTERLEAVE (object);
454
455 switch (prop_id) {
456 case PROP_CHANNEL_POSITIONS:
457 if (self->channel_positions &&
458 self->channel_positions != self->input_channel_positions)
459 g_value_array_free (self->channel_positions);
460
461 self->channel_positions = g_value_dup_boxed (value);
462 self->channel_positions_from_input = FALSE;
463 break;
464 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
465 self->channel_positions_from_input = g_value_get_boolean (value);
466
467 if (self->channel_positions_from_input) {
468 if (self->channel_positions &&
469 self->channel_positions != self->input_channel_positions)
470 g_value_array_free (self->channel_positions);
471 self->channel_positions = self->input_channel_positions;
472 }
473 break;
474 default:
475 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
476 break;
477 }
478 }
479
480 static void
gst_interleave_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)481 gst_interleave_get_property (GObject * object, guint prop_id,
482 GValue * value, GParamSpec * pspec)
483 {
484 GstInterleave *self = GST_INTERLEAVE (object);
485
486 switch (prop_id) {
487 case PROP_CHANNEL_POSITIONS:
488 g_value_set_boxed (value, self->channel_positions);
489 break;
490 case PROP_CHANNEL_POSITIONS_FROM_INPUT:
491 g_value_set_boolean (value, self->channel_positions_from_input);
492 break;
493 default:
494 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
495 break;
496 }
497 }
498
499 static GstPad *
gst_interleave_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * req_name,const GstCaps * caps)500 gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
501 const gchar * req_name, const GstCaps * caps)
502 {
503 GstInterleave *self = GST_INTERLEAVE (element);
504 GstPad *new_pad;
505 gchar *pad_name;
506 gint channel, padnumber;
507 GValue val = { 0, };
508
509 if (templ->direction != GST_PAD_SINK)
510 goto not_sink_pad;
511
512 padnumber = g_atomic_int_add (&self->padcounter, 1);
513
514 channel = g_atomic_int_add (&self->channels, 1);
515 if (!self->channel_positions_from_input)
516 channel = padnumber;
517
518 pad_name = g_strdup_printf ("sink_%u", padnumber);
519 new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
520 "name", pad_name, "direction", templ->direction,
521 "template", templ, NULL));
522 GST_INTERLEAVE_PAD_CAST (new_pad)->channel = channel;
523 GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
524 g_free (pad_name);
525
526 gst_pad_use_fixed_caps (new_pad);
527
528 gst_collect_pads_add_pad (self->collect, new_pad, sizeof (GstCollectData),
529 NULL, TRUE);
530
531 gst_collect_pads_set_event_function (self->collect,
532 (GstCollectPadsEventFunction)
533 GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self);
534
535 gst_collect_pads_set_query_function (self->collect,
536 (GstCollectPadsQueryFunction)
537 GST_DEBUG_FUNCPTR (gst_interleave_sink_query), self);
538
539 if (!gst_element_add_pad (element, new_pad))
540 goto could_not_add;
541
542 g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
543 g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
544 self->input_channel_positions =
545 g_value_array_append (self->input_channel_positions, &val);
546 g_value_unset (&val);
547
548 /* Update the src caps if we already have them */
549 if (self->sinkcaps) {
550 GstCaps *srccaps;
551 GstStructure *s;
552
553 /* Take lock to make sure processing finishes first */
554 GST_OBJECT_LOCK (self->collect);
555
556 srccaps = gst_caps_copy (self->sinkcaps);
557 s = gst_caps_get_structure (srccaps, 0);
558
559 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
560 gst_interleave_set_channel_positions (self, s);
561
562 gst_interleave_send_stream_start (self);
563 gst_pad_set_caps (self->src, srccaps);
564 gst_caps_unref (srccaps);
565
566 GST_OBJECT_UNLOCK (self->collect);
567 }
568
569 return new_pad;
570
571 /* errors */
572 not_sink_pad:
573 {
574 g_warning ("interleave: requested new pad that is not a SINK pad\n");
575 return NULL;
576 }
577 could_not_add:
578 {
579 GST_DEBUG_OBJECT (self, "could not add pad %s", GST_PAD_NAME (new_pad));
580 gst_collect_pads_remove_pad (self->collect, new_pad);
581 gst_object_unref (new_pad);
582 return NULL;
583 }
584 }
585
586 static void
gst_interleave_release_pad(GstElement * element,GstPad * pad)587 gst_interleave_release_pad (GstElement * element, GstPad * pad)
588 {
589 GstInterleave *self = GST_INTERLEAVE (element);
590 GList *l;
591 GstAudioChannelPosition position;
592
593 g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));
594
595 /* Take lock to make sure we're not changing this when processing buffers */
596 GST_OBJECT_LOCK (self->collect);
597
598 g_atomic_int_add (&self->channels, -1);
599
600 if (gst_pad_has_current_caps (pad))
601 g_atomic_int_add (&self->configured_sinkpads_counter, -1);
602
603 position = GST_INTERLEAVE_PAD_CAST (pad)->channel;
604 g_value_array_remove (self->input_channel_positions, position);
605
606 /* Update channel numbers */
607 GST_OBJECT_LOCK (self);
608 for (l = GST_ELEMENT_CAST (self)->sinkpads; l != NULL; l = l->next) {
609 GstInterleavePad *ipad = GST_INTERLEAVE_PAD (l->data);
610
611 if (GST_INTERLEAVE_PAD_CAST (pad)->channel < ipad->channel)
612 ipad->channel--;
613 }
614 GST_OBJECT_UNLOCK (self);
615
616 /* Update the src caps if we already have them */
617 if (self->sinkcaps) {
618 if (self->channels > 0) {
619 GstCaps *srccaps;
620 GstStructure *s;
621
622 srccaps = gst_caps_copy (self->sinkcaps);
623 s = gst_caps_get_structure (srccaps, 0);
624
625 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
626 gst_interleave_set_channel_positions (self, s);
627
628 gst_interleave_send_stream_start (self);
629 gst_pad_set_caps (self->src, srccaps);
630 gst_caps_unref (srccaps);
631 } else {
632 gst_caps_replace (&self->sinkcaps, NULL);
633 }
634 }
635
636 GST_OBJECT_UNLOCK (self->collect);
637
638 gst_collect_pads_remove_pad (self->collect, pad);
639 gst_element_remove_pad (element, pad);
640 }
641
642 static GstStateChangeReturn
gst_interleave_change_state(GstElement * element,GstStateChange transition)643 gst_interleave_change_state (GstElement * element, GstStateChange transition)
644 {
645 GstInterleave *self;
646 GstStateChangeReturn ret;
647
648 self = GST_INTERLEAVE (element);
649
650 switch (transition) {
651 case GST_STATE_CHANGE_NULL_TO_READY:
652 break;
653 case GST_STATE_CHANGE_READY_TO_PAUSED:
654 self->timestamp = 0;
655 self->offset = 0;
656 gst_event_replace (&self->pending_segment, NULL);
657 self->send_stream_start = TRUE;
658 gst_collect_pads_start (self->collect);
659 break;
660 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
661 break;
662 default:
663 break;
664 }
665
666 /* Stop before calling the parent's state change function as
667 * GstCollectPads might take locks and we would deadlock in that
668 * case
669 */
670 if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
671 gst_collect_pads_stop (self->collect);
672
673 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
674
675 switch (transition) {
676 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
677 break;
678 case GST_STATE_CHANGE_PAUSED_TO_READY:
679 gst_caps_replace (&self->sinkcaps, NULL);
680 gst_event_replace (&self->pending_segment, NULL);
681 break;
682 case GST_STATE_CHANGE_READY_TO_NULL:
683 break;
684 default:
685 break;
686 }
687
688 return ret;
689 }
690
691 static void
__remove_channels(GstCaps * caps)692 __remove_channels (GstCaps * caps)
693 {
694 GstStructure *s;
695 gint i, size;
696
697 size = gst_caps_get_size (caps);
698 for (i = 0; i < size; i++) {
699 s = gst_caps_get_structure (caps, i);
700 gst_structure_remove_field (s, "channel-mask");
701 gst_structure_remove_field (s, "channels");
702 }
703 }
704
705 static void
__set_channels(GstCaps * caps,gint channels)706 __set_channels (GstCaps * caps, gint channels)
707 {
708 GstStructure *s;
709 gint i, size;
710
711 size = gst_caps_get_size (caps);
712 for (i = 0; i < size; i++) {
713 s = gst_caps_get_structure (caps, i);
714 if (channels > 0)
715 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
716 else
717 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
718 }
719 }
720
721 /* we can only accept caps that we and downstream can handle. */
722 static GstCaps *
gst_interleave_sink_getcaps(GstPad * pad,GstInterleave * self,GstCaps * filter)723 gst_interleave_sink_getcaps (GstPad * pad, GstInterleave * self,
724 GstCaps * filter)
725 {
726 GstCaps *result, *peercaps, *sinkcaps;
727
728 GST_OBJECT_LOCK (self);
729
730 /* If we already have caps on one of the sink pads return them */
731 if (self->sinkcaps) {
732 result = gst_caps_copy (self->sinkcaps);
733 } else {
734 /* get the downstream possible caps */
735 peercaps = gst_pad_peer_query_caps (self->src, NULL);
736
737 /* get the allowed caps on this sinkpad */
738 sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
739 __remove_channels (sinkcaps);
740 if (peercaps) {
741 peercaps = gst_caps_make_writable (peercaps);
742 __remove_channels (peercaps);
743 /* if the peer has caps, intersect */
744 GST_DEBUG_OBJECT (pad, "intersecting peer and template caps");
745 result = gst_caps_intersect (peercaps, sinkcaps);
746 gst_caps_unref (peercaps);
747 gst_caps_unref (sinkcaps);
748 } else {
749 /* the peer has no caps (or there is no peer), just use the allowed caps
750 * of this sinkpad. */
751 GST_DEBUG_OBJECT (pad, "no peer caps, using sinkcaps");
752 result = sinkcaps;
753 }
754 __set_channels (result, 1);
755 }
756
757 GST_OBJECT_UNLOCK (self);
758
759 if (filter != NULL) {
760 GstCaps *caps = result;
761
762 GST_LOG_OBJECT (pad, "intersecting filter caps %" GST_PTR_FORMAT " with "
763 "preliminary result %" GST_PTR_FORMAT, filter, caps);
764
765 result = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
766 gst_caps_unref (caps);
767 }
768
769 GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
770
771 return result;
772 }
773
774 static void
gst_interleave_set_process_function(GstInterleave * self)775 gst_interleave_set_process_function (GstInterleave * self)
776 {
777 switch (self->width) {
778 case 8:
779 self->func = (GstInterleaveFunc) interleave_8;
780 break;
781 case 16:
782 self->func = (GstInterleaveFunc) interleave_16;
783 break;
784 case 24:
785 self->func = (GstInterleaveFunc) interleave_24;
786 break;
787 case 32:
788 self->func = (GstInterleaveFunc) interleave_32;
789 break;
790 case 64:
791 self->func = (GstInterleaveFunc) interleave_64;
792 break;
793 default:
794 g_assert_not_reached ();
795 break;
796 }
797 }
798
799 static gboolean
gst_interleave_sink_setcaps(GstInterleave * self,GstPad * pad,const GstCaps * caps,const GstAudioInfo * info)800 gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad,
801 const GstCaps * caps, const GstAudioInfo * info)
802 {
803 g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);
804
805 /* TODO: handle caps changes */
806 if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
807 goto cannot_change_caps;
808 } else {
809 GstCaps *srccaps;
810 GstStructure *s;
811 gboolean res;
812
813 self->width = GST_AUDIO_INFO_WIDTH (info);
814 self->rate = GST_AUDIO_INFO_RATE (info);
815
816 gst_interleave_set_process_function (self);
817
818 srccaps = gst_caps_copy (caps);
819 s = gst_caps_get_structure (srccaps, 0);
820
821 gst_structure_remove_field (s, "channel-mask");
822
823 gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
824 G_TYPE_STRING, "interleaved", NULL);
825 gst_interleave_set_channel_positions (self, s);
826
827 gst_interleave_send_stream_start (self);
828 res = gst_pad_set_caps (self->src, srccaps);
829 gst_caps_unref (srccaps);
830
831 if (!res)
832 goto src_did_not_accept;
833 }
834
835 if (!self->sinkcaps) {
836 GstCaps *sinkcaps = gst_caps_copy (caps);
837 GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
838
839 gst_structure_remove_field (s, "channel-mask");
840
841 GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);
842
843 gst_caps_replace (&self->sinkcaps, sinkcaps);
844
845 gst_caps_unref (sinkcaps);
846 }
847
848 return TRUE;
849
850 cannot_change_caps:
851 {
852 GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
853 "change", self->sinkcaps);
854 return FALSE;
855 }
856 src_did_not_accept:
857 {
858 GST_WARNING_OBJECT (self, "src did not accept setcaps()");
859 return FALSE;
860 }
861 }
862
863 static gboolean
gst_interleave_sink_event(GstCollectPads * pads,GstCollectData * data,GstEvent * event,gpointer user_data)864 gst_interleave_sink_event (GstCollectPads * pads, GstCollectData * data,
865 GstEvent * event, gpointer user_data)
866 {
867 GstInterleave *self = GST_INTERLEAVE (user_data);
868 gboolean ret = TRUE;
869
870 GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
871 GST_DEBUG_PAD_NAME (data->pad));
872
873 switch (GST_EVENT_TYPE (event)) {
874 case GST_EVENT_FLUSH_STOP:
875 GST_OBJECT_LOCK (self);
876 gst_event_replace (&self->pending_segment, NULL);
877 GST_OBJECT_UNLOCK (self);
878 break;
879 case GST_EVENT_SEGMENT:
880 {
881 GST_OBJECT_LOCK (self);
882 gst_event_replace (&self->pending_segment, event);
883 GST_OBJECT_UNLOCK (self);
884 break;
885 }
886 case GST_EVENT_CAPS:
887 {
888 GstCaps *caps;
889 GstAudioInfo info;
890 GValue *val;
891 guint channel;
892
893 gst_event_parse_caps (event, &caps);
894
895 if (!gst_audio_info_from_caps (&info, caps)) {
896 GST_WARNING_OBJECT (self, "invalid sink caps");
897 gst_event_unref (event);
898 event = NULL;
899 ret = FALSE;
900 break;
901 }
902
903 if (self->channel_positions_from_input
904 && GST_AUDIO_INFO_CHANNELS (&info) == 1) {
905 channel = GST_INTERLEAVE_PAD_CAST (data->pad)->channel;
906 val = g_value_array_get_nth (self->input_channel_positions, channel);
907 g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
908 }
909
910 if (!gst_pad_has_current_caps (data->pad))
911 g_atomic_int_add (&self->configured_sinkpads_counter, 1);
912
913 /* Last caps that are set on a sink pad are used as output caps */
914 if (g_atomic_int_get (&self->configured_sinkpads_counter) ==
915 self->channels) {
916 ret = gst_interleave_sink_setcaps (self, data->pad, caps, &info);
917 gst_event_unref (event);
918 event = NULL;
919 }
920 break;
921 }
922 case GST_EVENT_TAG:
923 GST_FIXME_OBJECT (self, "FIXME: merge tags and send after stream-start");
924 break;
925 default:
926 break;
927 }
928
929 /* now GstCollectPads can take care of the rest, e.g. EOS */
930 if (event != NULL)
931 return gst_collect_pads_event_default (pads, data, event, FALSE);
932
933 return ret;
934 }
935
936 static gboolean
gst_interleave_sink_query(GstCollectPads * pads,GstCollectData * data,GstQuery * query,gpointer user_data)937 gst_interleave_sink_query (GstCollectPads * pads,
938 GstCollectData * data, GstQuery * query, gpointer user_data)
939 {
940 GstInterleave *self = GST_INTERLEAVE (user_data);
941 gboolean ret = TRUE;
942
943 GST_DEBUG ("Got %s query on pad %s:%s", GST_QUERY_TYPE_NAME (query),
944 GST_DEBUG_PAD_NAME (data->pad));
945
946 switch (GST_QUERY_TYPE (query)) {
947 case GST_QUERY_CAPS:
948 {
949 GstCaps *filter, *caps;
950
951 gst_query_parse_caps (query, &filter);
952 caps = gst_interleave_sink_getcaps (data->pad, self, filter);
953 gst_query_set_caps_result (query, caps);
954 gst_caps_unref (caps);
955 ret = TRUE;
956 break;
957 }
958 default:
959 ret = gst_collect_pads_query_default (pads, data, query, FALSE);
960 break;
961 }
962
963 return ret;
964 }
965
966 static gboolean
gst_interleave_src_query_duration(GstInterleave * self,GstQuery * query)967 gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
968 {
969 gint64 max;
970 gboolean res;
971 GstFormat format;
972 GstIterator *it;
973 gboolean done;
974
975 /* parse format */
976 gst_query_parse_duration (query, &format, NULL);
977
978 max = -1;
979 res = TRUE;
980 done = FALSE;
981
982 /* Take maximum of all durations */
983 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
984 while (!done) {
985 GstIteratorResult ires;
986
987 GValue item = { 0, };
988
989 ires = gst_iterator_next (it, &item);
990 switch (ires) {
991 case GST_ITERATOR_DONE:
992 done = TRUE;
993 break;
994 case GST_ITERATOR_OK:
995 {
996 GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
997
998 gint64 duration;
999
1000 /* ask sink peer for duration */
1001 res &= gst_pad_peer_query_duration (pad, format, &duration);
1002 /* take max from all valid return values */
1003 if (res) {
1004 /* valid unknown length, stop searching */
1005 if (duration == -1) {
1006 max = duration;
1007 done = TRUE;
1008 }
1009 /* else see if bigger than current max */
1010 else if (duration > max)
1011 max = duration;
1012 }
1013 gst_object_unref (pad);
1014 g_value_unset (&item);
1015 break;
1016 }
1017 case GST_ITERATOR_RESYNC:
1018 max = -1;
1019 res = TRUE;
1020 gst_iterator_resync (it);
1021 break;
1022 default:
1023 res = FALSE;
1024 done = TRUE;
1025 break;
1026 }
1027 }
1028 gst_iterator_free (it);
1029
1030 if (res) {
1031 /* If in bytes format we have to multiply with the number of channels
1032 * to get the correct results. All other formats should be fine */
1033 if (format == GST_FORMAT_BYTES && max != -1)
1034 max *= self->channels;
1035
1036 /* and store the max */
1037 GST_DEBUG_OBJECT (self, "Total duration in format %s: %"
1038 GST_TIME_FORMAT, gst_format_get_name (format), GST_TIME_ARGS (max));
1039 gst_query_set_duration (query, format, max);
1040 }
1041
1042 return res;
1043 }
1044
1045 static gboolean
gst_interleave_src_query(GstPad * pad,GstObject * parent,GstQuery * query)1046 gst_interleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1047 {
1048 GstInterleave *self = GST_INTERLEAVE (parent);
1049 gboolean res = FALSE;
1050
1051 switch (GST_QUERY_TYPE (query)) {
1052 case GST_QUERY_POSITION:
1053 {
1054 GstFormat format;
1055
1056 gst_query_parse_position (query, &format, NULL);
1057
1058 switch (format) {
1059 case GST_FORMAT_TIME:
1060 /* FIXME, bring to stream time, might be tricky */
1061 gst_query_set_position (query, format, self->timestamp);
1062 res = TRUE;
1063 break;
1064 case GST_FORMAT_BYTES:
1065 gst_query_set_position (query, format,
1066 self->offset * self->channels * self->width);
1067 res = TRUE;
1068 break;
1069 case GST_FORMAT_DEFAULT:
1070 gst_query_set_position (query, format, self->offset);
1071 res = TRUE;
1072 break;
1073 default:
1074 break;
1075 }
1076 break;
1077 }
1078 case GST_QUERY_DURATION:
1079 res = gst_interleave_src_query_duration (self, query);
1080 break;
1081 default:
1082 /* FIXME, needs a custom query handler because we have multiple
1083 * sinkpads */
1084 res = gst_pad_query_default (pad, parent, query);
1085 break;
1086 }
1087
1088 return res;
1089 }
1090
1091 static gboolean
forward_event_func(const GValue * item,GValue * ret,GstEvent * event)1092 forward_event_func (const GValue * item, GValue * ret, GstEvent * event)
1093 {
1094 GstPad *pad = GST_PAD_CAST (g_value_dup_object (item));
1095 gst_event_ref (event);
1096 GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
1097 if (!gst_pad_push_event (pad, event)) {
1098 g_value_set_boolean (ret, FALSE);
1099 GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.",
1100 event, GST_EVENT_TYPE_NAME (event));
1101 } else {
1102 GST_LOG_OBJECT (pad, "Sent event %p (%s).",
1103 event, GST_EVENT_TYPE_NAME (event));
1104 }
1105 gst_object_unref (pad);
1106 return TRUE;
1107 }
1108
1109 static gboolean
forward_event(GstInterleave * self,GstEvent * event)1110 forward_event (GstInterleave * self, GstEvent * event)
1111 {
1112 GstIterator *it;
1113 GValue vret = { 0 };
1114
1115 GST_LOG_OBJECT (self, "Forwarding event %p (%s)", event,
1116 GST_EVENT_TYPE_NAME (event));
1117
1118 g_value_init (&vret, G_TYPE_BOOLEAN);
1119 g_value_set_boolean (&vret, TRUE);
1120 it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
1121 gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret,
1122 event);
1123 gst_iterator_free (it);
1124 gst_event_unref (event);
1125
1126 return g_value_get_boolean (&vret);
1127 }
1128
1129
1130 static gboolean
gst_interleave_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1131 gst_interleave_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1132 {
1133 GstInterleave *self = GST_INTERLEAVE (parent);
1134 gboolean result;
1135
1136 switch (GST_EVENT_TYPE (event)) {
1137 case GST_EVENT_QOS:
1138 /* QoS might be tricky */
1139 result = FALSE;
1140 break;
1141 case GST_EVENT_SEEK:
1142 {
1143 GstSeekFlags flags;
1144
1145 gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
1146
1147 /* check if we are flushing */
1148 if (flags & GST_SEEK_FLAG_FLUSH) {
1149 /* make sure we accept nothing anymore and return WRONG_STATE */
1150 gst_collect_pads_set_flushing (self->collect, TRUE);
1151
1152 /* flushing seek, start flush downstream, the flush will be done
1153 * when all pads received a FLUSH_STOP. */
1154 gst_pad_push_event (self->src, gst_event_new_flush_start ());
1155 }
1156 result = forward_event (self, event);
1157 break;
1158 }
1159 case GST_EVENT_NAVIGATION:
1160 /* navigation is rather pointless. */
1161 result = FALSE;
1162 break;
1163 default:
1164 /* just forward the rest for now */
1165 result = forward_event (self, event);
1166 break;
1167 }
1168
1169 return result;
1170 }
1171
1172 static GstFlowReturn
gst_interleave_collected(GstCollectPads * pads,GstInterleave * self)1173 gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
1174 {
1175 guint size;
1176 GstBuffer *outbuf = NULL;
1177 GstFlowReturn ret = GST_FLOW_OK;
1178 GSList *collected;
1179 guint nsamples;
1180 guint ncollected = 0;
1181 gboolean empty = TRUE;
1182 gint width = self->width / 8;
1183 GstMapInfo write_info;
1184 GstClockTime timestamp = -1;
1185
1186 size = gst_collect_pads_available (pads);
1187 if (size == 0)
1188 goto eos;
1189
1190 g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
1191 g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
1192 g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED);
1193 g_return_val_if_fail (self->rate > 0, GST_FLOW_NOT_NEGOTIATED);
1194
1195 g_return_val_if_fail (size % width == 0, GST_FLOW_ERROR);
1196
1197 GST_DEBUG_OBJECT (self, "Starting to collect %u bytes from %d channels", size,
1198 self->channels);
1199
1200 nsamples = size / width;
1201
1202 outbuf = gst_buffer_new_allocate (NULL, size * self->channels, NULL);
1203
1204 if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) {
1205 gst_buffer_unref (outbuf);
1206 return GST_FLOW_NOT_NEGOTIATED;
1207 }
1208
1209 gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE);
1210 memset (write_info.data, 0, size * self->channels);
1211
1212 for (collected = pads->data; collected != NULL; collected = collected->next) {
1213 GstCollectData *cdata;
1214 GstBuffer *inbuf;
1215 guint8 *outdata;
1216 GstMapInfo input_info;
1217 gint channel;
1218
1219 cdata = (GstCollectData *) collected->data;
1220
1221 inbuf = gst_collect_pads_take_buffer (pads, cdata, size);
1222 if (inbuf == NULL) {
1223 GST_DEBUG_OBJECT (cdata->pad, "No buffer available");
1224 goto next;
1225 }
1226 ncollected++;
1227
1228 if (timestamp == -1)
1229 timestamp = GST_BUFFER_TIMESTAMP (inbuf);
1230
1231 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))
1232 goto next;
1233
1234 empty = FALSE;
1235 channel = GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
1236 if (self->channels <= 64 && self->channel_mask) {
1237 channel = self->default_channels_ordering_map[channel];
1238 }
1239 outdata = write_info.data + width * channel;
1240
1241 gst_buffer_map (inbuf, &input_info, GST_MAP_READ);
1242 self->func (outdata, input_info.data, self->channels, nsamples);
1243 gst_buffer_unmap (inbuf, &input_info);
1244
1245 next:
1246 if (inbuf)
1247 gst_buffer_unref (inbuf);
1248 }
1249
1250 if (ncollected == 0) {
1251 gst_buffer_unmap (outbuf, &write_info);
1252 goto eos;
1253 }
1254
1255 GST_OBJECT_LOCK (self);
1256 if (self->pending_segment) {
1257 GstEvent *event;
1258 GstSegment segment;
1259
1260 event = self->pending_segment;
1261 self->pending_segment = NULL;
1262 GST_OBJECT_UNLOCK (self);
1263
1264 /* convert the input segment to time now */
1265 gst_event_copy_segment (event, &segment);
1266
1267 if (segment.format != GST_FORMAT_TIME) {
1268 gst_event_unref (event);
1269
1270 /* not time, convert */
1271 switch (segment.format) {
1272 case GST_FORMAT_BYTES:
1273 segment.start *= width;
1274 if (segment.stop != -1)
1275 segment.stop *= width;
1276 if (segment.position != -1)
1277 segment.position *= width;
1278 /* fallthrough for the samples case */
1279 case GST_FORMAT_DEFAULT:
1280 segment.start =
1281 gst_util_uint64_scale_int (segment.start, GST_SECOND, self->rate);
1282 if (segment.stop != -1)
1283 segment.stop =
1284 gst_util_uint64_scale_int (segment.stop, GST_SECOND,
1285 self->rate);
1286 if (segment.position != -1)
1287 segment.position =
1288 gst_util_uint64_scale_int (segment.position, GST_SECOND,
1289 self->rate);
1290 break;
1291 default:
1292 GST_WARNING ("can't convert segment values");
1293 segment.start = 0;
1294 segment.stop = -1;
1295 segment.position = 0;
1296 break;
1297 }
1298 event = gst_event_new_segment (&segment);
1299 }
1300 gst_pad_push_event (self->src, event);
1301
1302 GST_OBJECT_LOCK (self);
1303 }
1304 GST_OBJECT_UNLOCK (self);
1305
1306 if (timestamp != -1) {
1307 self->offset = gst_util_uint64_scale_int (timestamp, self->rate,
1308 GST_SECOND);
1309 self->timestamp = timestamp;
1310 }
1311
1312 GST_BUFFER_TIMESTAMP (outbuf) = self->timestamp;
1313 GST_BUFFER_OFFSET (outbuf) = self->offset;
1314
1315 self->offset += nsamples;
1316 self->timestamp = gst_util_uint64_scale_int (self->offset,
1317 GST_SECOND, self->rate);
1318
1319 GST_BUFFER_DURATION (outbuf) =
1320 self->timestamp - GST_BUFFER_TIMESTAMP (outbuf);
1321
1322 if (empty)
1323 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
1324
1325 gst_buffer_unmap (outbuf, &write_info);
1326
1327 GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
1328 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
1329 ret = gst_pad_push (self->src, outbuf);
1330
1331 return ret;
1332
1333 eos:
1334 {
1335 GST_DEBUG_OBJECT (self, "no data available, must be EOS");
1336 if (outbuf)
1337 gst_buffer_unref (outbuf);
1338 gst_pad_push_event (self->src, gst_event_new_eos ());
1339 return GST_FLOW_EOS;
1340 }
1341 }
1342