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