docs/: add a gdp image
[platform/upstream/gstreamer.git] / libs / gst / dataprotocol / dataprotocol.c
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  */
22
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  *
64  * For reference, this image shows the byte layout of the GDP header:
65  *
66  * <inlinegraphic format="PNG" fileref="gdp-header.png"></inlinegraphic>
67  */
68
69 #ifdef HAVE_CONFIG_H
70 #include "config.h"
71 #endif
72
73 #include <gst/gst.h>
74 #include <gst/dataprotocol/dataprotocol.h>
75 #include <glib/gprintf.h>       /* g_sprintf */
76 #include <string.h>             /* strlen */
77 #include "dp-private.h"
78
79 /* debug category */
80 GST_DEBUG_CATEGORY (data_protocol_debug);
81 #define GST_CAT_DEFAULT data_protocol_debug
82
83 /* helper macros */
84
85 /* write first 6 bytes of header, as well as ABI padding */
86 #define GST_DP_INIT_HEADER(h, version, flags, type)             \
87 G_STMT_START {                                                  \
88   gint maj = 0, min = 0;                                        \
89   switch (version) {                                            \
90     case GST_DP_VERSION_0_2: maj = 0; min = 2; break;           \
91     case GST_DP_VERSION_1_0: maj = 1; min = 0; break;           \
92   }                                                             \
93   h[0] = (guint8) maj;                                          \
94   h[1] = (guint8) min;                                          \
95   h[2] = (guint8) flags;                                        \
96   h[3] = 0; /* padding byte */                                  \
97   GST_WRITE_UINT16_BE (h + 4, type);                            \
98                                                                 \
99   GST_WRITE_UINT64_BE (h + 42, (guint64) 0); /* ABI padding */  \
100   GST_WRITE_UINT64_BE (h + 50, (guint64) 0); /* ABI padding */  \
101 } G_STMT_END
102
103 #define GST_DP_SET_CRC(h, flags, payload, length);              \
104 G_STMT_START {                                                  \
105   guint16 crc = 0;                                              \
106   if (flags & GST_DP_HEADER_FLAG_CRC_HEADER)                    \
107     /* we don't crc the last four bytes since they are crc's */ \
108     crc = gst_dp_crc (h, 58);                                   \
109   GST_WRITE_UINT16_BE (h + 58, crc);                            \
110                                                                 \
111   crc = 0;                                                      \
112   if (length && (flags & GST_DP_HEADER_FLAG_CRC_PAYLOAD))       \
113     crc = gst_dp_crc (payload, length);                         \
114   GST_WRITE_UINT16_BE (h + 60, crc);                            \
115 } G_STMT_END
116
117 /* calculate a CCITT 16 bit CRC check value for a given byte array */
118 /*
119  * this code snippet is adapted from a web page I found
120  * it is identical except for cleanups, and a final XOR with 0xffff
121  * as outlined in the uecp spec
122  *
123  * XMODEM    x^16 + x^12 + x^5 + 1
124  */
125
126 #define POLY       0x1021
127 #define CRC_INIT   0xFFFF
128
129 /*** HELPER FUNCTIONS ***/
130
131 static gboolean
132 gst_dp_header_from_buffer_any (const GstBuffer * buffer, GstDPHeaderFlag flags,
133     guint * length, guint8 ** header, GstDPVersion version)
134 {
135   guint8 *h;
136   guint16 flags_mask;
137
138   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
139   g_return_val_if_fail (header, FALSE);
140
141   *length = GST_DP_HEADER_LENGTH;
142   h = g_malloc0 (GST_DP_HEADER_LENGTH);
143
144   /* version, flags, type */
145   GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_BUFFER);
146
147   /* buffer properties */
148   GST_WRITE_UINT32_BE (h + 6, GST_BUFFER_SIZE (buffer));
149   GST_WRITE_UINT64_BE (h + 10, GST_BUFFER_TIMESTAMP (buffer));
150   GST_WRITE_UINT64_BE (h + 18, GST_BUFFER_DURATION (buffer));
151   GST_WRITE_UINT64_BE (h + 26, GST_BUFFER_OFFSET (buffer));
152   GST_WRITE_UINT64_BE (h + 34, GST_BUFFER_OFFSET_END (buffer));
153
154   /* data flags; eats two bytes from the ABI area */
155   /* we copy everything but the read-only flags */
156   flags_mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_DISCONT |
157       GST_BUFFER_FLAG_IN_CAPS | GST_BUFFER_FLAG_GAP |
158       GST_BUFFER_FLAG_DELTA_UNIT;
159
160   GST_WRITE_UINT16_BE (h + 42, GST_BUFFER_FLAGS (buffer) & flags_mask);
161
162   GST_DP_SET_CRC (h, flags, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
163
164   GST_LOG ("created header from buffer:");
165   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
166   *header = h;
167   return TRUE;
168 }
169
170 static gboolean
171 gst_dp_packet_from_caps_any (const GstCaps * caps, GstDPHeaderFlag flags,
172     guint * length, guint8 ** header, guint8 ** payload, GstDPVersion version)
173 {
174   guint8 *h;
175   guchar *string;
176   guint payload_length;
177
178   /* FIXME: GST_IS_CAPS doesn't work
179      g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); */
180   g_return_val_if_fail (caps, FALSE);
181   g_return_val_if_fail (header, FALSE);
182   g_return_val_if_fail (payload, FALSE);
183
184   *length = GST_DP_HEADER_LENGTH;
185   h = g_malloc0 (GST_DP_HEADER_LENGTH);
186
187   string = (guchar *) gst_caps_to_string (caps);
188   payload_length = strlen ((gchar *) string) + 1;       /* include trailing 0 */
189
190   /* version, flags, type */
191   GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_CAPS);
192
193   /* buffer properties */
194   GST_WRITE_UINT32_BE (h + 6, payload_length);
195   GST_WRITE_UINT64_BE (h + 10, (guint64) 0);
196   GST_WRITE_UINT64_BE (h + 18, (guint64) 0);
197   GST_WRITE_UINT64_BE (h + 26, (guint64) 0);
198   GST_WRITE_UINT64_BE (h + 34, (guint64) 0);
199
200   GST_DP_SET_CRC (h, flags, string, payload_length);
201
202   GST_LOG ("created header from caps:");
203   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
204   *header = h;
205   *payload = string;
206   return TRUE;
207 }
208
209
210 /*** PUBLIC FUNCTIONS ***/
211
212 /**
213  * gst_dp_crc:
214  *
215  * Calculate a CRC for the given buffer over the given number of bytes.
216  * This is only provided for verification purposes; typical GDP users
217  * will not need this function.
218  *
219  * Returns: a two-byte CRC checksum.
220  */
221 guint16
222 gst_dp_crc (const guint8 * buffer, guint length)
223 {
224   static gboolean initialized = FALSE;
225   static guint16 crc_table[256];
226   guint16 crc_register = CRC_INIT;
227   unsigned long i, j, k;
228
229   if (!initialized) {
230     for (i = 0; i < 256; i++) {
231       j = i << 8;
232       for (k = 8; k--;) {
233         j = j & 0x8000 ? (j << 1) ^ POLY : j << 1;
234       }
235
236       crc_table[i] = (guint16) j;
237     }
238     initialized = TRUE;
239   }
240
241   /* calc CRC */
242   for (; length--;) {
243     crc_register = (guint16) ((crc_register << 8) ^
244         crc_table[((crc_register >> 8) & 0x00ff) ^ *buffer++]);
245   }
246   return (0xffff ^ crc_register);
247 }
248
249 /* debugging function; dumps byte array values per 8 bytes */
250 /* FIXME: would be nice to merge this with gst_util_dump_mem () */
251 void
252 gst_dp_dump_byte_array (guint8 * array, guint length)
253 {
254   int i;
255   int n = 8;                    /* number of bytes per line */
256   gchar *line = g_malloc0 (3 * n + 1);
257
258   GST_LOG ("dumping byte array of length %d", length);
259   for (i = 0; i < length; ++i) {
260     g_sprintf (line + 3 * (i % n), "%02x ", array[i]);
261     if (i % n == (n - 1)) {
262       GST_LOG ("%03d: %s", i - (n - 1), line);
263     }
264   }
265   if (i % n != 0) {
266     GST_LOG ("%03d: %s", (i / n) * n, line);
267   }
268   g_free (line);
269 }
270
271 GType
272 gst_dp_version_get_type (void)
273 {
274   static GType gst_dp_version_type = 0;
275   static const GEnumValue gst_dp_version[] = {
276     {GST_DP_VERSION_0_2, "GDP Version 0.2", "0.2"},
277     {GST_DP_VERSION_1_0, "GDP Version 1.0", "1.0"},
278     {0, NULL, NULL},
279   };
280
281   if (!gst_dp_version_type) {
282     gst_dp_version_type =
283         g_enum_register_static ("GstDPVersion", gst_dp_version);
284   }
285   return gst_dp_version_type;
286 };
287
288 /**
289  * gst_dp_init:
290  *
291  * Initialize GStreamer Data Protocol library.
292  *
293  * Should be called before using these functions from source linking
294  * to this source file.
295  */
296 void
297 gst_dp_init (void)
298 {
299   static gboolean _gst_dp_initialized = FALSE;
300
301   if (_gst_dp_initialized)
302     return;
303
304   _gst_dp_initialized = TRUE;
305
306   gst_dp_version_get_type ();
307
308   GST_DEBUG_CATEGORY_INIT (data_protocol_debug, "gdp", 0,
309       "GStreamer Data Protocol");
310 }
311
312 /**
313  * gst_dp_header_payload_length:
314  * @header: the byte header of the packet array
315  *
316  * Get the length of the payload described by @header.
317  *
318  * Returns: the length of the payload this header describes.
319  */
320 guint32
321 gst_dp_header_payload_length (const guint8 * header)
322 {
323   return GST_DP_HEADER_PAYLOAD_LENGTH (header);
324 }
325
326 /**
327  * gst_dp_header_payload_type:
328  * @header: the byte header of the packet array
329  *
330  * Get the type of the payload described by @header.
331  *
332  * Returns: the #GstDPPayloadType the payload this header describes.
333  */
334 GstDPPayloadType
335 gst_dp_header_payload_type (const guint8 * header)
336 {
337   return GST_DP_HEADER_PAYLOAD_TYPE (header);
338 }
339
340 /*** PACKETIZER FUNCTIONS ***/
341
342 /**
343  * gst_dp_header_from_buffer:
344  * @buffer: a #GstBuffer to create a header for
345  * @flags: the #GDPHeaderFlags to create the header with
346  * @length: a guint pointer to store the header length in
347  * @header: a guint8 * pointer to store a newly allocated header byte array in
348  *
349  * Creates a GDP header from the given buffer.
350  *
351  * Deprecated: use a #GstDPPacketizer
352  *
353  * Returns: %TRUE if the header was successfully created.
354  */
355 gboolean
356 gst_dp_header_from_buffer (const GstBuffer * buffer, GstDPHeaderFlag flags,
357     guint * length, guint8 ** header)
358 {
359   return gst_dp_header_from_buffer_any (buffer, flags, length, header,
360       GST_DP_VERSION_0_2);
361 }
362
363 static gboolean
364 gst_dp_header_from_buffer_1_0 (const GstBuffer * buffer, GstDPHeaderFlag flags,
365     guint * length, guint8 ** header)
366 {
367   return gst_dp_header_from_buffer_any (buffer, flags, length, header,
368       GST_DP_VERSION_1_0);
369 }
370
371  /**
372  * gst_dp_packet_from_caps:
373  * @caps: a #GstCaps to create a packet for
374  * @flags: the #GDPHeaderFlags to create the header with
375  * @length: a guint pointer to store the header length in
376  * @header: a guint8 pointer to store a newly allocated header byte array in
377  * @payload: a guint8 pointer to store a newly allocated payload byte array in
378  *
379  * Creates a GDP packet from the given caps.
380  *
381  * Deprecated: use a #GstDPPacketizer
382  *
383  * Returns: %TRUE if the packet was successfully created.
384  */
385 gboolean
386 gst_dp_packet_from_caps (const GstCaps * caps, GstDPHeaderFlag flags,
387     guint * length, guint8 ** header, guint8 ** payload)
388 {
389   return gst_dp_packet_from_caps_any (caps, flags, length, header, payload,
390       GST_DP_VERSION_0_2);
391 }
392
393 gboolean
394 gst_dp_packet_from_caps_1_0 (const GstCaps * caps, GstDPHeaderFlag flags,
395     guint * length, guint8 ** header, guint8 ** payload)
396 {
397   return gst_dp_packet_from_caps_any (caps, flags, length, header, payload,
398       GST_DP_VERSION_1_0);
399 }
400
401 /**
402  * gst_dp_packet_from_event:
403  * @event: a #GstEvent to create a packet for
404  * @flags: the #GDPHeaderFlags to create the header with
405  * @length: a guint pointer to store the header length in
406  * @header: a guint8 pointer to store a newly allocated header byte array in
407  * @payload: a guint8 pointer to store a newly allocated payload byte array in
408  *
409  * Creates a GDP packet from the given event.
410  *
411  * Deprecated: use a #GstDPPacketizer
412  *
413  * Returns: %TRUE if the packet was successfully created.
414  */
415 gboolean
416 gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
417     guint * length, guint8 ** header, guint8 ** payload)
418 {
419   guint8 *h;
420   guint pl_length;              /* length of payload */
421
422   g_return_val_if_fail (event, FALSE);
423   g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
424   g_return_val_if_fail (header, FALSE);
425   g_return_val_if_fail (payload, FALSE);
426
427   *length = GST_DP_HEADER_LENGTH;
428   h = g_malloc0 (GST_DP_HEADER_LENGTH);
429
430   /* first construct payload, since we need the length */
431   switch (GST_EVENT_TYPE (event)) {
432     case GST_EVENT_UNKNOWN:
433       GST_WARNING ("Unknown event, ignoring");
434       *length = 0;
435       g_free (h);
436       return FALSE;
437     case GST_EVENT_EOS:
438     case GST_EVENT_FLUSH_START:
439     case GST_EVENT_FLUSH_STOP:
440     case GST_EVENT_NEWSEGMENT:
441       pl_length = 0;
442       *payload = NULL;
443       break;
444     case GST_EVENT_SEEK:
445     {
446       gdouble rate;
447       GstFormat format;
448       GstSeekFlags flags;
449       GstSeekType cur_type, stop_type;
450       gint64 cur, stop;
451
452       gst_event_parse_seek ((GstEvent *) event, &rate, &format, &flags,
453           &cur_type, &cur, &stop_type, &stop);
454
455       pl_length = 4 + 4 + 4 + 8 + 4 + 8;
456       *payload = g_malloc0 (pl_length);
457       /* FIXME write rate */
458       GST_WRITE_UINT32_BE (*payload, (guint32) format);
459       GST_WRITE_UINT32_BE (*payload + 4, (guint32) flags);
460       GST_WRITE_UINT32_BE (*payload + 8, (guint32) cur_type);
461       GST_WRITE_UINT64_BE (*payload + 12, (guint64) cur);
462       GST_WRITE_UINT32_BE (*payload + 20, (guint32) stop_type);
463       GST_WRITE_UINT64_BE (*payload + 24, (guint64) stop);
464       break;
465     }
466     case GST_EVENT_QOS:
467     case GST_EVENT_NAVIGATION:
468     case GST_EVENT_TAG:
469       GST_WARNING ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
470       *length = 0;
471       g_free (h);
472       return FALSE;
473     default:
474       GST_WARNING ("Unknown event type %d, ignoring", GST_EVENT_TYPE (event));
475       *length = 0;
476       g_free (h);
477       return FALSE;
478   }
479
480   /* version, flags, type */
481   GST_DP_INIT_HEADER (h, GST_DP_VERSION_0_2, flags,
482       GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
483
484   /* length */
485   GST_WRITE_UINT32_BE (h + 6, (guint32) pl_length);
486   /* timestamp */
487   GST_WRITE_UINT64_BE (h + 10, GST_EVENT_TIMESTAMP (event));
488
489   GST_DP_SET_CRC (h, flags, *payload, pl_length);
490
491   GST_LOG ("created header from event:");
492   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
493   *header = h;
494   return TRUE;
495 }
496
497 static gboolean
498 gst_dp_packet_from_event_1_0 (const GstEvent * event, GstDPHeaderFlag flags,
499     guint * length, guint8 ** header, guint8 ** payload)
500 {
501   guint8 *h;
502   guint32 pl_length;            /* length of payload */
503   guchar *string = NULL;
504
505   g_return_val_if_fail (event, FALSE);
506   g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
507   g_return_val_if_fail (header, FALSE);
508   g_return_val_if_fail (payload, FALSE);
509
510   *length = GST_DP_HEADER_LENGTH;
511   h = g_malloc0 (GST_DP_HEADER_LENGTH);
512
513   if (event->structure) {
514     string = (guchar *) gst_structure_to_string (event->structure);
515     GST_LOG ("event %p has structure, string %s", event, string);
516     pl_length = strlen ((gchar *) string) + 1;  /* include trailing 0 */
517   } else {
518     GST_LOG ("event %p has no structure");
519     pl_length = 0;
520   }
521
522   /* version, flags, type */
523   GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags,
524       GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
525
526   /* length */
527   GST_WRITE_UINT32_BE (h + 6, pl_length);
528   /* timestamp */
529   GST_WRITE_UINT64_BE (h + 10, GST_EVENT_TIMESTAMP (event));
530
531   GST_DP_SET_CRC (h, flags, *payload, pl_length);
532
533   GST_LOG ("created header from event:");
534   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
535   *header = h;
536   *payload = string;
537   return TRUE;
538 }
539
540 /*** DEPACKETIZING FUNCTIONS ***/
541
542 /**
543  * gst_dp_buffer_from_header:
544  * @header_length: the length of the packet header
545  * @header: the byte array of the packet header
546  *
547  * Creates a newly allocated #GstBuffer from the given header.
548  * The buffer data needs to be copied into it before validating.
549  *
550  * Use this function if you want to pre-allocate a buffer based on the
551  * packet header to read the packet payload in to.
552  *
553  * Returns: A #GstBuffer if the buffer was successfully created, or NULL.
554  */
555 GstBuffer *
556 gst_dp_buffer_from_header (guint header_length, const guint8 * header)
557 {
558   GstBuffer *buffer;
559
560   g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
561       GST_DP_PAYLOAD_BUFFER, NULL);
562   buffer =
563       gst_buffer_new_and_alloc ((guint) GST_DP_HEADER_PAYLOAD_LENGTH (header));
564   GST_BUFFER_TIMESTAMP (buffer) = GST_DP_HEADER_TIMESTAMP (header);
565   GST_BUFFER_DURATION (buffer) = GST_DP_HEADER_DURATION (header);
566   GST_BUFFER_OFFSET (buffer) = GST_DP_HEADER_OFFSET (header);
567   GST_BUFFER_OFFSET_END (buffer) = GST_DP_HEADER_OFFSET_END (header);
568   GST_BUFFER_FLAGS (buffer) = GST_DP_HEADER_BUFFER_FLAGS (header);
569
570   return buffer;
571 }
572
573 /**
574  * gst_dp_caps_from_packet:
575  * @header_length: the length of the packet header
576  * @header: the byte array of the packet header
577  * @payload: the byte array of the packet payload
578  *
579  * Creates a newly allocated #GstCaps from the given packet.
580  *
581  * Returns: A #GstCaps containing the caps represented in the packet,
582  *          or NULL if the packet could not be converted.
583  */
584 GstCaps *
585 gst_dp_caps_from_packet (guint header_length, const guint8 * header,
586     const guint8 * payload)
587 {
588   GstCaps *caps;
589   gchar *string;
590
591   g_return_val_if_fail (header, NULL);
592   g_return_val_if_fail (payload, NULL);
593   g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
594       GST_DP_PAYLOAD_CAPS, NULL);
595
596   string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
597   caps = gst_caps_from_string (string);
598   g_free (string);
599   return caps;
600 }
601
602 static GstEvent *
603 gst_dp_event_from_packet_0_2 (guint header_length, const guint8 * header,
604     const guint8 * payload)
605 {
606   GstEvent *event = NULL;
607   GstEventType type;
608
609   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
610   switch (type) {
611     case GST_EVENT_UNKNOWN:
612       GST_WARNING ("Unknown event, ignoring");
613       return FALSE;
614     case GST_EVENT_EOS:
615     case GST_EVENT_FLUSH_START:
616     case GST_EVENT_FLUSH_STOP:
617     case GST_EVENT_NEWSEGMENT:
618       event = gst_event_new_custom (type, NULL);
619       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
620       break;
621     case GST_EVENT_SEEK:
622     {
623       gdouble rate;
624       GstFormat format;
625       GstSeekFlags flags;
626       GstSeekType cur_type, stop_type;
627       gint64 cur, stop;
628
629       /* FIXME, read rate */
630       rate = 1.0;
631       format = (GstFormat) GST_READ_UINT32_BE (payload);
632       flags = (GstSeekFlags) GST_READ_UINT32_BE (payload + 4);
633       cur_type = (GstSeekType) GST_READ_UINT32_BE (payload + 8);
634       cur = (gint64) GST_READ_UINT64_BE (payload + 12);
635       stop_type = (GstSeekType) GST_READ_UINT32_BE (payload + 20);
636       stop = (gint64) GST_READ_UINT64_BE (payload + 24);
637
638       event = gst_event_new_seek (rate, format, flags, cur_type, cur,
639           stop_type, stop);
640       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
641       break;
642     }
643     case GST_EVENT_QOS:
644     case GST_EVENT_NAVIGATION:
645     case GST_EVENT_TAG:
646       GST_WARNING ("Unhandled event type %d, ignoring", type);
647       return FALSE;
648     default:
649       GST_WARNING ("Unknown event type %d, ignoring", type);
650       return FALSE;
651   }
652
653   return event;
654 }
655
656 static GstEvent *
657 gst_dp_event_from_packet_1_0 (guint header_length, const guint8 * header,
658     const guint8 * payload)
659 {
660   GstEvent *event = NULL;
661   GstEventType type;
662   gchar *string;
663   GstStructure *s;
664
665   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
666   string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
667   s = gst_structure_from_string (string, NULL);
668   g_free (string);
669   if (!s)
670     return NULL;
671   event = gst_event_new_custom (type, s);
672   return event;
673 }
674
675
676 /**
677  * gst_dp_event_from_packet:
678  * @header_length: the length of the packet header
679  * @header: the byte array of the packet header
680  * @payload: the byte array of the packet payload
681  *
682  * Creates a newly allocated #GstEvent from the given packet.
683  *
684  * Returns: A #GstEvent if the event was successfully created,
685  *          or NULL if an event could not be read from the payload.
686  */
687 GstEvent *
688 gst_dp_event_from_packet (guint header_length, const guint8 * header,
689     const guint8 * payload)
690 {
691   guint8 major, minor;
692
693   g_return_val_if_fail (header, NULL);
694
695   major = GST_DP_HEADER_MAJOR_VERSION (header);
696   minor = GST_DP_HEADER_MINOR_VERSION (header);
697
698   if (major == 0 && minor == 2)
699     return gst_dp_event_from_packet_0_2 (header_length, header, payload);
700   else if (major == 1 && minor == 0)
701     return gst_dp_event_from_packet_1_0 (header_length, header, payload);
702   else {
703     GST_ERROR ("Unknown GDP version %d.%d", major, minor);
704     return NULL;
705   }
706 }
707
708 /**
709  * gst_dp_validate_header:
710  * @header_length: the length of the packet header
711  * @header: the byte array of the packet header
712  *
713  * Validates the given packet header by checking the CRC checksum.
714  *
715  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
716  */
717 gboolean
718 gst_dp_validate_header (guint header_length, const guint8 * header)
719 {
720   guint16 crc_read, crc_calculated;
721
722   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_HEADER))
723     return TRUE;
724   crc_read = GST_DP_HEADER_CRC_HEADER (header);
725   /* don't include the last two crc fields for the crc check */
726   crc_calculated = gst_dp_crc (header, header_length - 4);
727   if (crc_read != crc_calculated) {
728     GST_WARNING ("header crc mismatch: read %02x, calculated %02x", crc_read,
729         crc_calculated);
730     return FALSE;
731   }
732   GST_LOG ("header crc validation: %02x", crc_read);
733   return TRUE;
734 }
735
736 /**
737  * gst_dp_validate_payload:
738  * @header_length: the length of the packet header
739  * @header: the byte array of the packet header
740  * @payload: the byte array of the packet payload
741  *
742  * Validates the given packet payload using the given packet header
743  * by checking the CRC checksum.
744  *
745  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
746  */
747 gboolean
748 gst_dp_validate_payload (guint header_length, const guint8 * header,
749     const guint8 * payload)
750 {
751   guint16 crc_read, crc_calculated;
752
753   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_PAYLOAD))
754     return TRUE;
755   crc_read = GST_DP_HEADER_CRC_PAYLOAD (header);
756   crc_calculated = gst_dp_crc (payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
757   if (crc_read != crc_calculated) {
758     GST_WARNING ("payload crc mismatch: read %02x, calculated %02x", crc_read,
759         crc_calculated);
760     return FALSE;
761   }
762   GST_LOG ("payload crc validation: %02x", crc_read);
763   return TRUE;
764 }
765
766 /**
767  * gst_dp_validate_packet:
768  * @header_length: the length of the packet header
769  * @header: the byte array of the packet header
770  * @payload: the byte array of the packet payload
771  *
772  * Validates the given packet by checking version information and checksums.
773  *
774  * Returns: %TRUE if the packet validates.
775  */
776 gboolean
777 gst_dp_validate_packet (guint header_length, const guint8 * header,
778     const guint8 * payload)
779 {
780   if (!gst_dp_validate_header (header_length, header))
781     return FALSE;
782   if (!gst_dp_validate_payload (header_length, header, payload))
783     return FALSE;
784
785   return TRUE;
786 }
787
788 /**
789  * gst_dp_packetizer_new:
790  * @version: the #GstDPVersion of the protocol to packetize for.
791  *
792  * Creates a new packetizer.
793  *
794  * Returns: a newly allocated #GstDPPacketizer
795  */
796 GstDPPacketizer *
797 gst_dp_packetizer_new (GstDPVersion version)
798 {
799   GstDPPacketizer *ret;
800
801   ret = g_malloc0 (sizeof (GstDPPacketizer));
802   ret->version = version;
803
804   switch (version) {
805     case GST_DP_VERSION_0_2:
806       ret->header_from_buffer = gst_dp_header_from_buffer;
807       ret->packet_from_caps = gst_dp_packet_from_caps;
808       ret->packet_from_event = gst_dp_packet_from_event;
809       break;
810     case GST_DP_VERSION_1_0:
811       ret->header_from_buffer = gst_dp_header_from_buffer_1_0;
812       ret->packet_from_caps = gst_dp_packet_from_caps_1_0;
813       ret->packet_from_event = gst_dp_packet_from_event_1_0;
814       break;
815     default:
816       g_free (ret);
817       ret = NULL;
818       break;
819   }
820
821   return ret;
822 }
823
824 /**
825  * gst_dp_packetizer_free:
826  * @packetizer: the #GstDPPacketizer to free.
827  *
828  * Free the given packetizer.
829  */
830 void
831 gst_dp_packetizer_free (GstDPPacketizer * packetizer)
832 {
833   g_free (packetizer);
834 }