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