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