1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot org>
4 *
5 * dataprotocol.c: Functions implementing the GStreamer Data Protocol
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
23 /**
24 * SECTION:gstdataprotocol
25 * @short_description: Serialization of caps, buffers and events.
26 * @see_also: #GstCaps, #GstEvent, #GstBuffer
27 *
28 * This helper library provides serialization of GstBuffer, GstCaps and
29 * GstEvent structures.
30 *
31 * This serialization is useful when GStreamer needs to interface with
32 * the outside world to transport data between distinct GStreamer pipelines.
33 * The connections with the outside world generally don't have mechanisms
34 * to transport properties of these structures.
35 *
36 * For example, transporting buffers across named pipes or network connections
37 * doesn't maintain the buffer size and separation.
38 *
39 * This data protocol assumes a reliable connection-oriented transport, such as
40 * TCP, a pipe, or a file. The protocol does not serialize the caps for
41 * each buffer; instead, it transport the caps only when they change in the
42 * stream. This implies that there will always be a caps packet before any
43 * buffer packets.
44 *
45 * The versioning of the protocol is independent of GStreamer's version.
46 * The major number gets incremented, and the minor reset, for incompatible
47 * changes. The minor number gets incremented for compatible changes that
48 * allow clients who do not completely understand the newer protocol version
49 * to still decode what they do understand.
50 *
51 * Version 0.2 serializes only a small subset of all events, with a custom
52 * payload for each type. Also, all GDP streams start with the initial caps
53 * packet.
54 *
55 * Version 1.0 serializes all events by taking the string representation of
56 * the event as the payload. In addition, GDP streams can now start with
57 * events as well, as required by the new data stream model in GStreamer 0.10.
58 *
59 * Converting buffers, caps and events to GDP buffers is done using a
60 * #GstDPPacketizer object and invoking its packetizer functions.
61 * For backwards-compatibility reasons, the old 0.2 methods are still
62 * available but deprecated.
63 */
65 #ifdef HAVE_CONFIG_H
66 #include "config.h"
67 #endif
69 #include <gst/gst.h>
70 #include <gst/dataprotocol/dataprotocol.h>
71 #include <glib/gprintf.h> /* g_sprintf */
72 #include <string.h> /* strlen */
73 #include "dp-private.h"
75 /* debug category */
76 GST_DEBUG_CATEGORY (data_protocol_debug);
77 #define GST_CAT_DEFAULT data_protocol_debug
79 /* helper macros */
81 /* write first 6 bytes of header, as well as ABI padding */
82 #define GST_DP_INIT_HEADER(h, version, flags, type) \
83 G_STMT_START { \
84 gint maj = 0, min = 0; \
85 switch (version) { \
86 case GST_DP_VERSION_0_2: maj = 0; min = 2; break; \
87 case GST_DP_VERSION_1_0: maj = 1; min = 0; break; \
88 } \
89 h[0] = (guint8) maj; \
90 h[1] = (guint8) min; \
91 h[2] = (guint8) flags; \
92 h[3] = 0; /* padding byte */ \
93 GST_WRITE_UINT16_BE (h + 4, type); \
94 \
95 GST_WRITE_UINT64_BE (h + 42, (guint64) 0); /* ABI padding */ \
96 GST_WRITE_UINT64_BE (h + 50, (guint64) 0); /* ABI padding */ \
97 } G_STMT_END
99 #define GST_DP_SET_CRC(h, flags, payload, length); \
100 G_STMT_START { \
101 guint16 crc = 0; \
102 if (flags & GST_DP_HEADER_FLAG_CRC_HEADER) \
103 /* we don't crc the last four bytes since they are crc's */ \
104 crc = gst_dp_crc (h, 58); \
105 GST_WRITE_UINT16_BE (h + 58, crc); \
106 \
107 crc = 0; \
108 if (length && (flags & GST_DP_HEADER_FLAG_CRC_PAYLOAD)) \
109 crc = gst_dp_crc (payload, length); \
110 GST_WRITE_UINT16_BE (h + 60, crc); \
111 } G_STMT_END
113 /* calculate a CCITT 16 bit CRC check value for a given byte array */
114 /*
115 * this code snippet is adapted from a web page I found
116 * it is identical except for cleanups, and a final XOR with 0xffff
117 * as outlined in the uecp spec
118 *
119 * XMODEM x^16 + x^12 + x^5 + 1
120 */
122 #define POLY 0x1021
123 #define CRC_INIT 0xFFFF
125 /*** HELPER FUNCTIONS ***/
127 static gboolean
128 gst_dp_header_from_buffer_any (const GstBuffer * buffer, GstDPHeaderFlag flags,
129 guint * length, guint8 ** header, GstDPVersion version)
130 {
131 guint8 *h;
132 guint16 flags_mask;
134 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
135 g_return_val_if_fail (header, FALSE);
137 *length = GST_DP_HEADER_LENGTH;
138 h = g_malloc0 (GST_DP_HEADER_LENGTH);
140 /* version, flags, type */
141 GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_BUFFER);
143 /* buffer properties */
144 GST_WRITE_UINT32_BE (h + 6, GST_BUFFER_SIZE (buffer));
145 GST_WRITE_UINT64_BE (h + 10, GST_BUFFER_TIMESTAMP (buffer));
146 GST_WRITE_UINT64_BE (h + 18, GST_BUFFER_DURATION (buffer));
147 GST_WRITE_UINT64_BE (h + 26, GST_BUFFER_OFFSET (buffer));
148 GST_WRITE_UINT64_BE (h + 34, GST_BUFFER_OFFSET_END (buffer));
150 /* data flags; eats two bytes from the ABI area */
151 /* we copy everything but the read-only flags */
152 flags_mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_DISCONT |
153 GST_BUFFER_FLAG_IN_CAPS | GST_BUFFER_FLAG_GAP |
154 GST_BUFFER_FLAG_DELTA_UNIT;
156 GST_WRITE_UINT16_BE (h + 42, GST_BUFFER_FLAGS (buffer) & flags_mask);
158 GST_DP_SET_CRC (h, flags, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
160 GST_LOG ("created header from buffer:");
161 gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
162 *header = h;
163 return TRUE;
164 }
166 static gboolean
167 gst_dp_packet_from_caps_any (const GstCaps * caps, GstDPHeaderFlag flags,
168 guint * length, guint8 ** header, guint8 ** payload, GstDPVersion version)
169 {
170 guint8 *h;
171 guchar *string;
172 guint payload_length;
174 /* FIXME: GST_IS_CAPS doesn't work
175 g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); */
176 g_return_val_if_fail (caps, FALSE);
177 g_return_val_if_fail (header, FALSE);
178 g_return_val_if_fail (payload, FALSE);
180 *length = GST_DP_HEADER_LENGTH;
181 h = g_malloc0 (GST_DP_HEADER_LENGTH);
183 string = (guchar *) gst_caps_to_string (caps);
184 payload_length = strlen ((gchar *) string) + 1; /* include trailing 0 */
186 /* version, flags, type */
187 GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_CAPS);
189 /* buffer properties */
190 GST_WRITE_UINT32_BE (h + 6, payload_length);
191 GST_WRITE_UINT64_BE (h + 10, (guint64) 0);
192 GST_WRITE_UINT64_BE (h + 18, (guint64) 0);
193 GST_WRITE_UINT64_BE (h + 26, (guint64) 0);
194 GST_WRITE_UINT64_BE (h + 34, (guint64) 0);
196 GST_DP_SET_CRC (h, flags, string, payload_length);
198 GST_LOG ("created header from caps:");
199 gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
200 *header = h;
201 *payload = string;
202 return TRUE;
203 }
206 /*** PUBLIC FUNCTIONS ***/
208 /**
209 * gst_dp_crc:
210 *
211 * Calculate a CRC for the given buffer over the given number of bytes.
212 * This is only provided for verification purposes; typical GDP users
213 * will not need this function.
214 *
215 * Returns: a two-byte CRC checksum.
216 */
217 guint16
218 gst_dp_crc (const guint8 * buffer, guint length)
219 {
220 static gboolean initialized = FALSE;
221 static guint16 crc_table[256];
222 guint16 crc_register = CRC_INIT;
223 unsigned long i, j, k;
225 if (!initialized) {
226 for (i = 0; i < 256; i++) {
227 j = i << 8;
228 for (k = 8; k--;) {
229 j = j & 0x8000 ? (j << 1) ^ POLY : j << 1;
230 }
232 crc_table[i] = (guint16) j;
233 }
234 initialized = TRUE;
235 }
237 /* calc CRC */
238 for (; length--;) {
239 crc_register = (guint16) ((crc_register << 8) ^
240 crc_table[((crc_register >> 8) & 0x00ff) ^ *buffer++]);
241 }
242 return (0xffff ^ crc_register);
243 }
245 /* debugging function; dumps byte array values per 8 bytes */
246 /* FIXME: would be nice to merge this with gst_util_dump_mem () */
247 void
248 gst_dp_dump_byte_array (guint8 * array, guint length)
249 {
250 int i;
251 int n = 8; /* number of bytes per line */
252 gchar *line = g_malloc0 (3 * n + 1);
254 GST_LOG ("dumping byte array of length %d", length);
255 for (i = 0; i < length; ++i) {
256 g_sprintf (line + 3 * (i % n), "%02x ", array[i]);
257 if (i % n == (n - 1)) {
258 GST_LOG ("%03d: %s", i - (n - 1), line);
259 }
260 }
261 if (i % n != 0) {
262 GST_LOG ("%03d: %s", (i / n) * n, line);
263 }
264 g_free (line);
265 }
267 GType
268 gst_dp_version_get_type (void)
269 {
270 static GType gst_dp_version_type = 0;
271 static const GEnumValue gst_dp_version[] = {
272 {GST_DP_VERSION_0_2, "GDP Version 0.2", "0.2"},
273 {GST_DP_VERSION_1_0, "GDP Version 1.0", "1.0"},
274 {0, NULL, NULL},
275 };
277 if (!gst_dp_version_type) {
278 gst_dp_version_type =
279 g_enum_register_static ("GstDPVersion", gst_dp_version);
280 }
281 return gst_dp_version_type;
282 };
284 /**
285 * gst_dp_init:
286 *
287 * Initialize GStreamer Data Protocol library.
288 *
289 * Should be called before using these functions from source linking
290 * to this source file.
291 */
292 void
293 gst_dp_init (void)
294 {
295 static gboolean _gst_dp_initialized = FALSE;
297 if (_gst_dp_initialized)
298 return;
300 _gst_dp_initialized = TRUE;
302 gst_dp_version_get_type ();
304 GST_DEBUG_CATEGORY_INIT (data_protocol_debug, "gdp", 0,
305 "GStreamer Data Protocol");
306 }
308 /**
309 * gst_dp_header_payload_length:
310 * @header: the byte header of the packet array
311 *
312 * Get the length of the payload described by @header.
313 *
314 * Returns: the length of the payload this header describes.
315 */
316 guint32
317 gst_dp_header_payload_length (const guint8 * header)
318 {
319 return GST_DP_HEADER_PAYLOAD_LENGTH (header);
320 }
322 /**
323 * gst_dp_header_payload_type:
324 * @header: the byte header of the packet array
325 *
326 * Get the type of the payload described by @header.
327 *
328 * Returns: the #GstDPPayloadType the payload this header describes.
329 */
330 GstDPPayloadType
331 gst_dp_header_payload_type (const guint8 * header)
332 {
333 return GST_DP_HEADER_PAYLOAD_TYPE (header);
334 }
336 /*** PACKETIZER FUNCTIONS ***/
338 /**
339 * gst_dp_header_from_buffer:
340 * @buffer: a #GstBuffer to create a header for
341 * @flags: the #GDPHeaderFlags to create the header with
342 * @length: a guint pointer to store the header length in
343 * @header: a guint8 * pointer to store a newly allocated header byte array in
344 *
345 * Creates a GDP header from the given buffer.
346 *
347 * Deprecated: use a #GstDPPacketizer
348 *
349 * Returns: %TRUE if the header was successfully created.
350 */
351 gboolean
352 gst_dp_header_from_buffer (const GstBuffer * buffer, GstDPHeaderFlag flags,
353 guint * length, guint8 ** header)
354 {
355 return gst_dp_header_from_buffer_any (buffer, flags, length, header,
356 GST_DP_VERSION_0_2);
357 }
359 static gboolean
360 gst_dp_header_from_buffer_1_0 (const GstBuffer * buffer, GstDPHeaderFlag flags,
361 guint * length, guint8 ** header)
362 {
363 return gst_dp_header_from_buffer_any (buffer, flags, length, header,
364 GST_DP_VERSION_1_0);
365 }
367 /**
368 * gst_dp_packet_from_caps:
369 * @caps: a #GstCaps to create a packet for
370 * @flags: the #GDPHeaderFlags to create the header with
371 * @length: a guint pointer to store the header length in
372 * @header: a guint8 pointer to store a newly allocated header byte array in
373 * @payload: a guint8 pointer to store a newly allocated payload byte array in
374 *
375 * Creates a GDP packet from the given caps.
376 *
377 * Deprecated: use a #GstDPPacketizer
378 *
379 * Returns: %TRUE if the packet was successfully created.
380 */
381 gboolean
382 gst_dp_packet_from_caps (const GstCaps * caps, GstDPHeaderFlag flags,
383 guint * length, guint8 ** header, guint8 ** payload)
384 {
385 return gst_dp_packet_from_caps_any (caps, flags, length, header, payload,
386 GST_DP_VERSION_0_2);
387 }
389 gboolean
390 gst_dp_packet_from_caps_1_0 (const GstCaps * caps, GstDPHeaderFlag flags,
391 guint * length, guint8 ** header, guint8 ** payload)
392 {
393 return gst_dp_packet_from_caps_any (caps, flags, length, header, payload,
394 GST_DP_VERSION_1_0);
395 }
397 /**
398 * gst_dp_packet_from_event:
399 * @event: a #GstEvent to create a packet for
400 * @flags: the #GDPHeaderFlags to create the header with
401 * @length: a guint pointer to store the header length in
402 * @header: a guint8 pointer to store a newly allocated header byte array in
403 * @payload: a guint8 pointer to store a newly allocated payload byte array in
404 *
405 * Creates a GDP packet from the given event.
406 *
407 * Deprecated: use a #GstDPPacketizer
408 *
409 * Returns: %TRUE if the packet was successfully created.
410 */
411 gboolean
412 gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
413 guint * length, guint8 ** header, guint8 ** payload)
414 {
415 guint8 *h;
416 guint pl_length; /* length of payload */
418 g_return_val_if_fail (event, FALSE);
419 g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
420 g_return_val_if_fail (header, FALSE);
421 g_return_val_if_fail (payload, FALSE);
423 *length = GST_DP_HEADER_LENGTH;
424 h = g_malloc0 (GST_DP_HEADER_LENGTH);
426 /* first construct payload, since we need the length */
427 switch (GST_EVENT_TYPE (event)) {
428 case GST_EVENT_UNKNOWN:
429 GST_WARNING ("Unknown event, ignoring");
430 *length = 0;
431 g_free (h);
432 return FALSE;
433 case GST_EVENT_EOS:
434 case GST_EVENT_FLUSH_START:
435 case GST_EVENT_FLUSH_STOP:
436 case GST_EVENT_NEWSEGMENT:
437 pl_length = 0;
438 *payload = NULL;
439 break;
440 case GST_EVENT_SEEK:
441 {
442 gdouble rate;
443 GstFormat format;
444 GstSeekFlags flags;
445 GstSeekType cur_type, stop_type;
446 gint64 cur, stop;
448 gst_event_parse_seek ((GstEvent *) event, &rate, &format, &flags,
449 &cur_type, &cur, &stop_type, &stop);
451 pl_length = 4 + 4 + 4 + 8 + 4 + 8;
452 *payload = g_malloc0 (pl_length);
453 /* FIXME write rate */
454 GST_WRITE_UINT32_BE (*payload, (guint32) format);
455 GST_WRITE_UINT32_BE (*payload + 4, (guint32) flags);
456 GST_WRITE_UINT32_BE (*payload + 8, (guint32) cur_type);
457 GST_WRITE_UINT64_BE (*payload + 12, (guint64) cur);
458 GST_WRITE_UINT32_BE (*payload + 20, (guint32) stop_type);
459 GST_WRITE_UINT64_BE (*payload + 24, (guint64) stop);
460 break;
461 }
462 case GST_EVENT_QOS:
463 case GST_EVENT_NAVIGATION:
464 case GST_EVENT_TAG:
465 GST_WARNING ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
466 *length = 0;
467 g_free (h);
468 return FALSE;
469 default:
470 GST_WARNING ("Unknown event type %d, ignoring", GST_EVENT_TYPE (event));
471 *length = 0;
472 g_free (h);
473 return FALSE;
474 }
476 /* version, flags, type */
477 GST_DP_INIT_HEADER (h, GST_DP_VERSION_0_2, flags,
478 GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
480 /* length */
481 GST_WRITE_UINT32_BE (h + 6, (guint32) pl_length);
482 /* timestamp */
483 GST_WRITE_UINT64_BE (h + 10, GST_EVENT_TIMESTAMP (event));
485 GST_DP_SET_CRC (h, flags, *payload, pl_length);
487 GST_LOG ("created header from event:");
488 gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
489 *header = h;
490 return TRUE;
491 }
493 static gboolean
494 gst_dp_packet_from_event_1_0 (const GstEvent * event, GstDPHeaderFlag flags,
495 guint * length, guint8 ** header, guint8 ** payload)
496 {
497 guint8 *h;
498 guint32 pl_length; /* length of payload */
499 guchar *string = NULL;
501 g_return_val_if_fail (event, FALSE);
502 g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
503 g_return_val_if_fail (header, FALSE);
504 g_return_val_if_fail (payload, FALSE);
506 *length = GST_DP_HEADER_LENGTH;
507 h = g_malloc0 (GST_DP_HEADER_LENGTH);
509 if (event->structure) {
510 string = (guchar *) gst_structure_to_string (event->structure);
511 GST_LOG ("event %p has structure, string %s", event, string);
512 pl_length = strlen ((gchar *) string) + 1; /* include trailing 0 */
513 } else {
514 GST_LOG ("event %p has no structure");
515 pl_length = 0;
516 }
518 /* version, flags, type */
519 GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags,
520 GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
522 /* length */
523 GST_WRITE_UINT32_BE (h + 6, pl_length);
524 /* timestamp */
525 GST_WRITE_UINT64_BE (h + 10, GST_EVENT_TIMESTAMP (event));
527 GST_DP_SET_CRC (h, flags, *payload, pl_length);
529 GST_LOG ("created header from event:");
530 gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
531 *header = h;
532 *payload = string;
533 return TRUE;
534 }
536 /*** DEPACKETIZING FUNCTIONS ***/
538 /**
539 * gst_dp_buffer_from_header:
540 * @header_length: the length of the packet header
541 * @header: the byte array of the packet header
542 *
543 * Creates a newly allocated #GstBuffer from the given header.
544 * The buffer data needs to be copied into it before validating.
545 *
546 * Use this function if you want to pre-allocate a buffer based on the
547 * packet header to read the packet payload in to.
548 *
549 * Returns: A #GstBuffer if the buffer was successfully created, or NULL.
550 */
551 GstBuffer *
552 gst_dp_buffer_from_header (guint header_length, const guint8 * header)
553 {
554 GstBuffer *buffer;
556 g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
557 GST_DP_PAYLOAD_BUFFER, NULL);
558 buffer =
559 gst_buffer_new_and_alloc ((guint) GST_DP_HEADER_PAYLOAD_LENGTH (header));
560 GST_BUFFER_TIMESTAMP (buffer) = GST_DP_HEADER_TIMESTAMP (header);
561 GST_BUFFER_DURATION (buffer) = GST_DP_HEADER_DURATION (header);
562 GST_BUFFER_OFFSET (buffer) = GST_DP_HEADER_OFFSET (header);
563 GST_BUFFER_OFFSET_END (buffer) = GST_DP_HEADER_OFFSET_END (header);
564 GST_BUFFER_FLAGS (buffer) = GST_DP_HEADER_BUFFER_FLAGS (header);
566 return buffer;
567 }
569 /**
570 * gst_dp_caps_from_packet:
571 * @header_length: the length of the packet header
572 * @header: the byte array of the packet header
573 * @payload: the byte array of the packet payload
574 *
575 * Creates a newly allocated #GstCaps from the given packet.
576 *
577 * Returns: A #GstCaps containing the caps represented in the packet,
578 * or NULL if the packet could not be converted.
579 */
580 GstCaps *
581 gst_dp_caps_from_packet (guint header_length, const guint8 * header,
582 const guint8 * payload)
583 {
584 GstCaps *caps;
585 gchar *string;
587 g_return_val_if_fail (header, NULL);
588 g_return_val_if_fail (payload, NULL);
589 g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
590 GST_DP_PAYLOAD_CAPS, NULL);
592 string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
593 caps = gst_caps_from_string (string);
594 g_free (string);
595 return caps;
596 }
598 static GstEvent *
599 gst_dp_event_from_packet_0_2 (guint header_length, const guint8 * header,
600 const guint8 * payload)
601 {
602 GstEvent *event = NULL;
603 GstEventType type;
605 type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
606 switch (type) {
607 case GST_EVENT_UNKNOWN:
608 GST_WARNING ("Unknown event, ignoring");
609 return FALSE;
610 case GST_EVENT_EOS:
611 case GST_EVENT_FLUSH_START:
612 case GST_EVENT_FLUSH_STOP:
613 case GST_EVENT_NEWSEGMENT:
614 event = gst_event_new_custom (type, NULL);
615 GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
616 break;
617 case GST_EVENT_SEEK:
618 {
619 gdouble rate;
620 GstFormat format;
621 GstSeekFlags flags;
622 GstSeekType cur_type, stop_type;
623 gint64 cur, stop;
625 /* FIXME, read rate */
626 rate = 1.0;
627 format = (GstFormat) GST_READ_UINT32_BE (payload);
628 flags = (GstSeekFlags) GST_READ_UINT32_BE (payload + 4);
629 cur_type = (GstSeekType) GST_READ_UINT32_BE (payload + 8);
630 cur = (gint64) GST_READ_UINT64_BE (payload + 12);
631 stop_type = (GstSeekType) GST_READ_UINT32_BE (payload + 20);
632 stop = (gint64) GST_READ_UINT64_BE (payload + 24);
634 event = gst_event_new_seek (rate, format, flags, cur_type, cur,
635 stop_type, stop);
636 GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
637 break;
638 }
639 case GST_EVENT_QOS:
640 case GST_EVENT_NAVIGATION:
641 case GST_EVENT_TAG:
642 GST_WARNING ("Unhandled event type %d, ignoring", type);
643 return FALSE;
644 default:
645 GST_WARNING ("Unknown event type %d, ignoring", type);
646 return FALSE;
647 }
649 return event;
650 }
652 static GstEvent *
653 gst_dp_event_from_packet_1_0 (guint header_length, const guint8 * header,
654 const guint8 * payload)
655 {
656 GstEvent *event = NULL;
657 GstEventType type;
658 gchar *string;
659 GstStructure *s;
661 type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
662 string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
663 s = gst_structure_from_string (string, NULL);
664 g_free (string);
665 if (!s)
666 return NULL;
667 event = gst_event_new_custom (type, s);
668 return event;
669 }
672 /**
673 * gst_dp_event_from_packet:
674 * @header_length: the length of the packet header
675 * @header: the byte array of the packet header
676 * @payload: the byte array of the packet payload
677 *
678 * Creates a newly allocated #GstEvent from the given packet.
679 *
680 * Returns: A #GstEvent if the event was successfully created,
681 * or NULL if an event could not be read from the payload.
682 */
683 GstEvent *
684 gst_dp_event_from_packet (guint header_length, const guint8 * header,
685 const guint8 * payload)
686 {
687 guint8 major, minor;
689 g_return_val_if_fail (header, NULL);
691 major = GST_DP_HEADER_MAJOR_VERSION (header);
692 minor = GST_DP_HEADER_MINOR_VERSION (header);
694 if (major == 0 && minor == 2)
695 return gst_dp_event_from_packet_0_2 (header_length, header, payload);
696 else if (major == 1 && minor == 0)
697 return gst_dp_event_from_packet_1_0 (header_length, header, payload);
698 else {
699 GST_ERROR ("Unknown GDP version %d.%d", major, minor);
700 return NULL;
701 }
702 }
704 /**
705 * gst_dp_validate_header:
706 * @header_length: the length of the packet header
707 * @header: the byte array of the packet header
708 *
709 * Validates the given packet header by checking the CRC checksum.
710 *
711 * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
712 */
713 gboolean
714 gst_dp_validate_header (guint header_length, const guint8 * header)
715 {
716 guint16 crc_read, crc_calculated;
718 if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_HEADER))
719 return TRUE;
720 crc_read = GST_DP_HEADER_CRC_HEADER (header);
721 /* don't include the last two crc fields for the crc check */
722 crc_calculated = gst_dp_crc (header, header_length - 4);
723 if (crc_read != crc_calculated) {
724 GST_WARNING ("header crc mismatch: read %02x, calculated %02x", crc_read,
725 crc_calculated);
726 return FALSE;
727 }
728 GST_LOG ("header crc validation: %02x", crc_read);
729 return TRUE;
730 }
732 /**
733 * gst_dp_validate_payload:
734 * @header_length: the length of the packet header
735 * @header: the byte array of the packet header
736 * @payload: the byte array of the packet payload
737 *
738 * Validates the given packet payload using the given packet header
739 * by checking the CRC checksum.
740 *
741 * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
742 */
743 gboolean
744 gst_dp_validate_payload (guint header_length, const guint8 * header,
745 const guint8 * payload)
746 {
747 guint16 crc_read, crc_calculated;
749 if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_PAYLOAD))
750 return TRUE;
751 crc_read = GST_DP_HEADER_CRC_PAYLOAD (header);
752 crc_calculated = gst_dp_crc (payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
753 if (crc_read != crc_calculated) {
754 GST_WARNING ("payload crc mismatch: read %02x, calculated %02x", crc_read,
755 crc_calculated);
756 return FALSE;
757 }
758 GST_LOG ("payload crc validation: %02x", crc_read);
759 return TRUE;
760 }
762 /**
763 * gst_dp_validate_packet:
764 * @header_length: the length of the packet header
765 * @header: the byte array of the packet header
766 * @payload: the byte array of the packet payload
767 *
768 * Validates the given packet by checking version information and checksums.
769 *
770 * Returns: %TRUE if the packet validates.
771 */
772 gboolean
773 gst_dp_validate_packet (guint header_length, const guint8 * header,
774 const guint8 * payload)
775 {
776 if (!gst_dp_validate_header (header_length, header))
777 return FALSE;
778 if (!gst_dp_validate_payload (header_length, header, payload))
779 return FALSE;
781 return TRUE;
782 }
784 /**
785 * gst_dp_packetizer_new:
786 * @version: the #GstDPVersion of the protocol to packetize for.
787 *
788 * Creates a new packetizer.
789 *
790 * Returns: a newly allocated #GstDPPacketizer
791 */
792 GstDPPacketizer *
793 gst_dp_packetizer_new (GstDPVersion version)
794 {
795 GstDPPacketizer *ret;
797 ret = g_malloc0 (sizeof (GstDPPacketizer));
798 ret->version = version;
800 switch (version) {
801 case GST_DP_VERSION_0_2:
802 ret->header_from_buffer = gst_dp_header_from_buffer;
803 ret->packet_from_caps = gst_dp_packet_from_caps;
804 ret->packet_from_event = gst_dp_packet_from_event;
805 break;
806 case GST_DP_VERSION_1_0:
807 ret->header_from_buffer = gst_dp_header_from_buffer_1_0;
808 ret->packet_from_caps = gst_dp_packet_from_caps_1_0;
809 ret->packet_from_event = gst_dp_packet_from_event_1_0;
810 break;
811 default:
812 g_free (ret);
813 ret = NULL;
814 break;
815 }
817 return ret;
818 }
820 /**
821 * gst_dp_packetizer_free:
822 * @packetizer: the #GstDPPacketizer to free.
823 *
824 * Free the given packetizer.
825 */
826 void
827 gst_dp_packetizer_free (GstDPPacketizer * packetizer)
828 {
829 g_free (packetizer);
830 }