Rework GstSegment handling
[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_PREROLL | 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_and_alloc ((guint) GST_DP_HEADER_PAYLOAD_LENGTH (header));
465
466   GST_BUFFER_TIMESTAMP (buffer) = GST_DP_HEADER_TIMESTAMP (header);
467   GST_BUFFER_DURATION (buffer) = GST_DP_HEADER_DURATION (header);
468   GST_BUFFER_OFFSET (buffer) = GST_DP_HEADER_OFFSET (header);
469   GST_BUFFER_OFFSET_END (buffer) = GST_DP_HEADER_OFFSET_END (header);
470   GST_BUFFER_FLAGS (buffer) = GST_DP_HEADER_BUFFER_FLAGS (header);
471
472   return buffer;
473 }
474
475 /**
476  * gst_dp_caps_from_packet:
477  * @header_length: the length of the packet header
478  * @header: the byte array of the packet header
479  * @payload: the byte array of the packet payload
480  *
481  * Creates a newly allocated #GstCaps from the given packet.
482  *
483  * This function does not check the arguments passed to it, use
484  * gst_dp_validate_packet() first if the header and payload data are
485  * unchecked.
486  *
487  * Returns: A #GstCaps containing the caps represented in the packet,
488  *          or NULL if the packet could not be converted.
489  */
490 GstCaps *
491 gst_dp_caps_from_packet (guint header_length, const guint8 * header,
492     const guint8 * payload)
493 {
494   GstCaps *caps;
495   gchar *string;
496
497   g_return_val_if_fail (header, NULL);
498   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
499   g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
500       GST_DP_PAYLOAD_CAPS, NULL);
501   g_return_val_if_fail (payload, NULL);
502
503   /* 0 sized payload length will work create NULL string */
504   string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
505   caps = gst_caps_from_string (string);
506   g_free (string);
507
508   return caps;
509 }
510
511 static GstEvent *
512 gst_dp_event_from_packet_0_2 (guint header_length, const guint8 * header,
513     const guint8 * payload)
514 {
515   GstEvent *event = NULL;
516   GstEventType type;
517
518   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
519   switch (type) {
520     case GST_EVENT_UNKNOWN:
521       GST_WARNING ("Unknown event, ignoring");
522       return NULL;
523     case GST_EVENT_EOS:
524     case GST_EVENT_FLUSH_START:
525     case GST_EVENT_FLUSH_STOP:
526     case GST_EVENT_SEGMENT:
527       event = gst_event_new_custom (type, NULL);
528       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
529       break;
530     case GST_EVENT_SEEK:
531     {
532       gdouble rate;
533       GstFormat format;
534       GstSeekFlags flags;
535       GstSeekType cur_type, stop_type;
536       gint64 cur, stop;
537
538       g_return_val_if_fail (payload != NULL, NULL);
539
540       /* FIXME, read rate */
541       rate = 1.0;
542       format = (GstFormat) GST_READ_UINT32_BE (payload);
543       flags = (GstSeekFlags) GST_READ_UINT32_BE (payload + 4);
544       cur_type = (GstSeekType) GST_READ_UINT32_BE (payload + 8);
545       cur = (gint64) GST_READ_UINT64_BE (payload + 12);
546       stop_type = (GstSeekType) GST_READ_UINT32_BE (payload + 20);
547       stop = (gint64) GST_READ_UINT64_BE (payload + 24);
548
549       event = gst_event_new_seek (rate, format, flags, cur_type, cur,
550           stop_type, stop);
551       GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
552       break;
553     }
554     case GST_EVENT_QOS:
555     case GST_EVENT_NAVIGATION:
556     case GST_EVENT_TAG:
557       GST_WARNING ("Unhandled event type %d, ignoring", type);
558       return NULL;
559     default:
560       GST_WARNING ("Unknown event type %d, ignoring", type);
561       return NULL;
562   }
563
564   return event;
565 }
566
567 static GstEvent *
568 gst_dp_event_from_packet_1_0 (guint header_length, const guint8 * header,
569     const guint8 * payload)
570 {
571   GstEvent *event = NULL;
572   GstEventType type;
573   gchar *string = NULL;
574   GstStructure *s = NULL;
575
576   type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
577   if (payload) {
578     string =
579         g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
580     s = gst_structure_from_string (string, NULL);
581     g_free (string);
582   }
583   event = gst_event_new_custom (type, s);
584   return event;
585 }
586
587
588 /**
589  * gst_dp_event_from_packet:
590  * @header_length: the length of the packet header
591  * @header: the byte array of the packet header
592  * @payload: the byte array of the packet payload
593  *
594  * Creates a newly allocated #GstEvent from the given packet.
595  *
596  * This function does not check the arguments passed to it, use
597  * gst_dp_validate_packet() first if the header and payload data are
598  * unchecked.
599  *
600  * Returns: A #GstEvent if the event was successfully created,
601  *          or NULL if an event could not be read from the payload.
602  */
603 GstEvent *
604 gst_dp_event_from_packet (guint header_length, const guint8 * header,
605     const guint8 * payload)
606 {
607   guint8 major, minor;
608
609   g_return_val_if_fail (header, NULL);
610   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
611
612   major = GST_DP_HEADER_MAJOR_VERSION (header);
613   minor = GST_DP_HEADER_MINOR_VERSION (header);
614
615   if (major == 0 && minor == 2)
616     return gst_dp_event_from_packet_0_2 (header_length, header, payload);
617   else if (major == 1 && minor == 0)
618     return gst_dp_event_from_packet_1_0 (header_length, header, payload);
619   else {
620     GST_ERROR ("Unknown GDP version %d.%d", major, minor);
621     return NULL;
622   }
623 }
624
625 /**
626  * gst_dp_validate_header:
627  * @header_length: the length of the packet header
628  * @header: the byte array of the packet header
629  *
630  * Validates the given packet header by checking the CRC checksum.
631  *
632  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
633  */
634 gboolean
635 gst_dp_validate_header (guint header_length, const guint8 * header)
636 {
637   guint16 crc_read, crc_calculated;
638
639   g_return_val_if_fail (header != NULL, FALSE);
640   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
641
642   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_HEADER))
643     return TRUE;
644
645   crc_read = GST_DP_HEADER_CRC_HEADER (header);
646
647   /* don't include the last two crc fields for the crc check */
648   crc_calculated = gst_dp_crc (header, header_length - 4);
649   if (crc_read != crc_calculated)
650     goto crc_error;
651
652   GST_LOG ("header crc validation: %02x", crc_read);
653   return TRUE;
654
655   /* ERRORS */
656 crc_error:
657   {
658     GST_WARNING ("header crc mismatch: read %02x, calculated %02x", crc_read,
659         crc_calculated);
660     return FALSE;
661   }
662 }
663
664 /**
665  * gst_dp_validate_payload:
666  * @header_length: the length of the packet header
667  * @header: the byte array of the packet header
668  * @payload: the byte array of the packet payload
669  *
670  * Validates the given packet payload using the given packet header
671  * by checking the CRC checksum.
672  *
673  * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
674  */
675 gboolean
676 gst_dp_validate_payload (guint header_length, const guint8 * header,
677     const guint8 * payload)
678 {
679   guint16 crc_read, crc_calculated;
680
681   g_return_val_if_fail (header != NULL, FALSE);
682   g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
683
684   if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_PAYLOAD))
685     return TRUE;
686
687   crc_read = GST_DP_HEADER_CRC_PAYLOAD (header);
688   crc_calculated = gst_dp_crc (payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
689   if (crc_read != crc_calculated)
690     goto crc_error;
691
692   GST_LOG ("payload crc validation: %02x", crc_read);
693   return TRUE;
694
695   /* ERRORS */
696 crc_error:
697   {
698     GST_WARNING ("payload crc mismatch: read %02x, calculated %02x", crc_read,
699         crc_calculated);
700     return FALSE;
701   }
702 }
703
704 /**
705  * gst_dp_validate_packet:
706  * @header_length: the length of the packet header
707  * @header: the byte array of the packet header
708  * @payload: the byte array of the packet payload
709  *
710  * Validates the given packet by checking version information and checksums.
711  *
712  * Returns: %TRUE if the packet validates.
713  */
714 gboolean
715 gst_dp_validate_packet (guint header_length, const guint8 * header,
716     const guint8 * payload)
717 {
718   if (!gst_dp_validate_header (header_length, header))
719     return FALSE;
720   if (!gst_dp_validate_payload (header_length, header, payload))
721     return FALSE;
722
723   return TRUE;
724 }
725
726 /**
727  * gst_dp_packetizer_new:
728  * @version: the #GstDPVersion of the protocol to packetize for.
729  *
730  * Creates a new packetizer.
731  *
732  * Returns: a newly allocated #GstDPPacketizer
733  */
734 GstDPPacketizer *
735 gst_dp_packetizer_new (GstDPVersion version)
736 {
737   GstDPPacketizer *ret;
738
739   ret = g_malloc0 (sizeof (GstDPPacketizer));
740   ret->version = version;
741
742   switch (version) {
743     case GST_DP_VERSION_1_0:
744       ret->header_from_buffer = gst_dp_header_from_buffer_1_0;
745       ret->packet_from_caps = gst_dp_packet_from_caps_1_0;
746       ret->packet_from_event = gst_dp_packet_from_event_1_0;
747       break;
748     default:
749       g_free (ret);
750       ret = NULL;
751       break;
752   }
753
754   return ret;
755 }
756
757 /**
758  * gst_dp_packetizer_free:
759  * @packetizer: the #GstDPPacketizer to free.
760  *
761  * Free the given packetizer.
762  */
763 void
764 gst_dp_packetizer_free (GstDPPacketizer * packetizer)
765 {
766   g_free (packetizer);
767 }