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