gdp: remove deprecated code
[platform/upstream/gstreamer.git] / gst / gdp / 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_STATIC (data_protocol_debug);
81 #define GST_CAT_DEFAULT data_protocol_debug
82
83 /* helper macros */
84
85 /* write first 6 bytes of header */
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 } G_STMT_END
99
100 #define GST_DP_SET_CRC(h, flags, payload, length);              \
101 G_STMT_START {                                                  \
102   guint16 crc = 0;                                              \
103   if (flags & GST_DP_HEADER_FLAG_CRC_HEADER)                    \
104     /* we don't crc the last four bytes since they are crc's */ \
105     crc = gst_dp_crc (h, 58);                                   \
106   GST_WRITE_UINT16_BE (h + 58, crc);                            \
107                                                                 \
108   crc = 0;                                                      \
109   if (length && (flags & GST_DP_HEADER_FLAG_CRC_PAYLOAD))       \
110     crc = gst_dp_crc (payload, length);                         \
111   GST_WRITE_UINT16_BE (h + 60, crc);                            \
112 } G_STMT_END
113
114 /* calculate a CCITT 16 bit CRC check value for a given byte array */
115 /*
116  * this code snippet is adapted from a web page I found
117  * it is identical except for cleanups, and a final XOR with 0xffff
118  * as outlined in the uecp spec
119  *
120  * XMODEM    x^16 + x^12 + x^5 + 1
121  */
122
123 #define POLY       0x1021
124 #define CRC_INIT   0xFFFF
125
126 /*** HELPER FUNCTIONS ***/
127
128 static gboolean
129 gst_dp_header_from_buffer_any (const GstBuffer * buffer, GstDPHeaderFlag flags,
130     guint * length, guint8 ** header, GstDPVersion version)
131 {
132   guint8 *h;
133   guint16 flags_mask;
134
135   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
136   g_return_val_if_fail (length, FALSE);
137   g_return_val_if_fail (header, FALSE);
138
139   *length = GST_DP_HEADER_LENGTH;
140   h = g_malloc0 (GST_DP_HEADER_LENGTH);
141
142   /* version, flags, type */
143   GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_BUFFER);
144
145   /* buffer properties */
146   GST_WRITE_UINT32_BE (h + 6, GST_BUFFER_SIZE (buffer));
147   GST_WRITE_UINT64_BE (h + 10, GST_BUFFER_TIMESTAMP (buffer));
148   GST_WRITE_UINT64_BE (h + 18, GST_BUFFER_DURATION (buffer));
149   GST_WRITE_UINT64_BE (h + 26, GST_BUFFER_OFFSET (buffer));
150   GST_WRITE_UINT64_BE (h + 34, GST_BUFFER_OFFSET_END (buffer));
151
152   /* data flags; eats two bytes from the ABI area */
153   /* we copy everything but the read-only flags */
154   flags_mask = GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_DISCONT |
155       GST_BUFFER_FLAG_IN_CAPS | GST_BUFFER_FLAG_GAP |
156       GST_BUFFER_FLAG_DELTA_UNIT;
157
158   GST_WRITE_UINT16_BE (h + 42, GST_BUFFER_FLAGS (buffer) & flags_mask);
159
160   GST_DP_SET_CRC (h, flags, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
161
162   GST_LOG ("created header from buffer:");
163   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
164   *header = h;
165   return TRUE;
166 }
167
168 static gboolean
169 gst_dp_packet_from_caps_any (const GstCaps * caps, GstDPHeaderFlag flags,
170     guint * length, guint8 ** header, guint8 ** payload, GstDPVersion version)
171 {
172   guint8 *h;
173   guchar *string;
174   guint payload_length;
175
176   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
177   g_return_val_if_fail (length, FALSE);
178   g_return_val_if_fail (header, FALSE);
179   g_return_val_if_fail (payload, FALSE);
180
181   *length = GST_DP_HEADER_LENGTH;
182   h = g_malloc0 (GST_DP_HEADER_LENGTH);
183
184   string = (guchar *) gst_caps_to_string (caps);
185   payload_length = strlen ((gchar *) string) + 1;       /* include trailing 0 */
186
187   /* version, flags, type */
188   GST_DP_INIT_HEADER (h, version, flags, GST_DP_PAYLOAD_CAPS);
189
190   /* buffer properties */
191   GST_WRITE_UINT32_BE (h + 6, payload_length);
192   GST_WRITE_UINT64_BE (h + 10, (guint64) 0);
193   GST_WRITE_UINT64_BE (h + 18, (guint64) 0);
194   GST_WRITE_UINT64_BE (h + 26, (guint64) 0);
195   GST_WRITE_UINT64_BE (h + 34, (guint64) 0);
196
197   GST_DP_SET_CRC (h, flags, string, payload_length);
198
199   GST_LOG ("created header from caps:");
200   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
201   *header = h;
202   *payload = string;
203   return TRUE;
204 }
205
206
207 /*** PUBLIC FUNCTIONS ***/
208
209 static const guint16 gst_dp_crc_table[256] = {
210   0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
211   0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
212   0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
213   0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
214   0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
215   0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
216   0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
217   0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
218   0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
219   0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
220   0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
221   0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
222   0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
223   0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
224   0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
225   0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
226   0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
227   0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
228   0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
229   0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
230   0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
231   0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
232   0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
233   0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
234   0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
235   0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
236   0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
237   0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
238   0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
239   0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
240   0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
241   0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
242 };
243
244 /**
245  * gst_dp_crc:
246  * @buffer: array of bytes
247  * @length: the length of @buffer
248  *
249  * Calculate a CRC for the given buffer over the given number of bytes.
250  * This is only provided for verification purposes; typical GDP users
251  * will not need this function.
252  *
253  * Returns: a two-byte CRC checksum.
254  */
255 guint16
256 gst_dp_crc (const guint8 * buffer, guint length)
257 {
258   guint16 crc_register = CRC_INIT;
259
260   g_return_val_if_fail (buffer != NULL || length == 0, 0);
261
262   /* calc CRC */
263   for (; length--;) {
264     crc_register = (guint16) ((crc_register << 8) ^
265         gst_dp_crc_table[((crc_register >> 8) & 0x00ff) ^ *buffer++]);
266   }
267   return (0xffff ^ crc_register);
268 }
269
270 /* debugging function; dumps byte array values per 8 bytes */
271 /* FIXME: would be nice to merge this with gst_util_dump_mem () */
272 void
273 gst_dp_dump_byte_array (guint8 * array, guint length)
274 {
275   int i;
276   int n = 8;                    /* number of bytes per line */
277   gchar *line = g_malloc0 (3 * n + 1);
278
279   GST_LOG ("dumping byte array of length %d", length);
280   for (i = 0; i < length; ++i) {
281     g_sprintf (line + 3 * (i % n), "%02x ", array[i]);
282     if (i % n == (n - 1)) {
283       GST_LOG ("%03d: %s", i - (n - 1), line);
284     }
285   }
286   if (i % n != 0) {
287     GST_LOG ("%03d: %s", (i / n) * n, line);
288   }
289   g_free (line);
290 }
291
292 GType
293 gst_dp_version_get_type (void)
294 {
295   static gsize gst_dp_version_type = 0;
296   static const GEnumValue gst_dp_version[] = {
297     {GST_DP_VERSION_0_2, "GST_DP_VERSION_0_2", "0.2"},
298     {GST_DP_VERSION_1_0, "GST_DP_VERSION_1_0", "1.0"},
299     {0, NULL, NULL},
300   };
301
302   if (g_once_init_enter (&gst_dp_version_type)) {
303     GType tmp = g_enum_register_static ("GstDPVersion", gst_dp_version);
304     g_once_init_leave (&gst_dp_version_type, tmp);
305   }
306
307   return (GType) gst_dp_version_type;
308 };
309
310 /**
311  * gst_dp_init:
312  *
313  * Initialize GStreamer Data Protocol library.
314  *
315  * Should be called before using these functions from source linking
316  * to this source file.
317  */
318 void
319 gst_dp_init (void)
320 {
321   static gboolean _gst_dp_initialized = FALSE;
322
323   if (_gst_dp_initialized)
324     return;
325
326   _gst_dp_initialized = TRUE;
327
328   g_type_class_ref (gst_dp_version_get_type ());
329
330   GST_DEBUG_CATEGORY_INIT (data_protocol_debug, "gdp", 0,
331       "GStreamer Data Protocol");
332 }
333
334 /**
335  * gst_dp_header_payload_length:
336  * @header: the byte header of the packet array
337  *
338  * Get the length of the payload described by @header.
339  *
340  * Returns: the length of the payload this header describes.
341  */
342 guint32
343 gst_dp_header_payload_length (const guint8 * header)
344 {
345   g_return_val_if_fail (header != NULL, 0);
346
347   return GST_DP_HEADER_PAYLOAD_LENGTH (header);
348 }
349
350 /**
351  * gst_dp_header_payload_type:
352  * @header: the byte header of the packet array
353  *
354  * Get the type of the payload described by @header.
355  *
356  * Returns: the #GstDPPayloadType the payload this header describes.
357  */
358 GstDPPayloadType
359 gst_dp_header_payload_type (const guint8 * header)
360 {
361   g_return_val_if_fail (header != NULL, GST_DP_PAYLOAD_NONE);
362
363   return GST_DP_HEADER_PAYLOAD_TYPE (header);
364 }
365
366 /*** PACKETIZER FUNCTIONS ***/
367
368 static gboolean
369 gst_dp_header_from_buffer_1_0 (const GstBuffer * buffer, GstDPHeaderFlag flags,
370     guint * length, guint8 ** header)
371 {
372   return gst_dp_header_from_buffer_any (buffer, flags, length, header,
373       GST_DP_VERSION_1_0);
374 }
375
376 static gboolean
377 gst_dp_packet_from_caps_1_0 (const GstCaps * caps, GstDPHeaderFlag flags,
378     guint * length, guint8 ** header, guint8 ** payload)
379 {
380   return gst_dp_packet_from_caps_any (caps, flags, length, header, payload,
381       GST_DP_VERSION_1_0);
382 }
383
384 static gboolean
385 gst_dp_packet_from_event_1_0 (const GstEvent * event, GstDPHeaderFlag flags,
386     guint * length, guint8 ** header, guint8 ** payload)
387 {
388   guint8 *h;
389   guint32 pl_length;            /* length of payload */
390   guchar *string = NULL;
391
392   g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
393   g_return_val_if_fail (length, FALSE);
394   g_return_val_if_fail (header, FALSE);
395   g_return_val_if_fail (payload, FALSE);
396
397   *length = GST_DP_HEADER_LENGTH;
398   h = g_malloc0 (GST_DP_HEADER_LENGTH);
399
400   if (event->structure) {
401     string = (guchar *) gst_structure_to_string (event->structure);
402     GST_LOG ("event %p has structure, string %s", event, string);
403     pl_length = strlen ((gchar *) string) + 1;  /* include trailing 0 */
404   } else {
405     GST_LOG ("event %p has no structure", event);
406     pl_length = 0;
407   }
408
409   /* version, flags, type */
410   GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags,
411       GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
412
413   /* length */
414   GST_WRITE_UINT32_BE (h + 6, pl_length);
415   /* timestamp */
416   GST_WRITE_UINT64_BE (h + 10, GST_EVENT_TIMESTAMP (event));
417
418   GST_DP_SET_CRC (h, flags, string, pl_length);
419
420   GST_LOG ("created header from event:");
421   gst_dp_dump_byte_array (h, GST_DP_HEADER_LENGTH);
422   *header = h;
423   *payload = string;
424   return TRUE;
425 }
426
427 /*** DEPACKETIZING FUNCTIONS ***/
428
429 /**
430  * gst_dp_buffer_from_header:
431  * @header_length: the length of the packet header
432  * @header: the byte array of the packet header
433  *
434  * Creates a newly allocated #GstBuffer from the given header.
435  * The buffer data needs to be copied into it before validating.
436  *
437  * Use this function if you want to pre-allocate a buffer based on the
438  * packet header to read the packet payload in to.
439  *
440  * This function does not check the header passed to it, use
441  * gst_dp_validate_header() first if the header data is unchecked.
442  *
443  * Returns: A #GstBuffer if the buffer was successfully created, or NULL.
444  */
445 GstBuffer *
446 gst_dp_buffer_from_header (guint header_length, const guint8 * header)
447 {
448   GstBuffer *buffer;
449
450   g_return_val_if_fail (header != NULL, NULL);
451   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
452   g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
453       GST_DP_PAYLOAD_BUFFER, NULL);
454
455   buffer =
456       gst_buffer_new_and_alloc ((guint) GST_DP_HEADER_PAYLOAD_LENGTH (header));
457
458   GST_BUFFER_TIMESTAMP (buffer) = GST_DP_HEADER_TIMESTAMP (header);
459   GST_BUFFER_DURATION (buffer) = GST_DP_HEADER_DURATION (header);
460   GST_BUFFER_OFFSET (buffer) = GST_DP_HEADER_OFFSET (header);
461   GST_BUFFER_OFFSET_END (buffer) = GST_DP_HEADER_OFFSET_END (header);
462   GST_BUFFER_FLAGS (buffer) = GST_DP_HEADER_BUFFER_FLAGS (header);
463
464   return buffer;
465 }
466
467 /**
468  * gst_dp_caps_from_packet:
469  * @header_length: the length of the packet header
470  * @header: the byte array of the packet header
471  * @payload: the byte array of the packet payload
472  *
473  * Creates a newly allocated #GstCaps from the given packet.
474  *
475  * This function does not check the arguments passed to it, use
476  * gst_dp_validate_packet() first if the header and payload data are
477  * unchecked.
478  *
479  * Returns: A #GstCaps containing the caps represented in the packet,
480  *          or NULL if the packet could not be converted.
481  */
482 GstCaps *
483 gst_dp_caps_from_packet (guint header_length, const guint8 * header,
484     const guint8 * payload)
485 {
486   GstCaps *caps;
487   gchar *string;
488
489   g_return_val_if_fail (header, NULL);
490   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
491   g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
492       GST_DP_PAYLOAD_CAPS, NULL);
493   g_return_val_if_fail (payload, NULL);
494
495   /* 0 sized payload length will work create NULL string */
496   string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
497   caps = gst_caps_from_string (string);
498   g_free (string);
499
500   return caps;
501 }
502
503 static GstEvent *
504 gst_dp_event_from_packet_0_2 (guint header_length, const guint8 * header,
505     const guint8 * payload)
506 {
507   GstEvent *event = NULL;
508   GstEventType type;
509
510   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
511   switch (type) {
512     case GST_EVENT_UNKNOWN:
513       GST_WARNING ("Unknown event, ignoring");
514       return NULL;
515     case GST_EVENT_EOS:
516     case GST_EVENT_FLUSH_START:
517     case GST_EVENT_FLUSH_STOP:
518     case GST_EVENT_NEWSEGMENT:
519       event = gst_event_new_custom (type, NULL);
520       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
521       break;
522     case GST_EVENT_SEEK:
523     {
524       gdouble rate;
525       GstFormat format;
526       GstSeekFlags flags;
527       GstSeekType cur_type, stop_type;
528       gint64 cur, stop;
529
530       g_return_val_if_fail (payload != NULL, NULL);
531
532       /* FIXME, read rate */
533       rate = 1.0;
534       format = (GstFormat) GST_READ_UINT32_BE (payload);
535       flags = (GstSeekFlags) GST_READ_UINT32_BE (payload + 4);
536       cur_type = (GstSeekType) GST_READ_UINT32_BE (payload + 8);
537       cur = (gint64) GST_READ_UINT64_BE (payload + 12);
538       stop_type = (GstSeekType) GST_READ_UINT32_BE (payload + 20);
539       stop = (gint64) GST_READ_UINT64_BE (payload + 24);
540
541       event = gst_event_new_seek (rate, format, flags, cur_type, cur,
542           stop_type, stop);
543       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
544       break;
545     }
546     case GST_EVENT_QOS:
547     case GST_EVENT_NAVIGATION:
548     case GST_EVENT_TAG:
549       GST_WARNING ("Unhandled event type %d, ignoring", type);
550       return NULL;
551     default:
552       GST_WARNING ("Unknown event type %d, ignoring", type);
553       return NULL;
554   }
555
556   return event;
557 }
558
559 static GstEvent *
560 gst_dp_event_from_packet_1_0 (guint header_length, const guint8 * header,
561     const guint8 * payload)
562 {
563   GstEvent *event = NULL;
564   GstEventType type;
565   gchar *string = NULL;
566   GstStructure *s = NULL;
567
568   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
569   if (payload) {
570     string =
571         g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
572     s = gst_structure_from_string (string, NULL);
573     g_free (string);
574   }
575   event = gst_event_new_custom (type, s);
576   return event;
577 }
578
579
580 /**
581  * gst_dp_event_from_packet:
582  * @header_length: the length of the packet header
583  * @header: the byte array of the packet header
584  * @payload: the byte array of the packet payload
585  *
586  * Creates a newly allocated #GstEvent from the given packet.
587  *
588  * This function does not check the arguments passed to it, use
589  * gst_dp_validate_packet() first if the header and payload data are
590  * unchecked.
591  *
592  * Returns: A #GstEvent if the event was successfully created,
593  *          or NULL if an event could not be read from the payload.
594  */
595 GstEvent *
596 gst_dp_event_from_packet (guint header_length, const guint8 * header,
597     const guint8 * payload)
598 {
599   guint8 major, minor;
600
601   g_return_val_if_fail (header, NULL);
602   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
603
604   major = GST_DP_HEADER_MAJOR_VERSION (header);
605   minor = GST_DP_HEADER_MINOR_VERSION (header);
606
607   if (major == 0 && minor == 2)
608     return gst_dp_event_from_packet_0_2 (header_length, header, payload);
609   else if (major == 1 && minor == 0)
610     return gst_dp_event_from_packet_1_0 (header_length, header, payload);
611   else {
612     GST_ERROR ("Unknown GDP version %d.%d", major, minor);
613     return NULL;
614   }
615 }
616
617 /**
618  * gst_dp_validate_header:
619  * @header_length: the length of the packet header
620  * @header: the byte array of the packet header
621  *
622  * Validates the given packet header by checking the CRC checksum.
623  *
624  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
625  */
626 gboolean
627 gst_dp_validate_header (guint header_length, const guint8 * header)
628 {
629   guint16 crc_read, crc_calculated;
630
631   g_return_val_if_fail (header != NULL, FALSE);
632   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
633
634   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_HEADER))
635     return TRUE;
636
637   crc_read = GST_DP_HEADER_CRC_HEADER (header);
638
639   /* don't include the last two crc fields for the crc check */
640   crc_calculated = gst_dp_crc (header, header_length - 4);
641   if (crc_read != crc_calculated)
642     goto crc_error;
643
644   GST_LOG ("header crc validation: %02x", crc_read);
645   return TRUE;
646
647   /* ERRORS */
648 crc_error:
649   {
650     GST_WARNING ("header crc mismatch: read %02x, calculated %02x", crc_read,
651         crc_calculated);
652     return FALSE;
653   }
654 }
655
656 /**
657  * gst_dp_validate_payload:
658  * @header_length: the length of the packet header
659  * @header: the byte array of the packet header
660  * @payload: the byte array of the packet payload
661  *
662  * Validates the given packet payload using the given packet header
663  * by checking the CRC checksum.
664  *
665  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
666  */
667 gboolean
668 gst_dp_validate_payload (guint header_length, const guint8 * header,
669     const guint8 * payload)
670 {
671   guint16 crc_read, crc_calculated;
672
673   g_return_val_if_fail (header != NULL, FALSE);
674   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
675
676   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_PAYLOAD))
677     return TRUE;
678
679   crc_read = GST_DP_HEADER_CRC_PAYLOAD (header);
680   crc_calculated = gst_dp_crc (payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
681   if (crc_read != crc_calculated)
682     goto crc_error;
683
684   GST_LOG ("payload crc validation: %02x", crc_read);
685   return TRUE;
686
687   /* ERRORS */
688 crc_error:
689   {
690     GST_WARNING ("payload crc mismatch: read %02x, calculated %02x", crc_read,
691         crc_calculated);
692     return FALSE;
693   }
694 }
695
696 /**
697  * gst_dp_validate_packet:
698  * @header_length: the length of the packet header
699  * @header: the byte array of the packet header
700  * @payload: the byte array of the packet payload
701  *
702  * Validates the given packet by checking version information and checksums.
703  *
704  * Returns: %TRUE if the packet validates.
705  */
706 gboolean
707 gst_dp_validate_packet (guint header_length, const guint8 * header,
708     const guint8 * payload)
709 {
710   if (!gst_dp_validate_header (header_length, header))
711     return FALSE;
712   if (!gst_dp_validate_payload (header_length, header, payload))
713     return FALSE;
714
715   return TRUE;
716 }
717
718 /**
719  * gst_dp_packetizer_new:
720  * @version: the #GstDPVersion of the protocol to packetize for.
721  *
722  * Creates a new packetizer.
723  *
724  * Returns: a newly allocated #GstDPPacketizer
725  */
726 GstDPPacketizer *
727 gst_dp_packetizer_new (GstDPVersion version)
728 {
729   GstDPPacketizer *ret;
730
731   ret = g_malloc0 (sizeof (GstDPPacketizer));
732   ret->version = version;
733
734   switch (version) {
735     case GST_DP_VERSION_1_0:
736       ret->header_from_buffer = gst_dp_header_from_buffer_1_0;
737       ret->packet_from_caps = gst_dp_packet_from_caps_1_0;
738       ret->packet_from_event = gst_dp_packet_from_event_1_0;
739       break;
740     default:
741       g_free (ret);
742       ret = NULL;
743       break;
744   }
745
746   return ret;
747 }
748
749 /**
750  * gst_dp_packetizer_free:
751  * @packetizer: the #GstDPPacketizer to free.
752  *
753  * Free the given packetizer.
754  */
755 void
756 gst_dp_packetizer_free (GstDPPacketizer * packetizer)
757 {
758   g_free (packetizer);
759 }