19 |
19 |
20 /** |
20 /** |
21 * SECTION:element-gdppay |
21 * SECTION:element-gdppay |
22 * @see_also: gdpdepay |
22 * @see_also: gdpdepay |
23 * |
23 * |
|
24 * <refsect2> |
|
25 * <para> |
24 * This element payloads GStreamer buffers and events using the |
26 * This element payloads GStreamer buffers and events using the |
25 * GStreamer Data Protocol. |
27 * GStreamer Data Protocol. |
26 * |
28 * </para> |
27 * <refsect2> |
29 * <para> |
28 * |[ |
30 * <programlisting> |
29 * gst-launch -v -m videotestsrc num-buffers=50 ! gdppay ! filesink location=test.gdp |
31 * gst-launch -v -m videotestsrc num-buffers=50 ! gdppay ! filesink location=test.gdp |
30 * ]| This pipeline creates a serialized video stream that can be played back |
32 * </programlisting> |
|
33 * This pipeline creates a serialized video stream that can be played back |
31 * with the example shown in gdpdepay. |
34 * with the example shown in gdpdepay. |
|
35 * </para> |
32 * </refsect2> |
36 * </refsect2> |
33 */ |
37 */ |
34 |
38 |
35 #ifdef HAVE_CONFIG_H |
39 #ifdef HAVE_CONFIG_H |
36 #include "config.h" |
40 #include "config.h" |
80 |
84 |
81 GST_BOILERPLATE_FULL (GstGDPPay, gst_gdp_pay, GstElement, |
85 GST_BOILERPLATE_FULL (GstGDPPay, gst_gdp_pay, GstElement, |
82 GST_TYPE_ELEMENT, _do_init); |
86 GST_TYPE_ELEMENT, _do_init); |
83 |
87 |
84 static void gst_gdp_pay_reset (GstGDPPay * this); |
88 static void gst_gdp_pay_reset (GstGDPPay * this); |
85 |
|
86 static GstFlowReturn gst_gdp_pay_chain (GstPad * pad, GstBuffer * buffer); |
89 static GstFlowReturn gst_gdp_pay_chain (GstPad * pad, GstBuffer * buffer); |
87 |
90 |
88 static gboolean gst_gdp_pay_src_event (GstPad * pad, GstEvent * event); |
91 static gboolean gst_gdp_pay_src_event (GstPad * pad, GstEvent * event); |
89 |
|
90 static gboolean gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event); |
92 static gboolean gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event); |
91 |
93 |
92 static GstStateChangeReturn gst_gdp_pay_change_state (GstElement * |
94 static GstStateChangeReturn gst_gdp_pay_change_state (GstElement * |
93 element, GstStateChange transition); |
95 element, GstStateChange transition); |
94 |
96 |
114 |
116 |
115 static void |
117 static void |
116 gst_gdp_pay_class_init (GstGDPPayClass * klass) |
118 gst_gdp_pay_class_init (GstGDPPayClass * klass) |
117 { |
119 { |
118 GObjectClass *gobject_class; |
120 GObjectClass *gobject_class; |
119 |
|
120 GstElementClass *gstelement_class; |
121 GstElementClass *gstelement_class; |
121 |
122 |
122 gobject_class = (GObjectClass *) klass; |
123 gobject_class = (GObjectClass *) klass; |
123 gstelement_class = (GstElementClass *) klass; |
124 gstelement_class = (GstElementClass *) klass; |
124 |
125 |
127 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gdp_pay_finalize); |
128 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gdp_pay_finalize); |
128 |
129 |
129 g_object_class_install_property (gobject_class, PROP_CRC_HEADER, |
130 g_object_class_install_property (gobject_class, PROP_CRC_HEADER, |
130 g_param_spec_boolean ("crc-header", "CRC Header", |
131 g_param_spec_boolean ("crc-header", "CRC Header", |
131 "Calculate and store a CRC checksum on the header", |
132 "Calculate and store a CRC checksum on the header", |
132 DEFAULT_CRC_HEADER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
133 DEFAULT_CRC_HEADER, G_PARAM_READWRITE)); |
133 g_object_class_install_property (gobject_class, PROP_CRC_PAYLOAD, |
134 g_object_class_install_property (gobject_class, PROP_CRC_PAYLOAD, |
134 g_param_spec_boolean ("crc-payload", "CRC Payload", |
135 g_param_spec_boolean ("crc-payload", "CRC Payload", |
135 "Calculate and store a CRC checksum on the payload", |
136 "Calculate and store a CRC checksum on the payload", |
136 DEFAULT_CRC_PAYLOAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
137 DEFAULT_CRC_PAYLOAD, G_PARAM_READWRITE)); |
137 g_object_class_install_property (gobject_class, PROP_VERSION, |
138 g_object_class_install_property (gobject_class, PROP_VERSION, |
138 g_param_spec_enum ("version", "Version", |
139 g_param_spec_enum ("version", "Version", |
139 "Version of the GStreamer Data Protocol", |
140 "Version of the GStreamer Data Protocol", |
140 GST_TYPE_DP_VERSION, DEFAULT_VERSION, |
141 GST_TYPE_DP_VERSION, DEFAULT_VERSION, G_PARAM_READWRITE)); |
141 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
142 |
142 |
143 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state); |
143 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state); |
144 } |
144 } |
145 |
145 |
146 static void |
146 static void |
187 /* clear the queued buffers */ |
187 /* clear the queued buffers */ |
188 while (this->queue) { |
188 while (this->queue) { |
189 GstBuffer *buffer; |
189 GstBuffer *buffer; |
190 |
190 |
191 buffer = GST_BUFFER_CAST (this->queue->data); |
191 buffer = GST_BUFFER_CAST (this->queue->data); |
|
192 GST_DEBUG_OBJECT (this, "Pushing queued GDP buffer %p", buffer); |
192 |
193 |
193 /* delete buffer from queue now */ |
194 /* delete buffer from queue now */ |
194 this->queue = g_list_delete_link (this->queue, this->queue); |
195 this->queue = g_list_delete_link (this->queue, this->queue); |
195 |
|
196 gst_buffer_unref (buffer); |
|
197 } |
196 } |
198 if (this->caps) { |
197 if (this->caps) { |
199 gst_caps_unref (this->caps); |
198 gst_caps_unref (this->caps); |
200 this->caps = NULL; |
199 this->caps = NULL; |
201 } |
200 } |
226 |
225 |
227 static GstBuffer * |
226 static GstBuffer * |
228 gst_gdp_buffer_from_caps (GstGDPPay * this, GstCaps * caps) |
227 gst_gdp_buffer_from_caps (GstGDPPay * this, GstCaps * caps) |
229 { |
228 { |
230 GstBuffer *headerbuf; |
229 GstBuffer *headerbuf; |
231 |
|
232 GstBuffer *payloadbuf; |
230 GstBuffer *payloadbuf; |
233 |
|
234 guint8 *header, *payload; |
231 guint8 *header, *payload; |
235 |
|
236 guint len; |
232 guint len; |
237 |
233 |
238 if (!this->packetizer->packet_from_caps (caps, this->header_flag, &len, |
234 if (!this->packetizer->packet_from_caps (caps, this->header_flag, &len, |
239 &header, &payload)) |
235 &header, &payload)) |
240 goto packet_failed; |
236 goto packet_failed; |
292 |
286 |
293 static GstBuffer * |
287 static GstBuffer * |
294 gst_gdp_buffer_from_event (GstGDPPay * this, GstEvent * event) |
288 gst_gdp_buffer_from_event (GstGDPPay * this, GstEvent * event) |
295 { |
289 { |
296 GstBuffer *headerbuf; |
290 GstBuffer *headerbuf; |
297 |
|
298 GstBuffer *payloadbuf; |
291 GstBuffer *payloadbuf; |
299 |
|
300 guint8 *header, *payload; |
292 guint8 *header, *payload; |
301 |
|
302 guint len; |
293 guint len; |
303 |
|
304 gboolean ret; |
294 gboolean ret; |
305 |
295 |
306 ret = |
296 ret = |
307 this->packetizer->packet_from_event (event, this->header_flag, &len, |
297 this->packetizer->packet_from_event (event, this->header_flag, &len, |
308 &header, &payload); |
298 &header, &payload); |
338 { |
328 { |
339 GstCaps *caps; |
329 GstCaps *caps; |
340 |
330 |
341 /* We use copies of these to avoid circular refcounts */ |
331 /* We use copies of these to avoid circular refcounts */ |
342 GstBuffer *new_segment_buf, *caps_buf, *tag_buf; |
332 GstBuffer *new_segment_buf, *caps_buf, *tag_buf; |
343 |
|
344 GstStructure *structure; |
333 GstStructure *structure; |
345 |
|
346 GstFlowReturn r = GST_FLOW_OK; |
334 GstFlowReturn r = GST_FLOW_OK; |
347 |
|
348 gboolean version_one_zero = TRUE; |
335 gboolean version_one_zero = TRUE; |
349 |
336 |
350 GValue array = { 0 }; |
337 GValue array = { 0 }; |
351 GValue value = { 0 }; |
338 GValue value = { 0 }; |
352 |
339 |
375 if (version_one_zero) { |
362 if (version_one_zero) { |
376 gst_gdp_stamp_buffer (this, this->new_segment_buf); |
363 gst_gdp_stamp_buffer (this, this->new_segment_buf); |
377 GST_DEBUG_OBJECT (this, "1.0, appending copy of new segment buffer %p", |
364 GST_DEBUG_OBJECT (this, "1.0, appending copy of new segment buffer %p", |
378 this->new_segment_buf); |
365 this->new_segment_buf); |
379 new_segment_buf = gst_buffer_copy (this->new_segment_buf); |
366 new_segment_buf = gst_buffer_copy (this->new_segment_buf); |
380 gst_buffer_set_caps (new_segment_buf, NULL); |
|
381 g_value_init (&value, GST_TYPE_BUFFER); |
367 g_value_init (&value, GST_TYPE_BUFFER); |
382 gst_value_set_buffer (&value, new_segment_buf); |
368 gst_value_set_buffer (&value, new_segment_buf); |
383 gst_value_array_append_value (&array, &value); |
369 gst_value_array_append_value (&array, &value); |
384 g_value_unset (&value); |
370 g_value_unset (&value); |
385 gst_buffer_unref (new_segment_buf); |
371 gst_buffer_unref (new_segment_buf); |
387 if (this->tag_buf) { |
373 if (this->tag_buf) { |
388 gst_gdp_stamp_buffer (this, this->tag_buf); |
374 gst_gdp_stamp_buffer (this, this->tag_buf); |
389 GST_DEBUG_OBJECT (this, "1.0, appending copy of tag buffer %p", |
375 GST_DEBUG_OBJECT (this, "1.0, appending copy of tag buffer %p", |
390 this->tag_buf); |
376 this->tag_buf); |
391 tag_buf = gst_buffer_copy (this->tag_buf); |
377 tag_buf = gst_buffer_copy (this->tag_buf); |
392 gst_buffer_set_caps (tag_buf, NULL); |
|
393 g_value_init (&value, GST_TYPE_BUFFER); |
378 g_value_init (&value, GST_TYPE_BUFFER); |
394 gst_value_set_buffer (&value, tag_buf); |
379 gst_value_set_buffer (&value, tag_buf); |
395 gst_value_array_append_value (&array, &value); |
380 gst_value_array_append_value (&array, &value); |
396 g_value_unset (&value); |
381 g_value_unset (&value); |
397 gst_buffer_unref (tag_buf); |
382 gst_buffer_unref (tag_buf); |
399 } |
384 } |
400 |
385 |
401 gst_gdp_stamp_buffer (this, this->caps_buf); |
386 gst_gdp_stamp_buffer (this, this->caps_buf); |
402 GST_DEBUG_OBJECT (this, "appending copy of caps buffer %p", this->caps_buf); |
387 GST_DEBUG_OBJECT (this, "appending copy of caps buffer %p", this->caps_buf); |
403 caps_buf = gst_buffer_copy (this->caps_buf); |
388 caps_buf = gst_buffer_copy (this->caps_buf); |
404 gst_buffer_set_caps (caps_buf, NULL); |
|
405 g_value_init (&value, GST_TYPE_BUFFER); |
389 g_value_init (&value, GST_TYPE_BUFFER); |
406 gst_value_set_buffer (&value, caps_buf); |
390 gst_value_set_buffer (&value, caps_buf); |
407 gst_value_array_append_value (&array, &value); |
391 gst_value_array_append_value (&array, &value); |
408 g_value_unset (&value); |
392 g_value_unset (&value); |
409 gst_buffer_unref (caps_buf); |
393 gst_buffer_unref (caps_buf); |
411 /* we also need to add GDP serializations of the streamheaders of the |
395 /* we also need to add GDP serializations of the streamheaders of the |
412 * incoming caps */ |
396 * incoming caps */ |
413 structure = gst_caps_get_structure (this->caps, 0); |
397 structure = gst_caps_get_structure (this->caps, 0); |
414 if (gst_structure_has_field (structure, "streamheader")) { |
398 if (gst_structure_has_field (structure, "streamheader")) { |
415 const GValue *sh; |
399 const GValue *sh; |
416 |
|
417 GArray *buffers; |
400 GArray *buffers; |
418 |
|
419 GstBuffer *buffer; |
401 GstBuffer *buffer; |
420 |
|
421 int i; |
402 int i; |
422 |
403 |
423 sh = gst_structure_get_value (structure, "streamheader"); |
404 sh = gst_structure_get_value (structure, "streamheader"); |
424 buffers = g_value_peek_pointer (sh); |
405 buffers = g_value_peek_pointer (sh); |
425 GST_DEBUG_OBJECT (this, |
406 GST_DEBUG_OBJECT (this, |
426 "Need to serialize %d incoming streamheader buffers on ours", |
407 "Need to serialize %d incoming streamheader buffers on ours", |
427 buffers->len); |
408 buffers->len); |
428 for (i = 0; i < buffers->len; ++i) { |
409 for (i = 0; i < buffers->len; ++i) { |
429 GValue *bufval; |
410 GValue *bufval; |
430 |
|
431 GstBuffer *outbuffer; |
411 GstBuffer *outbuffer; |
432 |
412 |
433 bufval = &g_array_index (buffers, GValue, i); |
413 bufval = &g_array_index (buffers, GValue, i); |
434 buffer = g_value_peek_pointer (bufval); |
414 buffer = g_value_peek_pointer (bufval); |
435 outbuffer = gst_gdp_pay_buffer_from_buffer (this, buffer); |
415 outbuffer = gst_gdp_pay_buffer_from_buffer (this, buffer); |
484 if (r != GST_FLOW_OK) { |
464 if (r != GST_FLOW_OK) { |
485 GST_WARNING_OBJECT (this, "pushing GDP newsegment buffer returned %d", r); |
465 GST_WARNING_OBJECT (this, "pushing GDP newsegment buffer returned %d", r); |
486 goto done; |
466 goto done; |
487 } |
467 } |
488 if (this->tag_buf) { |
468 if (this->tag_buf) { |
489 gst_buffer_set_caps (this->tag_buf, caps); |
|
490 GST_DEBUG_OBJECT (this, "Pushing GDP tag buffer %p", this->tag_buf); |
469 GST_DEBUG_OBJECT (this, "Pushing GDP tag buffer %p", this->tag_buf); |
491 /* we stored these bufs with refcount 1, so make sure we keep a ref */ |
470 /* we stored these bufs with refcount 1, so make sure we keep a ref */ |
492 r = gst_pad_push (this->srcpad, gst_buffer_ref (this->tag_buf)); |
471 r = gst_pad_push (this->srcpad, gst_buffer_ref (this->tag_buf)); |
493 if (r != GST_FLOW_OK) { |
472 if (r != GST_FLOW_OK) { |
494 GST_WARNING_OBJECT (this, "pushing GDP tag buffer returned %d", r); |
473 GST_WARNING_OBJECT (this, "pushing GDP tag buffer returned %d", r); |
542 gst_gdp_queue_buffer (GstGDPPay * this, GstBuffer * buffer) |
521 gst_gdp_queue_buffer (GstGDPPay * this, GstBuffer * buffer) |
543 { |
522 { |
544 if (this->sent_streamheader) { |
523 if (this->sent_streamheader) { |
545 GST_LOG_OBJECT (this, "Pushing GDP buffer %p, caps %" GST_PTR_FORMAT, |
524 GST_LOG_OBJECT (this, "Pushing GDP buffer %p, caps %" GST_PTR_FORMAT, |
546 buffer, this->caps); |
525 buffer, this->caps); |
547 gst_buffer_set_caps (buffer, GST_PAD_CAPS (this->srcpad)); |
|
548 return gst_pad_push (this->srcpad, buffer); |
526 return gst_pad_push (this->srcpad, buffer); |
549 } |
527 } |
550 |
528 |
551 /* store it on an internal queue. buffer remains reffed. */ |
529 /* store it on an internal queue. buffer remains reffed. */ |
552 this->queue = g_list_append (this->queue, buffer); |
530 this->queue = g_list_append (this->queue, buffer); |
609 goto no_caps_buffer; |
584 goto no_caps_buffer; |
610 |
585 |
611 GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer); |
586 GST_BUFFER_TIMESTAMP (outbuffer) = GST_BUFFER_TIMESTAMP (buffer); |
612 GST_BUFFER_DURATION (outbuffer) = 0; |
587 GST_BUFFER_DURATION (outbuffer) = 0; |
613 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_IN_CAPS); |
588 GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_IN_CAPS); |
614 |
|
615 if (this->caps_buf) |
|
616 gst_buffer_unref (this->caps_buf); |
|
617 this->caps_buf = outbuffer; |
589 this->caps_buf = outbuffer; |
618 gst_gdp_pay_reset_streamheader (this); |
590 gst_gdp_pay_reset_streamheader (this); |
619 } |
591 } |
620 |
592 |
621 if (caps) |
593 if (caps) |
678 |
650 |
679 static gboolean |
651 static gboolean |
680 gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event) |
652 gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event) |
681 { |
653 { |
682 GstBuffer *outbuffer; |
654 GstBuffer *outbuffer; |
683 |
|
684 GstGDPPay *this = GST_GDP_PAY (gst_pad_get_parent (pad)); |
655 GstGDPPay *this = GST_GDP_PAY (gst_pad_get_parent (pad)); |
685 |
|
686 GstFlowReturn flowret; |
656 GstFlowReturn flowret; |
687 |
|
688 gboolean ret = TRUE; |
657 gboolean ret = TRUE; |
689 |
658 |
690 GST_DEBUG_OBJECT (this, "received event %p of type %s (%d)", |
659 GST_DEBUG_OBJECT (this, "received event %p of type %s (%d)", |
691 event, gst_event_type_get_name (event->type), event->type); |
660 event, gst_event_type_get_name (event->type), event->type); |
692 |
661 |
845 |
813 |
846 static GstStateChangeReturn |
814 static GstStateChangeReturn |
847 gst_gdp_pay_change_state (GstElement * element, GstStateChange transition) |
815 gst_gdp_pay_change_state (GstElement * element, GstStateChange transition) |
848 { |
816 { |
849 GstStateChangeReturn ret; |
817 GstStateChangeReturn ret; |
850 |
|
851 GstGDPPay *this = GST_GDP_PAY (element); |
818 GstGDPPay *this = GST_GDP_PAY (element); |
852 |
819 |
853 switch (transition) { |
820 switch (transition) { |
854 case GST_STATE_CHANGE_READY_TO_PAUSED: |
821 case GST_STATE_CHANGE_READY_TO_PAUSED: |
855 break; |
822 break; |