• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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