1 /* GStreamer
2 * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
3 * Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 /**
22 * SECTION:element-gdppay
23 * @title: gdppay
24 * @see_also: gdpdepay
25 *
26 * This element payloads GStreamer buffers and events using the
27 * GStreamer Data Protocol.
28 *
29 * |[
30 * gst-launch-1.0 -v -m videotestsrc num-buffers=50 ! gdppay ! filesink location=test.gdp
31 * ]| This pipeline creates a serialized video stream that can be played back
32 * with the example shown in gdpdepay.
33 *
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "dataprotocol.h"
41
42 #include "gstgdpelements.h"
43 #include "gstgdppay.h"
44
45 static GstStaticPadTemplate gdp_pay_sink_template =
46 GST_STATIC_PAD_TEMPLATE ("sink",
47 GST_PAD_SINK,
48 GST_PAD_ALWAYS,
49 GST_STATIC_CAPS_ANY);
50
51 static GstStaticPadTemplate gdp_pay_src_template =
52 GST_STATIC_PAD_TEMPLATE ("src",
53 GST_PAD_SRC,
54 GST_PAD_ALWAYS,
55 GST_STATIC_CAPS ("application/x-gdp"));
56
57 GST_DEBUG_CATEGORY_STATIC (gst_gdp_pay_debug);
58 #define GST_CAT_DEFAULT gst_gdp_pay_debug
59
60 #define DEFAULT_CRC_HEADER TRUE
61 #define DEFAULT_CRC_PAYLOAD FALSE
62
63 enum
64 {
65 PROP_0,
66 PROP_CRC_HEADER,
67 PROP_CRC_PAYLOAD
68 };
69
70 #define _do_init \
71 GST_DEBUG_CATEGORY_INIT (gst_gdp_pay_debug, "gdppay", 0, \
72 "GDP payloader");
73 #define gst_gdp_pay_parent_class parent_class
74 G_DEFINE_TYPE_WITH_CODE (GstGDPPay, gst_gdp_pay, GST_TYPE_ELEMENT, _do_init);
75 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (gdppay, "gdppay", GST_RANK_NONE,
76 GST_TYPE_GDP_PAY, gdp_element_init (plugin));
77
78 static void gst_gdp_pay_reset (GstGDPPay * this);
79
80 static GstFlowReturn gst_gdp_pay_chain (GstPad * pad, GstObject * parent,
81 GstBuffer * buffer);
82 static gboolean gst_gdp_pay_src_event (GstPad * pad, GstObject * parent,
83 GstEvent * event);
84 static gboolean gst_gdp_pay_sink_event (GstPad * pad, GstObject * parent,
85 GstEvent * event);
86
87 static GstStateChangeReturn gst_gdp_pay_change_state (GstElement *
88 element, GstStateChange transition);
89
90 static void gst_gdp_pay_set_property (GObject * object, guint prop_id,
91 const GValue * value, GParamSpec * pspec);
92 static void gst_gdp_pay_get_property (GObject * object, guint prop_id,
93 GValue * value, GParamSpec * pspec);
94
95 static void gst_gdp_pay_finalize (GObject * gobject);
96
97 static void
gst_gdp_pay_class_init(GstGDPPayClass * klass)98 gst_gdp_pay_class_init (GstGDPPayClass * klass)
99 {
100 GObjectClass *gobject_class;
101 GstElementClass *gstelement_class;
102
103 gobject_class = (GObjectClass *) klass;
104 gstelement_class = (GstElementClass *) klass;
105
106 gobject_class->set_property = gst_gdp_pay_set_property;
107 gobject_class->get_property = gst_gdp_pay_get_property;
108 gobject_class->finalize = gst_gdp_pay_finalize;
109
110 g_object_class_install_property (gobject_class, PROP_CRC_HEADER,
111 g_param_spec_boolean ("crc-header", "CRC Header",
112 "Calculate and store a CRC checksum on the header",
113 DEFAULT_CRC_HEADER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 g_object_class_install_property (gobject_class, PROP_CRC_PAYLOAD,
115 g_param_spec_boolean ("crc-payload", "CRC Payload",
116 "Calculate and store a CRC checksum on the payload",
117 DEFAULT_CRC_PAYLOAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
118 gst_element_class_set_static_metadata (gstelement_class,
119 "GDP Payloader", "GDP/Payloader",
120 "Payloads GStreamer Data Protocol buffers",
121 "Thomas Vander Stichele <thomas at apestaart dot org>");
122
123 gst_element_class_add_static_pad_template (gstelement_class,
124 &gdp_pay_sink_template);
125 gst_element_class_add_static_pad_template (gstelement_class,
126 &gdp_pay_src_template);
127
128 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state);
129 }
130
131 static void
gst_gdp_pay_init(GstGDPPay * gdppay)132 gst_gdp_pay_init (GstGDPPay * gdppay)
133 {
134 gdppay->sinkpad =
135 gst_pad_new_from_static_template (&gdp_pay_sink_template, "sink");
136 gst_pad_set_chain_function (gdppay->sinkpad,
137 GST_DEBUG_FUNCPTR (gst_gdp_pay_chain));
138 gst_pad_set_event_function (gdppay->sinkpad,
139 GST_DEBUG_FUNCPTR (gst_gdp_pay_sink_event));
140 gst_element_add_pad (GST_ELEMENT (gdppay), gdppay->sinkpad);
141
142 gdppay->srcpad =
143 gst_pad_new_from_static_template (&gdp_pay_src_template, "src");
144 gst_pad_set_event_function (gdppay->srcpad,
145 GST_DEBUG_FUNCPTR (gst_gdp_pay_src_event));
146 gst_element_add_pad (GST_ELEMENT (gdppay), gdppay->srcpad);
147
148 gdppay->crc_header = DEFAULT_CRC_HEADER;
149 gdppay->crc_payload = DEFAULT_CRC_PAYLOAD;
150 gdppay->header_flag = gdppay->crc_header | gdppay->crc_payload;
151 gdppay->offset = 0;
152 }
153
154 static void
gst_gdp_pay_finalize(GObject * gobject)155 gst_gdp_pay_finalize (GObject * gobject)
156 {
157 GstGDPPay *this = GST_GDP_PAY (gobject);
158
159 gst_gdp_pay_reset (this);
160
161 GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (gobject));
162 }
163
164 static void
gst_gdp_pay_reset(GstGDPPay * this)165 gst_gdp_pay_reset (GstGDPPay * this)
166 {
167 GST_DEBUG_OBJECT (this, "Resetting GDP object");
168 /* clear the queued buffers */
169 while (this->queue) {
170 GstBuffer *buffer;
171
172 buffer = GST_BUFFER_CAST (this->queue->data);
173
174 /* delete buffer from queue now */
175 this->queue = g_list_delete_link (this->queue, this->queue);
176
177 gst_buffer_unref (buffer);
178 }
179 if (this->caps) {
180 gst_caps_unref (this->caps);
181 this->caps = NULL;
182 }
183 this->have_caps = FALSE;
184 this->have_segment = FALSE;
185 this->have_streamstartid = FALSE;
186 this->sent_streamheader = FALSE;
187 this->reset_streamheader = FALSE;
188 this->offset = 0;
189 }
190
191 /* set OFFSET and OFFSET_END with running count */
192 static void
gst_gdp_stamp_buffer(GstGDPPay * this,GstBuffer * buffer)193 gst_gdp_stamp_buffer (GstGDPPay * this, GstBuffer * buffer)
194 {
195 GST_BUFFER_OFFSET (buffer) = this->offset;
196 GST_BUFFER_OFFSET_END (buffer) = this->offset + gst_buffer_get_size (buffer);
197 this->offset = GST_BUFFER_OFFSET_END (buffer);
198 }
199
200 static GstBuffer *
gst_gdp_buffer_from_caps(GstGDPPay * this,GstCaps * caps)201 gst_gdp_buffer_from_caps (GstGDPPay * this, GstCaps * caps)
202 {
203 return gst_dp_payload_caps (caps, this->header_flag);
204 }
205
206 static GstBuffer *
gst_gdp_pay_buffer_from_buffer(GstGDPPay * this,GstBuffer * buffer)207 gst_gdp_pay_buffer_from_buffer (GstGDPPay * this, GstBuffer * buffer)
208 {
209 return gst_dp_payload_buffer (buffer, this->header_flag);
210 }
211
212 static GstBuffer *
gst_gdp_buffer_from_event(GstGDPPay * this,GstEvent * event)213 gst_gdp_buffer_from_event (GstGDPPay * this, GstEvent * event)
214 {
215 return gst_dp_payload_event (event, this->header_flag);
216 }
217
218 static void
gdp_streamheader_array_append_take_buffer(GValue * array,GstBuffer * buf)219 gdp_streamheader_array_append_take_buffer (GValue * array, GstBuffer * buf)
220 {
221 GValue value = { 0, };
222
223 g_value_init (&value, GST_TYPE_BUFFER);
224 gst_value_take_buffer (&value, buf);
225 gst_value_array_append_and_take_value (array, &value);
226 }
227
228 typedef struct
229 {
230 GstGDPPay *gdppay;
231 GValue *array;
232 } GstGDPPayAndArray;
233
234 static gboolean
gdp_streamheader_array_store_events(GstPad * pad,GstEvent ** event,gpointer udata)235 gdp_streamheader_array_store_events (GstPad * pad, GstEvent ** event,
236 gpointer udata)
237 {
238 GstGDPPayAndArray *gdp_and_array = udata;
239 GstGDPPay *this = gdp_and_array->gdppay;
240 GValue *array = gdp_and_array->array;
241 GstBuffer *buf;
242
243 /* Need to handle caps differently to keep compatibility with 1.0 */
244 if (GST_EVENT_TYPE (*event) == GST_EVENT_CAPS) {
245 GstCaps *caps;
246
247 gst_event_parse_caps (*event, &caps);
248 buf = gst_gdp_buffer_from_caps (this, caps);
249 } else {
250 buf = gst_gdp_buffer_from_event (this, *event);
251 }
252
253 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
254 gst_gdp_stamp_buffer (this, buf);
255 gdp_streamheader_array_append_take_buffer (array, buf);
256
257 return TRUE;
258 }
259
260 /* set our caps with streamheader, based on the latest newsegment and caps,
261 * and (possibly) GDP-serialized buffers of the streamheaders on the src pad */
262 static GstFlowReturn
gst_gdp_pay_reset_streamheader(GstGDPPay * this)263 gst_gdp_pay_reset_streamheader (GstGDPPay * this)
264 {
265 GstCaps *caps;
266 GstStructure *structure;
267 GstFlowReturn r = GST_FLOW_OK;
268 GstGDPPayAndArray gdp_and_array;
269
270 GValue array = { 0 };
271
272 gdp_and_array.gdppay = this;
273 gdp_and_array.array = &array;
274
275 GST_DEBUG_OBJECT (this, "start");
276
277 if (!this->have_segment || !this->have_caps || !this->have_streamstartid) {
278 GST_DEBUG_OBJECT (this, "1.0, missing new_segment or caps or stream "
279 "start id, returning");
280 return GST_FLOW_OK;
281 }
282
283 /* put copies of the buffers in a fixed list
284 * Stamp the buffers with offset and offset_end as well.
285 * We do this here so the offsets match the order the buffers go out in */
286 g_value_init (&array, GST_TYPE_ARRAY);
287 gst_pad_sticky_events_foreach (this->sinkpad,
288 gdp_streamheader_array_store_events, &gdp_and_array);
289
290 /* we also need to add GDP serializations of the streamheaders of the
291 * incoming caps */
292 structure = gst_caps_get_structure (this->caps, 0);
293 if (gst_structure_has_field (structure, "streamheader")) {
294 const GValue *sh;
295 GstBuffer *buffer;
296 int i, num;
297
298 sh = gst_structure_get_value (structure, "streamheader");
299 num = gst_value_array_get_size (sh);
300 GST_DEBUG_OBJECT (this,
301 "Need to serialize %d incoming streamheader buffers on ours", num);
302
303 for (i = 0; i < num; ++i) {
304 const GValue *bufval;
305 GstBuffer *outbuffer;
306
307 bufval = gst_value_array_get_value (sh, i);
308 buffer = gst_value_get_buffer (bufval);
309
310 /* Make copy before modifying buffer metadata */
311 buffer = gst_buffer_copy (buffer);
312
313 /* this buffer is deserialized by gdpdepay as a regular buffer,
314 it needs HEADER, because it's a streamheader - otherwise it
315 is mixed with regular data buffers */
316 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
317 GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
318 GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
319 GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
320
321 outbuffer = gst_gdp_pay_buffer_from_buffer (this, buffer);
322
323 gst_buffer_unref (buffer);
324
325 if (!outbuffer) {
326 g_value_unset (&array);
327 goto no_buffer;
328 }
329
330 /* Setting HEADER as other GDP event buffers */
331 GST_DEBUG_OBJECT (this,
332 "Setting HEADER flag on outgoing buffer %" GST_PTR_FORMAT, outbuffer);
333 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_HEADER);
334 GST_BUFFER_OFFSET (outbuffer) = GST_BUFFER_OFFSET_NONE;
335 GST_BUFFER_OFFSET_END (outbuffer) = GST_BUFFER_OFFSET_NONE;
336 GST_BUFFER_TIMESTAMP (outbuffer) = GST_CLOCK_TIME_NONE;
337
338 gdp_streamheader_array_append_take_buffer (&array, outbuffer);
339 }
340 } else {
341 GST_DEBUG_OBJECT (this, "no streamheader to serialize");
342 }
343
344 GST_DEBUG_OBJECT (this, "%d serialized buffers on streamheaders",
345 gst_value_array_get_size (&array));
346 caps = gst_caps_from_string ("application/x-gdp");
347 structure = gst_caps_get_structure (caps, 0);
348
349 gst_structure_set_value (structure, "streamheader", &array);
350 g_value_unset (&array);
351
352 GST_DEBUG_OBJECT (this, "Setting caps on src pad %" GST_PTR_FORMAT, caps);
353 gst_pad_set_caps (this->srcpad, caps);
354
355 /* if these are our first ever buffers, send out new_segment first */
356 if (!this->sent_streamheader) {
357 GstEvent *event;
358 GstSegment segment;
359
360 gst_segment_init (&segment, GST_FORMAT_BYTES);
361 event = gst_event_new_segment (&segment);
362
363 GST_DEBUG_OBJECT (this, "Sending out new_segment event %p", event);
364 if (!gst_pad_push_event (this->srcpad, event)) {
365 GST_WARNING_OBJECT (this, "pushing new segment failed");
366 r = GST_FLOW_ERROR;
367 goto done;
368 }
369 }
370
371 this->sent_streamheader = TRUE;
372 GST_DEBUG_OBJECT (this, "need to push %d queued buffers",
373 g_list_length (this->queue));
374 while (this->queue) {
375 GstBuffer *buffer;
376
377 buffer = GST_BUFFER_CAST (this->queue->data);
378 GST_DEBUG_OBJECT (this, "Pushing queued GDP buffer %p", buffer);
379
380 /* delete buffer from queue now */
381 this->queue = g_list_delete_link (this->queue, this->queue);
382
383 r = gst_pad_push (this->srcpad, buffer);
384 if (r != GST_FLOW_OK) {
385 GST_WARNING_OBJECT (this, "pushing queued GDP buffer returned %d", r);
386 goto done;
387 }
388 }
389
390 this->reset_streamheader = FALSE;
391
392 done:
393 gst_caps_unref (caps);
394 GST_DEBUG_OBJECT (this, "stop");
395 return r;
396
397 /* ERRORS */
398 no_buffer:
399 {
400 GST_ELEMENT_ERROR (this, STREAM, FORMAT, (NULL),
401 ("failed to create GDP buffer from streamheader"));
402 return GST_FLOW_ERROR;
403 }
404 }
405
406 /* queue a buffer internally if we haven't sent streamheader buffers yet;
407 * otherwise, just push on, this takes ownership of the buffer. */
408 static GstFlowReturn
gst_gdp_queue_buffer(GstGDPPay * this,GstBuffer * buffer)409 gst_gdp_queue_buffer (GstGDPPay * this, GstBuffer * buffer)
410 {
411 if (this->sent_streamheader && !this->reset_streamheader) {
412 GST_LOG_OBJECT (this, "Pushing GDP buffer %p, caps %" GST_PTR_FORMAT,
413 buffer, this->caps);
414 return gst_pad_push (this->srcpad, buffer);
415 }
416
417 /* store it on an internal queue. buffer remains reffed. */
418 this->queue = g_list_append (this->queue, buffer);
419 GST_DEBUG_OBJECT (this, "streamheader not sent yet or needs update, "
420 "queued buffer %p, now %d buffers queued",
421 buffer, g_list_length (this->queue));
422
423 return GST_FLOW_OK;
424 }
425
426 static GstFlowReturn
gst_gdp_pay_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)427 gst_gdp_pay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
428 {
429 GstGDPPay *this;
430 GstBuffer *outbuffer;
431 GstFlowReturn ret;
432
433 this = GST_GDP_PAY (parent);
434
435 /* we should have received a new_segment before, otherwise it's a bug.
436 * fake one in that case */
437 if (!this->have_segment) {
438 GstEvent *event;
439 GstSegment segment;
440
441 GST_WARNING_OBJECT (this,
442 "did not receive new-segment before first buffer");
443 gst_segment_init (&segment, GST_FORMAT_BYTES);
444 event = gst_event_new_segment (&segment);
445 outbuffer = gst_gdp_buffer_from_event (this, event);
446 gst_event_unref (event);
447
448 /* GDP 0.2 doesn't know about new-segment, so this is not fatal */
449 if (!outbuffer) {
450 GST_ELEMENT_WARNING (this, STREAM, ENCODE, (NULL),
451 ("Could not create GDP buffer from new segment event"));
452 } else {
453 GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer);
454 GST_BUFFER_DURATION (outbuffer) = 0;
455 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_HEADER);
456 GST_DEBUG_OBJECT (this, "Storing buffer %p as new_segment_buf",
457 outbuffer);
458 this->have_segment = TRUE;
459 }
460 }
461 /* make sure we've received caps before */
462 if (!this->caps)
463 goto no_caps;
464
465 /* create a GDP header packet,
466 * then create a GST buffer of the header packet and the buffer contents */
467 outbuffer = gst_gdp_pay_buffer_from_buffer (this, buffer);
468 if (!outbuffer)
469 goto no_buffer;
470
471 /* If the incoming buffer is HEADER, that means we have it on the caps
472 * as streamheader, and we have serialized a GDP version of it and put it
473 * on our caps */
474 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_HEADER)) {
475 GST_DEBUG_OBJECT (this, "Setting HEADER flag on outgoing buffer %p",
476 outbuffer);
477 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_HEADER);
478 }
479
480 gst_gdp_stamp_buffer (this, outbuffer);
481 GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer);
482 GST_BUFFER_DURATION (outbuffer) = GST_BUFFER_DURATION (buffer);
483
484 if (this->reset_streamheader)
485 gst_gdp_pay_reset_streamheader (this);
486
487 ret = gst_gdp_queue_buffer (this, outbuffer);
488
489 done:
490 gst_buffer_unref (buffer);
491
492 return ret;
493
494 /* ERRORS */
495 no_caps:
496 {
497 /* when returning a fatal error as a GstFlowReturn we must post an error
498 * message */
499 GST_ELEMENT_ERROR (this, STREAM, FORMAT, (NULL),
500 ("first received buffer does not have caps set"));
501 ret = GST_FLOW_NOT_NEGOTIATED;
502 goto done;
503 }
504 no_buffer:
505 {
506 GST_ELEMENT_ERROR (this, STREAM, ENCODE, (NULL),
507 ("Could not create GDP buffer from buffer"));
508 ret = GST_FLOW_ERROR;
509 goto done;
510 }
511 }
512
513 static gboolean
gst_gdp_pay_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)514 gst_gdp_pay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
515 {
516 GstBuffer *outbuffer;
517 GstGDPPay *this = GST_GDP_PAY (parent);
518 GstFlowReturn flowret;
519 GstCaps *caps;
520 gboolean ret = TRUE;
521
522 GST_DEBUG_OBJECT (this, "received event %p of type %s (%d)",
523 event, gst_event_type_get_name (event->type), event->type);
524
525 /* now turn the event into a buffer */
526 outbuffer = gst_gdp_buffer_from_event (this, event);
527 if (!outbuffer)
528 goto no_outbuffer;
529
530 GST_BUFFER_TIMESTAMP (outbuffer) = GST_CLOCK_TIME_NONE;
531 GST_BUFFER_DURATION (outbuffer) = 0;
532
533 /* if we got a new segment or tag event, we should put it on our streamheader,
534 * and not send it on */
535 switch (GST_EVENT_TYPE (event)) {
536 case GST_EVENT_STREAM_START:
537 GST_DEBUG_OBJECT (this, "Received stream start id");
538 this->have_streamstartid = TRUE;
539 break;
540 case GST_EVENT_SEGMENT:
541 GST_DEBUG_OBJECT (this, "Received segment %" GST_PTR_FORMAT, event);
542 this->have_segment = TRUE;
543 break;
544 case GST_EVENT_CAPS:{
545 GST_DEBUG_OBJECT (this, "Received caps %" GST_PTR_FORMAT, event);
546 this->have_caps = TRUE;
547 gst_event_parse_caps (event, &caps);
548 gst_buffer_replace (&outbuffer, NULL);
549 if (this->caps == NULL || !gst_caps_is_equal (this->caps, caps)) {
550 GST_INFO_OBJECT (pad, "caps changed to %" GST_PTR_FORMAT, caps);
551 gst_caps_replace (&this->caps, caps);
552 outbuffer = gst_gdp_buffer_from_caps (this, caps);
553 if (outbuffer == NULL)
554 goto no_buffer_from_caps;
555
556 GST_BUFFER_DURATION (outbuffer) = 0;
557 }
558 break;
559 }
560 default:
561 break;
562 }
563
564 if (GST_EVENT_IS_STICKY (event)) {
565 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_HEADER);
566 this->reset_streamheader = TRUE;
567 }
568
569 /* if we have EOS, we should send on EOS ourselves */
570 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS
571 || GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
572 GST_DEBUG_OBJECT (this, "Sending on event %" GST_PTR_FORMAT, event);
573 /* ref, we unref later again */
574 ret = gst_pad_push_event (this->srcpad, gst_event_ref (event));
575 }
576
577 if (GST_EVENT_TYPE (event) != GST_EVENT_EOS) {
578 GST_DEBUG_OBJECT (this, "queuing GDP buffer %p of event %p", outbuffer,
579 event);
580 flowret = gst_gdp_queue_buffer (this, outbuffer);
581 if (flowret != GST_FLOW_OK)
582 goto push_error;
583 } else {
584 gst_buffer_unref (outbuffer);
585 }
586
587 done:
588 gst_event_unref (event);
589
590 return ret;
591
592 /* ERRORS */
593 no_outbuffer:
594 {
595 GST_ELEMENT_WARNING (this, STREAM, ENCODE, (NULL),
596 ("Could not create GDP buffer from received event (type %s)",
597 gst_event_type_get_name (event->type)));
598 ret = FALSE;
599 goto done;
600 }
601 no_buffer_from_caps:
602 {
603 GST_ELEMENT_ERROR (this, STREAM, ENCODE, (NULL),
604 ("Could not create GDP buffer from caps %" GST_PTR_FORMAT, caps));
605 ret = FALSE;
606 goto done;
607 }
608 push_error:
609 {
610 GST_WARNING_OBJECT (this, "queueing GDP event buffer returned %d", flowret);
611 ret = FALSE;
612 goto done;
613 }
614 }
615
616 static gboolean
gst_gdp_pay_src_event(GstPad * pad,GstObject * parent,GstEvent * event)617 gst_gdp_pay_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
618 {
619 GstGDPPay *this;
620 gboolean res = TRUE;
621
622 this = GST_GDP_PAY (parent);
623
624 switch (GST_EVENT_TYPE (event)) {
625 case GST_EVENT_SEEK:
626 /* we refuse seek for now. */
627 gst_event_unref (event);
628 res = FALSE;
629 break;
630 case GST_EVENT_QOS:
631 case GST_EVENT_NAVIGATION:
632 default:
633 /* everything else is passed */
634 res = gst_pad_push_event (this->sinkpad, event);
635 break;
636 }
637
638 return res;
639 }
640
641 static void
gst_gdp_pay_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)642 gst_gdp_pay_set_property (GObject * object, guint prop_id,
643 const GValue * value, GParamSpec * pspec)
644 {
645 GstGDPPay *this;
646
647 g_return_if_fail (GST_IS_GDP_PAY (object));
648 this = GST_GDP_PAY (object);
649
650 switch (prop_id) {
651 case PROP_CRC_HEADER:
652 this->crc_header =
653 g_value_get_boolean (value) ? GST_DP_HEADER_FLAG_CRC_HEADER : 0;
654 this->header_flag = this->crc_header | this->crc_payload;
655 break;
656 case PROP_CRC_PAYLOAD:
657 this->crc_payload =
658 g_value_get_boolean (value) ? GST_DP_HEADER_FLAG_CRC_PAYLOAD : 0;
659 this->header_flag = this->crc_header | this->crc_payload;
660 break;
661 default:
662 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
663 break;
664 }
665 }
666
667 static void
gst_gdp_pay_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)668 gst_gdp_pay_get_property (GObject * object, guint prop_id,
669 GValue * value, GParamSpec * pspec)
670 {
671 GstGDPPay *this;
672
673 g_return_if_fail (GST_IS_GDP_PAY (object));
674 this = GST_GDP_PAY (object);
675
676 switch (prop_id) {
677 case PROP_CRC_HEADER:
678 g_value_set_boolean (value, this->crc_header);
679 break;
680 case PROP_CRC_PAYLOAD:
681 g_value_set_boolean (value, this->crc_payload);
682 break;
683 default:
684 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
685 break;
686 }
687 }
688
689 static GstStateChangeReturn
gst_gdp_pay_change_state(GstElement * element,GstStateChange transition)690 gst_gdp_pay_change_state (GstElement * element, GstStateChange transition)
691 {
692 GstStateChangeReturn ret;
693 GstGDPPay *this = GST_GDP_PAY (element);
694
695 switch (transition) {
696 case GST_STATE_CHANGE_READY_TO_PAUSED:
697 break;
698 default:
699 break;
700 }
701
702 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
703
704 switch (transition) {
705 case GST_STATE_CHANGE_PAUSED_TO_READY:
706 gst_gdp_pay_reset (this);
707 break;
708 default:
709 break;
710 }
711
712 return ret;
713 }
714