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 * Copyright (C) 2014 Tim-Philipp Müller <tim centricular com>
5 *
6 * dataprotocol.c: Functions implementing the GStreamer Data Protocol
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 /**
25 * SECTION:gstdataprotocol
26 * @title: GstDataProtocol
27 * @short_description: Serialization of caps, buffers and events.
28 * @see_also: #GstCaps, #GstEvent, #GstBuffer
29 *
30 * This helper library provides serialization of GstBuffer, GstCaps and
31 * GstEvent structures.
32 *
33 * This serialization is useful when GStreamer needs to interface with
34 * the outside world to transport data between distinct GStreamer pipelines.
35 * The connections with the outside world generally don't have mechanisms
36 * to transport properties of these structures.
37 *
38 * For example, transporting buffers across named pipes or network connections
39 * doesn't maintain the buffer size and separation.
40 *
41 * This data protocol assumes a reliable connection-oriented transport, such as
42 * TCP, a pipe, or a file. The protocol does not serialize the caps for
43 * each buffer; instead, it transport the caps only when they change in the
44 * stream. This implies that there will always be a caps packet before any
45 * buffer packets.
46 *
47 * The versioning of the protocol is independent of GStreamer's version.
48 * The major number gets incremented, and the minor reset, for incompatible
49 * changes. The minor number gets incremented for compatible changes that
50 * allow clients who do not completely understand the newer protocol version
51 * to still decode what they do understand.
52 *
53 * Version 0.2 serializes only a small subset of all events, with a custom
54 * payload for each type. Also, all GDP streams start with the initial caps
55 * packet.
56 *
57 * Version 1.0 serializes all events by taking the string representation of
58 * the event as the payload. In addition, GDP streams can now start with
59 * events as well, as required by the new data stream model in GStreamer 0.10.
60 *
61 * Converting buffers, caps and events to GDP buffers is done using the
62 * appropriate functions.
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 "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 #ifndef GST_CAT_DEFAULT
82 #define GST_CAT_DEFAULT data_protocol_debug
83 #endif
84
85 /* The version of the GDP protocol being used */
86 typedef enum
87 {
88 GST_DP_VERSION_0_2 = 1,
89 GST_DP_VERSION_1_0,
90 } GstDPVersion;
91
92 /* helper macros */
93
94 /* write first 6 bytes of header */
95 #define GST_DP_INIT_HEADER(h, version, flags, type) \
96 G_STMT_START { \
97 gint maj = 0, min = 0; \
98 switch (version) { \
99 case GST_DP_VERSION_0_2: maj = 0; min = 2; break; \
100 case GST_DP_VERSION_1_0: maj = 1; min = 0; break; \
101 } \
102 h[0] = (guint8) maj; \
103 h[1] = (guint8) min; \
104 h[2] = (guint8) flags; \
105 h[3] = 0; /* padding byte */ \
106 GST_WRITE_UINT16_BE (h + 4, type); \
107 } G_STMT_END
108
109 #define GST_DP_SET_CRC(h, flags, payload, length); \
110 G_STMT_START { \
111 guint16 crc = 0; \
112 if (flags & GST_DP_HEADER_FLAG_CRC_HEADER) \
113 /* we don't crc the last four bytes since they are crc's */ \
114 crc = gst_dp_crc (h, 58); \
115 GST_WRITE_UINT16_BE (h + 58, crc); \
116 \
117 crc = 0; \
118 if (length && (flags & GST_DP_HEADER_FLAG_CRC_PAYLOAD)) \
119 crc = gst_dp_crc (payload, length); \
120 GST_WRITE_UINT16_BE (h + 60, crc); \
121 } G_STMT_END
122
123 /* calculate a CCITT 16 bit CRC check value for a given byte array */
124 /*
125 * this code snippet is adapted from a web page I found
126 * it is identical except for cleanups, and a final XOR with 0xffff
127 * as outlined in the uecp spec
128 *
129 * XMODEM x^16 + x^12 + x^5 + 1
130 */
131
132 #define POLY 0x1021
133 #define CRC_INIT 0xFFFF
134
135 static guint16 gst_dp_crc (const guint8 * buffer, guint length);
136 static guint16 gst_dp_crc_from_memory_maps (const GstMapInfo * maps,
137 guint n_maps);
138
139 /* payloading functions */
140
141 GstBuffer *
gst_dp_payload_buffer(GstBuffer * buffer,GstDPHeaderFlag flags)142 gst_dp_payload_buffer (GstBuffer * buffer, GstDPHeaderFlag flags)
143 {
144 GstBuffer *ret_buf;
145 GstMapInfo map;
146 GstMemory *mem;
147 guint8 *h;
148 guint16 flags_mask;
149 guint16 header_crc = 0, crc = 0;
150 gsize buffer_size;
151
152 mem = gst_allocator_alloc (NULL, GST_DP_HEADER_LENGTH, NULL);
153 gst_memory_map (mem, &map, GST_MAP_READWRITE);
154 h = memset (map.data, 0, map.size);
155
156 /* version, flags, type */
157 GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags, GST_DP_PAYLOAD_BUFFER);
158
159 if ((flags & GST_DP_HEADER_FLAG_CRC_PAYLOAD)) {
160 GstMapInfo *maps;
161 guint n_maps, i;
162
163 buffer_size = 0;
164
165 n_maps = gst_buffer_n_memory (buffer);
166 if (n_maps > 0) {
167 maps = g_newa (GstMapInfo, n_maps);
168
169 for (i = 0; i < n_maps; ++i) {
170 GstMemory *mem;
171
172 mem = gst_buffer_peek_memory (buffer, i);
173 gst_memory_map (mem, &maps[i], GST_MAP_READ);
174 buffer_size += maps[i].size;
175 }
176
177 crc = gst_dp_crc_from_memory_maps (maps, n_maps);
178
179 for (i = 0; i < n_maps; ++i)
180 gst_memory_unmap (maps[i].memory, &maps[i]);
181 }
182 } else {
183 buffer_size = gst_buffer_get_size (buffer);
184 }
185
186 /* buffer properties */
187 GST_WRITE_UINT32_BE (h + 6, buffer_size);
188 GST_WRITE_UINT64_BE (h + 10, GST_BUFFER_TIMESTAMP (buffer));
189 GST_WRITE_UINT64_BE (h + 18, GST_BUFFER_DURATION (buffer));
190 GST_WRITE_UINT64_BE (h + 26, GST_BUFFER_OFFSET (buffer));
191 GST_WRITE_UINT64_BE (h + 34, GST_BUFFER_OFFSET_END (buffer));
192
193 /* data flags; eats two bytes from the ABI area */
194 /* we copy everything but the read-only flags */
195 flags_mask = GST_BUFFER_FLAG_LIVE | GST_BUFFER_FLAG_DISCONT |
196 GST_BUFFER_FLAG_HEADER | GST_BUFFER_FLAG_GAP | GST_BUFFER_FLAG_DELTA_UNIT;
197
198 GST_WRITE_UINT16_BE (h + 42, GST_BUFFER_FLAGS (buffer) & flags_mask);
199
200 /* from gstreamer 1.x, buffers also have the DTS */
201 GST_WRITE_UINT64_BE (h + 44, GST_BUFFER_DTS (buffer));
202
203 /* header CRC */
204 if ((flags & GST_DP_HEADER_FLAG_CRC_HEADER))
205 /* we don't crc the last four bytes since they are crc's */
206 header_crc = gst_dp_crc (h, 58);
207 else
208 header_crc = 0;
209
210 GST_WRITE_UINT16_BE (h + 58, header_crc);
211
212 /* payload CRC */
213 GST_WRITE_UINT16_BE (h + 60, crc);
214
215 GST_MEMDUMP ("payload header for buffer", h, GST_DP_HEADER_LENGTH);
216 gst_memory_unmap (mem, &map);
217
218 ret_buf = gst_buffer_new ();
219
220 /* header */
221 gst_buffer_append_memory (ret_buf, mem);
222
223 /* buffer data */
224 return gst_buffer_append (ret_buf, gst_buffer_ref (buffer));
225 }
226
227 GstBuffer *
gst_dp_payload_caps(const GstCaps * caps,GstDPHeaderFlag flags)228 gst_dp_payload_caps (const GstCaps * caps, GstDPHeaderFlag flags)
229 {
230 GstBuffer *buf;
231 GstMapInfo map;
232 GstMemory *mem;
233 guint8 *h;
234 guchar *string;
235 guint payload_length;
236
237 g_assert (GST_IS_CAPS (caps));
238
239 buf = gst_buffer_new ();
240
241 mem = gst_allocator_alloc (NULL, GST_DP_HEADER_LENGTH, NULL);
242 gst_memory_map (mem, &map, GST_MAP_READWRITE);
243 h = memset (map.data, 0, map.size);
244
245 string = (guchar *) gst_caps_to_string (caps);
246 payload_length = strlen ((gchar *) string) + 1; /* include trailing 0 */
247
248 /* version, flags, type */
249 GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags, GST_DP_PAYLOAD_CAPS);
250
251 /* buffer properties */
252 GST_WRITE_UINT32_BE (h + 6, payload_length);
253 GST_WRITE_UINT64_BE (h + 10, (guint64) 0);
254 GST_WRITE_UINT64_BE (h + 18, (guint64) 0);
255 GST_WRITE_UINT64_BE (h + 26, (guint64) 0);
256 GST_WRITE_UINT64_BE (h + 34, (guint64) 0);
257
258 GST_DP_SET_CRC (h, flags, string, payload_length);
259
260 GST_MEMDUMP ("payload header for caps", h, GST_DP_HEADER_LENGTH);
261 gst_memory_unmap (mem, &map);
262
263 /* header */
264 gst_buffer_append_memory (buf, mem);
265
266 /* caps string */
267 gst_buffer_append_memory (buf,
268 gst_memory_new_wrapped (0, string, payload_length, 0, payload_length,
269 string, g_free));
270
271 return buf;
272 }
273
274 GstBuffer *
gst_dp_payload_event(const GstEvent * event,GstDPHeaderFlag flags)275 gst_dp_payload_event (const GstEvent * event, GstDPHeaderFlag flags)
276 {
277 GstBuffer *buf;
278 GstMapInfo map;
279 GstMemory *mem;
280 guint8 *h;
281 guint32 pl_length; /* length of payload */
282 guchar *string = NULL;
283 const GstStructure *structure;
284
285 g_assert (GST_IS_EVENT (event));
286
287 buf = gst_buffer_new ();
288
289 mem = gst_allocator_alloc (NULL, GST_DP_HEADER_LENGTH, NULL);
290 gst_memory_map (mem, &map, GST_MAP_READWRITE);
291 h = memset (map.data, 0, map.size);
292
293 structure = gst_event_get_structure ((GstEvent *) event);
294 if (structure) {
295 string = (guchar *) gst_structure_to_string (structure);
296 GST_LOG ("event %p has structure, string %s", event, string);
297 pl_length = strlen ((gchar *) string) + 1; /* include trailing 0 */
298 } else {
299 GST_LOG ("event %p has no structure", event);
300 pl_length = 0;
301 }
302
303 /* version, flags, type */
304 GST_DP_INIT_HEADER (h, GST_DP_VERSION_1_0, flags,
305 GST_DP_PAYLOAD_EVENT_NONE + GST_EVENT_TYPE (event));
306
307 /* length */
308 GST_WRITE_UINT32_BE (h + 6, pl_length);
309 /* timestamp */
310 /* NOTE: timestamp field will be removed from GstEvent in 2.0 API */
311 GST_WRITE_UINT64_BE (h + 10, GST_CLOCK_TIME_NONE);
312
313 GST_DP_SET_CRC (h, flags, string, pl_length);
314
315 GST_MEMDUMP ("payload header for event", h, GST_DP_HEADER_LENGTH);
316 gst_memory_unmap (mem, &map);
317
318 /* header */
319 gst_buffer_append_memory (buf, mem);
320
321 /* event string */
322 if (pl_length > 0) {
323 gst_buffer_append_memory (buf,
324 gst_memory_new_wrapped (0, string, pl_length, 0, pl_length,
325 string, g_free));
326 }
327
328 return buf;
329 }
330
331 /*** PUBLIC FUNCTIONS ***/
332
333 static const guint16 gst_dp_crc_table[256] = {
334 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
335 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
336 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
337 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
338 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
339 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
340 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
341 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
342 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
343 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
344 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
345 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
346 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
347 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
348 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
349 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
350 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
351 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
352 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
353 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
354 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
355 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
356 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
357 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
358 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
359 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
360 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
361 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
362 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
363 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
364 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
365 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
366 };
367
368 /**
369 * gst_dp_crc:
370 * @buffer: array of bytes
371 * @length: the length of @buffer
372 *
373 * Calculate a CRC for the given buffer over the given number of bytes.
374 * This is only provided for verification purposes; typical GDP users
375 * will not need this function.
376 *
377 * Returns: a two-byte CRC checksum.
378 */
379 static guint16
gst_dp_crc(const guint8 * buffer,guint length)380 gst_dp_crc (const guint8 * buffer, guint length)
381 {
382 guint16 crc_register = CRC_INIT;
383
384 if (length == 0)
385 return 0;
386
387 g_assert (buffer != NULL);
388
389 /* calc CRC */
390 for (; length--;) {
391 crc_register = (guint16) ((crc_register << 8) ^
392 gst_dp_crc_table[((crc_register >> 8) & 0x00ff) ^ *buffer++]);
393 }
394 return (0xffff ^ crc_register);
395 }
396
397 static guint16
gst_dp_crc_from_memory_maps(const GstMapInfo * maps,guint n_maps)398 gst_dp_crc_from_memory_maps (const GstMapInfo * maps, guint n_maps)
399 {
400 guint16 crc_register = CRC_INIT;
401 gsize total_length = 0;
402
403 if (n_maps == 0)
404 return 0;
405
406 g_assert (maps != NULL);
407
408 /* calc CRC */
409 while (n_maps > 0) {
410 guint8 *buffer = maps->data;
411 gsize length = maps->size;
412
413 total_length += length;
414
415 while (length-- > 0) {
416 crc_register = (guint16) ((crc_register << 8) ^
417 gst_dp_crc_table[((crc_register >> 8) & 0x00ff) ^ *buffer++]);
418 }
419 --n_maps;
420 ++maps;
421 }
422
423 if (G_UNLIKELY (total_length == 0))
424 return 0;
425
426 return (0xffff ^ crc_register);
427 }
428
429 /**
430 * gst_dp_init:
431 *
432 * Initialize GStreamer Data Protocol library.
433 *
434 * Should be called before using these functions from source linking
435 * to this source file.
436 */
437 void
gst_dp_init(void)438 gst_dp_init (void)
439 {
440 GST_DEBUG_CATEGORY_INIT (data_protocol_debug, "gdp", 0,
441 "GStreamer Data Protocol");
442 }
443
444 /**
445 * gst_dp_header_payload_length:
446 * @header: the byte header of the packet array
447 *
448 * Get the length of the payload described by @header.
449 *
450 * Returns: the length of the payload this header describes.
451 */
452 guint32
gst_dp_header_payload_length(const guint8 * header)453 gst_dp_header_payload_length (const guint8 * header)
454 {
455 g_return_val_if_fail (header != NULL, 0);
456
457 return GST_DP_HEADER_PAYLOAD_LENGTH (header);
458 }
459
460 /**
461 * gst_dp_header_payload_type:
462 * @header: the byte header of the packet array
463 *
464 * Get the type of the payload described by @header.
465 *
466 * Returns: the #GstDPPayloadType the payload this header describes.
467 */
468 GstDPPayloadType
gst_dp_header_payload_type(const guint8 * header)469 gst_dp_header_payload_type (const guint8 * header)
470 {
471 g_return_val_if_fail (header != NULL, GST_DP_PAYLOAD_NONE);
472
473 return GST_DP_HEADER_PAYLOAD_TYPE (header);
474 }
475
476 /*** DEPACKETIZING FUNCTIONS ***/
477
478 /**
479 * gst_dp_buffer_from_header:
480 * @header_length: the length of the packet header
481 * @header: the byte array of the packet header
482 * @allocator: the allocator used to allocate the new #GstBuffer
483 * @allocation_params: the allocations parameters used to allocate the new #GstBuffer
484 *
485 * Creates a newly allocated #GstBuffer from the given header.
486 * The buffer data needs to be copied into it before validating.
487 *
488 * Use this function if you want to pre-allocate a buffer based on the
489 * packet header to read the packet payload in to.
490 *
491 * This function does not check the header passed to it, use
492 * gst_dp_validate_header() first if the header data is unchecked.
493 *
494 * Returns: A #GstBuffer if the buffer was successfully created, or NULL.
495 */
496 GstBuffer *
gst_dp_buffer_from_header(guint header_length,const guint8 * header,GstAllocator * allocator,GstAllocationParams * allocation_params)497 gst_dp_buffer_from_header (guint header_length, const guint8 * header,
498 GstAllocator * allocator, GstAllocationParams * allocation_params)
499 {
500 GstBuffer *buffer;
501
502 g_return_val_if_fail (header != NULL, NULL);
503 g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
504 g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
505 GST_DP_PAYLOAD_BUFFER, NULL);
506
507 buffer =
508 gst_buffer_new_allocate (allocator,
509 (guint) GST_DP_HEADER_PAYLOAD_LENGTH (header), allocation_params);
510
511 GST_BUFFER_TIMESTAMP (buffer) = GST_DP_HEADER_TIMESTAMP (header);
512 GST_BUFFER_DTS (buffer) = GST_DP_HEADER_DTS (header);
513 GST_BUFFER_DURATION (buffer) = GST_DP_HEADER_DURATION (header);
514 GST_BUFFER_OFFSET (buffer) = GST_DP_HEADER_OFFSET (header);
515 GST_BUFFER_OFFSET_END (buffer) = GST_DP_HEADER_OFFSET_END (header);
516 GST_BUFFER_FLAGS (buffer) = GST_DP_HEADER_BUFFER_FLAGS (header);
517
518 return buffer;
519 }
520
521 /**
522 * gst_dp_caps_from_packet:
523 * @header_length: the length of the packet header
524 * @header: the byte array of the packet header
525 * @payload: the byte array of the packet payload
526 *
527 * Creates a newly allocated #GstCaps from the given packet.
528 *
529 * This function does not check the arguments passed to it, use
530 * gst_dp_validate_packet() first if the header and payload data are
531 * unchecked.
532 *
533 * Returns: A #GstCaps containing the caps represented in the packet,
534 * or NULL if the packet could not be converted.
535 */
536 GstCaps *
gst_dp_caps_from_packet(guint header_length,const guint8 * header,const guint8 * payload)537 gst_dp_caps_from_packet (guint header_length, const guint8 * header,
538 const guint8 * payload)
539 {
540 GstCaps *caps;
541 gchar *string;
542
543 g_return_val_if_fail (header, NULL);
544 g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
545 g_return_val_if_fail (GST_DP_HEADER_PAYLOAD_TYPE (header) ==
546 GST_DP_PAYLOAD_CAPS, NULL);
547 g_return_val_if_fail (payload, NULL);
548
549 /* 0 sized payload length will work create NULL string */
550 string = g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
551 caps = gst_caps_from_string (string);
552 g_free (string);
553
554 return caps;
555 }
556
557 static GstEvent *
gst_dp_event_from_packet_0_2(guint header_length,const guint8 * header,const guint8 * payload)558 gst_dp_event_from_packet_0_2 (guint header_length, const guint8 * header,
559 const guint8 * payload)
560 {
561 GstEvent *event = NULL;
562 GstEventType type;
563
564 type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
565 switch (type) {
566 case GST_EVENT_UNKNOWN:
567 GST_WARNING ("Unknown event, ignoring");
568 return NULL;
569 case GST_EVENT_EOS:
570 case GST_EVENT_FLUSH_START:
571 case GST_EVENT_FLUSH_STOP:
572 case GST_EVENT_SEGMENT:
573 event = gst_event_new_custom (type, NULL);
574 break;
575 case GST_EVENT_SEEK:
576 {
577 gdouble rate;
578 GstFormat format;
579 GstSeekFlags flags;
580 GstSeekType start_type, stop_type;
581 gint64 start, stop;
582
583 g_return_val_if_fail (payload != NULL, NULL);
584
585 /* FIXME, read rate */
586 rate = 1.0;
587 format = (GstFormat) GST_READ_UINT32_BE (payload);
588 flags = (GstSeekFlags) GST_READ_UINT32_BE (payload + 4);
589 start_type = (GstSeekType) GST_READ_UINT32_BE (payload + 8);
590 start = (gint64) GST_READ_UINT64_BE (payload + 12);
591 stop_type = (GstSeekType) GST_READ_UINT32_BE (payload + 20);
592 stop = (gint64) GST_READ_UINT64_BE (payload + 24);
593
594 event = gst_event_new_seek (rate, format, flags, start_type, start,
595 stop_type, stop);
596 GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
597 break;
598 }
599 case GST_EVENT_QOS:
600 case GST_EVENT_NAVIGATION:
601 case GST_EVENT_TAG:
602 GST_WARNING ("Unhandled event type %d, ignoring", type);
603 return NULL;
604 default:
605 GST_WARNING ("Unknown event type %d, ignoring", type);
606 return NULL;
607 }
608
609 return event;
610 }
611
612 static GstEvent *
gst_dp_event_from_packet_1_0(guint header_length,const guint8 * header,const guint8 * payload)613 gst_dp_event_from_packet_1_0 (guint header_length, const guint8 * header,
614 const guint8 * payload)
615 {
616 GstEvent *event = NULL;
617 GstEventType type;
618 gchar *string = NULL;
619 GstStructure *s = NULL;
620
621 type = GST_DP_HEADER_PAYLOAD_TYPE (header) - GST_DP_PAYLOAD_EVENT_NONE;
622 if (payload) {
623 string =
624 g_strndup ((gchar *) payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
625 s = gst_structure_from_string (string, NULL);
626 if (s == NULL) {
627 GST_WARNING ("Could not parse payload string: %s", string);
628 g_free (string);
629 return NULL;
630 }
631
632 g_free (string);
633 }
634 GST_LOG ("Creating event of type 0x%x with structure '%" GST_PTR_FORMAT "'",
635 type, s);
636 event = gst_event_new_custom (type, s);
637 return event;
638 }
639
640
641 /**
642 * gst_dp_event_from_packet:
643 * @header_length: the length of the packet header
644 * @header: the byte array of the packet header
645 * @payload: the byte array of the packet payload
646 *
647 * Creates a newly allocated #GstEvent from the given packet.
648 *
649 * This function does not check the arguments passed to it, use
650 * gst_dp_validate_packet() first if the header and payload data are
651 * unchecked.
652 *
653 * Returns: A #GstEvent if the event was successfully created,
654 * or NULL if an event could not be read from the payload.
655 */
656 GstEvent *
gst_dp_event_from_packet(guint header_length,const guint8 * header,const guint8 * payload)657 gst_dp_event_from_packet (guint header_length, const guint8 * header,
658 const guint8 * payload)
659 {
660 guint8 major, minor;
661
662 g_return_val_if_fail (header, NULL);
663 g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, NULL);
664
665 major = GST_DP_HEADER_MAJOR_VERSION (header);
666 minor = GST_DP_HEADER_MINOR_VERSION (header);
667
668 if (major == 0 && minor == 2)
669 return gst_dp_event_from_packet_0_2 (header_length, header, payload);
670 else if (major == 1 && minor == 0)
671 return gst_dp_event_from_packet_1_0 (header_length, header, payload);
672 else {
673 GST_ERROR ("Unknown GDP version %d.%d", major, minor);
674 return NULL;
675 }
676 }
677
678 /**
679 * gst_dp_validate_header:
680 * @header_length: the length of the packet header
681 * @header: the byte array of the packet header
682 *
683 * Validates the given packet header by checking the CRC checksum.
684 *
685 * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
686 */
687 gboolean
gst_dp_validate_header(guint header_length,const guint8 * header)688 gst_dp_validate_header (guint header_length, const guint8 * header)
689 {
690 guint16 crc_read, crc_calculated;
691
692 g_return_val_if_fail (header != NULL, FALSE);
693 g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
694
695 if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_HEADER))
696 return TRUE;
697
698 crc_read = GST_DP_HEADER_CRC_HEADER (header);
699
700 /* don't include the last two crc fields for the crc check */
701 crc_calculated = gst_dp_crc (header, header_length - 4);
702 if (crc_read != crc_calculated)
703 goto crc_error;
704
705 GST_LOG ("header crc validation: %02x", crc_read);
706 return TRUE;
707
708 /* ERRORS */
709 crc_error:
710 {
711 GST_WARNING ("header crc mismatch: read %02x, calculated %02x", crc_read,
712 crc_calculated);
713 return FALSE;
714 }
715 }
716
717 /**
718 * gst_dp_validate_payload:
719 * @header_length: the length of the packet header
720 * @header: the byte array of the packet header
721 * @payload: the byte array of the packet payload
722 *
723 * Validates the given packet payload using the given packet header
724 * by checking the CRC checksum.
725 *
726 * Returns: %TRUE if the CRC matches, or no CRC checksum is present.
727 */
728 gboolean
gst_dp_validate_payload(guint header_length,const guint8 * header,const guint8 * payload)729 gst_dp_validate_payload (guint header_length, const guint8 * header,
730 const guint8 * payload)
731 {
732 guint16 crc_read, crc_calculated;
733
734 g_return_val_if_fail (header != NULL, FALSE);
735 g_return_val_if_fail (header_length >= GST_DP_HEADER_LENGTH, FALSE);
736
737 if (!(GST_DP_HEADER_FLAGS (header) & GST_DP_HEADER_FLAG_CRC_PAYLOAD))
738 return TRUE;
739
740 crc_read = GST_DP_HEADER_CRC_PAYLOAD (header);
741 crc_calculated = gst_dp_crc (payload, GST_DP_HEADER_PAYLOAD_LENGTH (header));
742 if (crc_read != crc_calculated)
743 goto crc_error;
744
745 GST_LOG ("payload crc validation: %02x", crc_read);
746 return TRUE;
747
748 /* ERRORS */
749 crc_error:
750 {
751 GST_WARNING ("payload crc mismatch: read %02x, calculated %02x", crc_read,
752 crc_calculated);
753 return FALSE;
754 }
755 }
756
757 /**
758 * gst_dp_validate_packet:
759 * @header_length: the length of the packet header
760 * @header: the byte array of the packet header
761 * @payload: the byte array of the packet payload
762 *
763 * Validates the given packet by checking version information and checksums.
764 *
765 * Returns: %TRUE if the packet validates.
766 */
767 gboolean
gst_dp_validate_packet(guint header_length,const guint8 * header,const guint8 * payload)768 gst_dp_validate_packet (guint header_length, const guint8 * header,
769 const guint8 * payload)
770 {
771 if (!gst_dp_validate_header (header_length, header))
772 return FALSE;
773 if (!gst_dp_validate_payload (header_length, header, payload))
774 return FALSE;
775
776 return TRUE;
777 }
778