1 /* GStreamer
2 * Copyright (C) 2008-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <gst/gst.h>
25 #include <gst/base/gstbytewriter.h>
26 #include <string.h>
27
28 #include "mxftypes.h"
29
30 GST_DEBUG_CATEGORY_EXTERN (mxf_debug);
31 #define GST_CAT_DEFAULT mxf_debug
32
33 gboolean
mxf_is_mxf_packet(const MXFUL * ul)34 mxf_is_mxf_packet (const MXFUL * ul)
35 {
36 return mxf_ul_is_subclass (MXF_UL (SMPTE), ul);
37 }
38
39 /* SMPTE 377M 6.1: Check if this is a valid partition pack */
40 gboolean
mxf_is_partition_pack(const MXFUL * ul)41 mxf_is_partition_pack (const MXFUL * ul)
42 {
43 if (mxf_ul_is_subclass (MXF_UL (PARTITION_PACK), ul) &&
44 ul->u[13] >= 0x02 && ul->u[13] <= 0x04 &&
45 ul->u[14] < 0x05 && ul->u[15] == 0x00)
46 return TRUE;
47
48 return FALSE;
49 }
50
51 /* SMPTE 377M 6.2: header partition pack has byte 14 == 0x02 */
52 gboolean
mxf_is_header_partition_pack(const MXFUL * ul)53 mxf_is_header_partition_pack (const MXFUL * ul)
54 {
55 if (mxf_is_partition_pack (ul) && ul->u[13] == 0x02)
56 return TRUE;
57
58 return FALSE;
59 }
60
61 /* SMPTE 377M 6.3: body partition pack has byte 14 == 0x03 */
62 gboolean
mxf_is_body_partition_pack(const MXFUL * ul)63 mxf_is_body_partition_pack (const MXFUL * ul)
64 {
65 if (mxf_is_partition_pack (ul) && ul->u[13] == 0x03)
66 return TRUE;
67
68 return FALSE;
69 }
70
71 /* SMPTE 377M 6.4: footer partition pack has byte 14 == 0x04 */
72 gboolean
mxf_is_footer_partition_pack(const MXFUL * ul)73 mxf_is_footer_partition_pack (const MXFUL * ul)
74 {
75 if (mxf_is_partition_pack (ul) && ul->u[13] == 0x04)
76 return TRUE;
77
78 return FALSE;
79 }
80
81 gboolean
mxf_is_fill(const MXFUL * ul)82 mxf_is_fill (const MXFUL * ul)
83 {
84 return (mxf_ul_is_subclass (MXF_UL (FILL), ul));
85 }
86
87 gboolean
mxf_is_primer_pack(const MXFUL * ul)88 mxf_is_primer_pack (const MXFUL * ul)
89 {
90 return (mxf_ul_is_subclass (MXF_UL (PRIMER_PACK), ul));
91 }
92
93 gboolean
mxf_is_metadata(const MXFUL * ul)94 mxf_is_metadata (const MXFUL * ul)
95 {
96 return (mxf_ul_is_subclass (MXF_UL (METADATA), ul));
97 }
98
99 /* SMPTE 377M 8.7.3 */
100 gboolean
mxf_is_descriptive_metadata(const MXFUL * ul)101 mxf_is_descriptive_metadata (const MXFUL * ul)
102 {
103 return (mxf_ul_is_subclass (MXF_UL (DESCRIPTIVE_METADATA), ul));
104 }
105
106 gboolean
mxf_is_random_index_pack(const MXFUL * ul)107 mxf_is_random_index_pack (const MXFUL * ul)
108 {
109 return (mxf_ul_is_subclass (MXF_UL (RANDOM_INDEX_PACK), ul));
110 }
111
112 gboolean
mxf_is_index_table_segment(const MXFUL * ul)113 mxf_is_index_table_segment (const MXFUL * ul)
114 {
115 return (mxf_ul_is_subclass (MXF_UL (INDEX_TABLE_SEGMENT), ul));
116 }
117
118 /* SMPTE 379M 6.2.1 */
119 gboolean
mxf_is_generic_container_system_item(const MXFUL * ul)120 mxf_is_generic_container_system_item (const MXFUL * ul)
121 {
122 return (mxf_ul_is_subclass (MXF_UL (GENERIC_CONTAINER_SYSTEM_ITEM), ul) &&
123 (ul->u[12] == 0x04 || ul->u[12] == 0x14));
124 }
125
126 /* SMPTE 379M 7.1 */
127 gboolean
mxf_is_generic_container_essence_element(const MXFUL * ul)128 mxf_is_generic_container_essence_element (const MXFUL * ul)
129 {
130 return (mxf_ul_is_subclass (MXF_UL (GENERIC_CONTAINER_ESSENCE_ELEMENT), ul)
131 && (ul->u[12] == 0x05 || ul->u[12] == 0x06
132 || ul->u[12] == 0x07 || ul->u[12] == 0x15
133 || ul->u[12] == 0x16 || ul->u[12] == 0x17 || ul->u[12] == 0x18));
134 }
135
136 /* SMPTE 379M 8 */
137 gboolean
mxf_is_generic_container_essence_container_label(const MXFUL * ul)138 mxf_is_generic_container_essence_container_label (const MXFUL * ul)
139 {
140 return (mxf_ul_is_subclass (MXF_UL
141 (GENERIC_CONTAINER_ESSENCE_CONTAINER_LABEL), ul) && (ul->u[12] == 0x01
142 || ul->u[12] == 0x02));
143 }
144
145 /* Essence container label found in files generated by Avid */
146 gboolean
mxf_is_avid_essence_container_label(const MXFUL * ul)147 mxf_is_avid_essence_container_label (const MXFUL * ul)
148 {
149 return (mxf_ul_is_subclass (MXF_UL (AVID_ESSENCE_CONTAINER_ESSENCE_LABEL),
150 ul));
151 }
152
153 /* Essence element key found in files generated by Avid */
154 gboolean
mxf_is_avid_essence_container_essence_element(const MXFUL * ul)155 mxf_is_avid_essence_container_essence_element (const MXFUL * ul)
156 {
157 return (mxf_ul_is_subclass (MXF_UL (AVID_ESSENCE_CONTAINER_ESSENCE_ELEMENT),
158 ul));
159 }
160
161 guint
mxf_ber_encode_size(guint size,guint8 ber[9])162 mxf_ber_encode_size (guint size, guint8 ber[9])
163 {
164 guint8 slen, i;
165 guint8 tmp[8];
166
167 memset (ber, 0, 9);
168
169 if (size <= 127) {
170 ber[0] = size;
171 return 1;
172 }
173
174 slen = 0;
175 while (size > 0) {
176 tmp[slen] = size & 0xff;
177 size >>= 8;
178 slen++;
179 }
180
181 ber[0] = 0x80 | slen;
182 for (i = 0; i < slen; i++) {
183 ber[i + 1] = tmp[slen - i - 1];
184 }
185
186 return slen + 1;
187 }
188
189 GstBuffer *
mxf_fill_to_buffer(guint size)190 mxf_fill_to_buffer (guint size)
191 {
192 GstBuffer *ret;
193 GstMapInfo map;
194 guint slen;
195 guint8 ber[9];
196
197 slen = mxf_ber_encode_size (size, ber);
198
199 ret = gst_buffer_new_and_alloc (16 + slen + size);
200 gst_buffer_map (ret, &map, GST_MAP_WRITE);
201
202 memcpy (map.data, MXF_UL (FILL), 16);
203 memcpy (map.data + 16, &ber, slen);
204 memset (map.data + slen, 0, size);
205
206 gst_buffer_unmap (ret, &map);
207
208 return ret;
209 }
210
211 void
mxf_uuid_init(MXFUUID * uuid,GHashTable * hashtable)212 mxf_uuid_init (MXFUUID * uuid, GHashTable * hashtable)
213 {
214 guint i;
215
216 do {
217 for (i = 0; i < 4; i++)
218 GST_WRITE_UINT32_BE (&uuid->u[i * 4], g_random_int ());
219 uuid->u[6] = 0x40 | (uuid->u[6] & 0x0f);
220 uuid->u[8] = (uuid->u[8] & 0xbf) | 0x80;
221 } while (hashtable && (mxf_uuid_is_zero (uuid) ||
222 g_hash_table_lookup_extended (hashtable, uuid, NULL, NULL)));
223 }
224
225 gboolean
mxf_uuid_is_equal(const MXFUUID * a,const MXFUUID * b)226 mxf_uuid_is_equal (const MXFUUID * a, const MXFUUID * b)
227 {
228 g_return_val_if_fail (a != NULL, FALSE);
229 g_return_val_if_fail (b != NULL, FALSE);
230
231 return (memcmp (a, b, 16) == 0);
232 }
233
234 gboolean
mxf_uuid_is_zero(const MXFUUID * a)235 mxf_uuid_is_zero (const MXFUUID * a)
236 {
237 static const guint8 zero[16] = { 0x00, };
238
239 g_return_val_if_fail (a != NULL, FALSE);
240
241 return (memcmp (a, zero, 16) == 0);
242 }
243
244 guint
mxf_uuid_hash(const MXFUUID * uuid)245 mxf_uuid_hash (const MXFUUID * uuid)
246 {
247 guint32 ret = 0;
248 guint i;
249
250 g_return_val_if_fail (uuid != NULL, 0);
251
252 for (i = 0; i < 4; i++)
253 ret ^= GST_READ_UINT32_BE (uuid->u + i * 4);
254
255 return ret;
256 }
257
258 gchar *
mxf_uuid_to_string(const MXFUUID * uuid,gchar str[48])259 mxf_uuid_to_string (const MXFUUID * uuid, gchar str[48])
260 {
261 gchar *ret = str;
262
263 g_return_val_if_fail (uuid != NULL, NULL);
264
265 if (ret == NULL)
266 ret = g_malloc (48);
267
268 g_snprintf (ret, 48,
269 "%02x.%02x.%02x.%02x."
270 "%02x.%02x.%02x.%02x."
271 "%02x.%02x.%02x.%02x."
272 "%02x.%02x.%02x.%02x",
273 uuid->u[0], uuid->u[1], uuid->u[2], uuid->u[3],
274 uuid->u[4], uuid->u[5], uuid->u[6], uuid->u[7],
275 uuid->u[8], uuid->u[9], uuid->u[10], uuid->u[11],
276 uuid->u[12], uuid->u[13], uuid->u[14], uuid->u[15]);
277
278 return ret;
279 }
280
281 MXFUUID *
mxf_uuid_from_string(const gchar * str,MXFUUID * uuid)282 mxf_uuid_from_string (const gchar * str, MXFUUID * uuid)
283 {
284 MXFUUID *ret = uuid;
285 gint len;
286 guint i, j;
287
288 g_return_val_if_fail (str != NULL, NULL);
289
290 len = strlen (str);
291 if (len != 47) {
292 GST_ERROR ("Invalid UUID string length %d, should be 47", len);
293 return NULL;
294 }
295
296 if (ret == NULL)
297 ret = g_new0 (MXFUUID, 1);
298
299 memset (ret, 0, 16);
300
301 for (i = 0, j = 0; i < 16; i++) {
302 if (!g_ascii_isxdigit (str[j]) ||
303 !g_ascii_isxdigit (str[j + 1]) ||
304 (str[j + 2] != '.' && str[j + 2] != '\0')) {
305 GST_ERROR ("Invalid UL string '%s'", str);
306 if (uuid == NULL)
307 g_free (ret);
308 return NULL;
309 }
310
311 ret->u[i] = (g_ascii_xdigit_value (str[j]) << 4) |
312 (g_ascii_xdigit_value (str[j + 1]));
313 j += 3;
314 }
315 return ret;
316 }
317
318 gboolean
mxf_uuid_array_parse(MXFUUID ** array,guint32 * count,const guint8 * data,guint size)319 mxf_uuid_array_parse (MXFUUID ** array, guint32 * count, const guint8 * data,
320 guint size)
321 {
322 guint32 element_count, element_size;
323 guint i;
324
325 g_return_val_if_fail (array != NULL, FALSE);
326 g_return_val_if_fail (count != NULL, FALSE);
327
328 if (size < 8)
329 return FALSE;
330
331 g_return_val_if_fail (data != NULL, FALSE);
332
333 element_count = GST_READ_UINT32_BE (data);
334 data += 4;
335 size -= 4;
336
337 if (element_count == 0) {
338 *array = NULL;
339 *count = 0;
340 return TRUE;
341 }
342
343 element_size = GST_READ_UINT32_BE (data);
344 data += 4;
345 size -= 4;
346
347 if (element_size != 16) {
348 *array = NULL;
349 *count = 0;
350 return FALSE;
351 }
352
353 if (element_count > size / 16) {
354 *array = NULL;
355 *count = 0;
356 return FALSE;
357 }
358
359 *array = g_new (MXFUUID, element_count);
360 *count = element_count;
361
362 for (i = 0; i < element_count; i++) {
363 memcpy (&((*array)[i]), data, 16);
364 data += 16;
365 }
366
367 return TRUE;
368 }
369
370 gboolean
mxf_umid_is_equal(const MXFUMID * a,const MXFUMID * b)371 mxf_umid_is_equal (const MXFUMID * a, const MXFUMID * b)
372 {
373 return (memcmp (a, b, 32) == 0);
374 }
375
376 gboolean
mxf_umid_is_zero(const MXFUMID * umid)377 mxf_umid_is_zero (const MXFUMID * umid)
378 {
379 static const MXFUMID zero = { {0,} };
380
381 return (memcmp (umid, &zero, 32) == 0);
382 }
383
384 gchar *
mxf_umid_to_string(const MXFUMID * umid,gchar str[96])385 mxf_umid_to_string (const MXFUMID * umid, gchar str[96])
386 {
387 g_return_val_if_fail (umid != NULL, NULL);
388 g_return_val_if_fail (str != NULL, NULL);
389
390 g_snprintf (str, 96,
391 "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x."
392 "%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
393 umid->u[0], umid->u[1], umid->u[2], umid->u[3], umid->u[4], umid->u[5],
394 umid->u[6], umid->u[7], umid->u[8], umid->u[9], umid->u[10], umid->u[11],
395 umid->u[12], umid->u[13], umid->u[14], umid->u[15],
396 umid->u[16],
397 umid->u[17],
398 umid->u[18],
399 umid->u[19],
400 umid->u[20],
401 umid->u[21],
402 umid->u[22],
403 umid->u[23],
404 umid->u[24],
405 umid->u[25],
406 umid->u[26], umid->u[27], umid->u[28], umid->u[29], umid->u[30],
407 umid->u[31]
408 );
409
410 return str;
411 }
412
413 MXFUMID *
mxf_umid_from_string(const gchar * str,MXFUMID * umid)414 mxf_umid_from_string (const gchar * str, MXFUMID * umid)
415 {
416 gint len;
417 guint i, j;
418
419 g_return_val_if_fail (str != NULL, NULL);
420 len = strlen (str);
421
422 memset (umid, 0, 32);
423
424 if (len != 95) {
425 GST_ERROR ("Invalid UMID string length %d", len);
426 return NULL;
427 }
428
429 for (i = 0, j = 0; i < 32; i++) {
430 if (!g_ascii_isxdigit (str[j]) ||
431 !g_ascii_isxdigit (str[j + 1]) ||
432 (str[j + 2] != '.' && str[j + 2] != '\0')) {
433 GST_ERROR ("Invalid UMID string '%s'", str);
434 return NULL;
435 }
436
437 umid->u[i] =
438 (g_ascii_xdigit_value (str[j]) << 4) | (g_ascii_xdigit_value (str[j +
439 1]));
440 j += 3;
441 }
442 return umid;
443 }
444
445 void
mxf_umid_init(MXFUMID * umid)446 mxf_umid_init (MXFUMID * umid)
447 {
448 guint i;
449 guint32 tmp;
450
451 /* SMPTE S330M 5.1.1:
452 * UMID Identifier
453 */
454 umid->u[0] = 0x06;
455 umid->u[1] = 0x0a;
456 umid->u[2] = 0x2b;
457 umid->u[3] = 0x34;
458 umid->u[4] = 0x01;
459 umid->u[5] = 0x01;
460 umid->u[6] = 0x01;
461 umid->u[7] = 0x05; /* version, see RP210 */
462 umid->u[8] = 0x01;
463 umid->u[9] = 0x01;
464 umid->u[10] = 0x0d; /* mixed group of components in a single container */
465
466 /* - UUID/UL method for material number
467 * - 24 bit PRG for instance number
468 */
469 umid->u[11] = 0x20 | 0x02;
470
471 /* Length of remaining data */
472 umid->u[12] = 0x13;
473
474 /* Instance number */
475 tmp = g_random_int ();
476 umid->u[13] = (tmp >> 24) & 0xff;
477 umid->u[14] = (tmp >> 16) & 0xff;
478 umid->u[15] = (tmp >> 8) & 0xff;
479
480 /* Material number: ISO UUID Version 4 */
481 for (i = 16; i < 32; i += 4)
482 GST_WRITE_UINT32_BE (&umid->u[i], g_random_int ());
483
484 umid->u[16 + 6] &= 0x0f;
485 umid->u[16 + 6] |= 0x40;
486
487 umid->u[16 + 8] &= 0x3f;
488 umid->u[16 + 8] |= 0x80;
489 }
490
491 gboolean
mxf_timestamp_parse(MXFTimestamp * timestamp,const guint8 * data,guint size)492 mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, guint size)
493 {
494 g_return_val_if_fail (timestamp != NULL, FALSE);
495
496 memset (timestamp, 0, sizeof (MXFTimestamp));
497
498 if (size < 8)
499 return FALSE;
500
501 g_return_val_if_fail (data != NULL, FALSE);
502
503 timestamp->year = GST_READ_UINT16_BE (data);
504 timestamp->month = GST_READ_UINT8 (data + 2);
505 timestamp->day = GST_READ_UINT8 (data + 3);
506 timestamp->hour = GST_READ_UINT8 (data + 4);
507 timestamp->minute = GST_READ_UINT8 (data + 5);
508 timestamp->second = GST_READ_UINT8 (data + 6);
509 timestamp->msecond = (GST_READ_UINT8 (data + 7) * 1000) / 256;
510
511 return TRUE;
512 }
513
514 /* SMPTE 377M 3.3: A value of 0 for every field means unknown timestamp */
515 gboolean
mxf_timestamp_is_unknown(const MXFTimestamp * a)516 mxf_timestamp_is_unknown (const MXFTimestamp * a)
517 {
518 static const MXFTimestamp unknown = { 0, 0, 0, 0, 0, 0, 0 };
519
520 return (memcmp (a, &unknown, sizeof (MXFTimestamp)) == 0);
521 }
522
523 gint
mxf_timestamp_compare(const MXFTimestamp * a,const MXFTimestamp * b)524 mxf_timestamp_compare (const MXFTimestamp * a, const MXFTimestamp * b)
525 {
526 gint diff;
527
528 if ((diff = a->year - b->year) != 0)
529 return diff;
530 else if ((diff = a->month - b->month) != 0)
531 return diff;
532 else if ((diff = a->day - b->day) != 0)
533 return diff;
534 else if ((diff = a->hour - b->hour) != 0)
535 return diff;
536 else if ((diff = a->minute - b->minute) != 0)
537 return diff;
538 else if ((diff = a->second - b->second) != 0)
539 return diff;
540 else if ((diff = a->msecond - b->msecond) != 0)
541 return diff;
542 else
543 return 0;
544 }
545
546 gchar *
mxf_timestamp_to_string(const MXFTimestamp * t,gchar str[32])547 mxf_timestamp_to_string (const MXFTimestamp * t, gchar str[32])
548 {
549 g_snprintf (str, 32,
550 "%04d-%02u-%02u %02u:%02u:%02u.%03u", t->year, t->month,
551 t->day, t->hour, t->minute, t->second, t->msecond);
552 return str;
553 }
554
555 void
mxf_timestamp_set_now(MXFTimestamp * timestamp)556 mxf_timestamp_set_now (MXFTimestamp * timestamp)
557 {
558 gint64 now;
559 time_t t;
560 struct tm *tm;
561
562 #ifdef HAVE_GMTIME_R
563 struct tm tm_;
564 #endif
565
566 now = g_get_real_time ();
567 t = now / G_USEC_PER_SEC;
568
569 #ifdef HAVE_GMTIME_R
570 tm = gmtime_r (&t, &tm_);
571 #else
572 tm = gmtime (&t);
573 #endif
574
575 timestamp->year = tm->tm_year + 1900;
576 timestamp->month = tm->tm_mon;
577 timestamp->day = tm->tm_mday;
578 timestamp->hour = tm->tm_hour;
579 timestamp->minute = tm->tm_min;
580 timestamp->second = tm->tm_sec;
581 timestamp->msecond = now / 1000;
582 }
583
584 void
mxf_timestamp_write(const MXFTimestamp * timestamp,guint8 * data)585 mxf_timestamp_write (const MXFTimestamp * timestamp, guint8 * data)
586 {
587 GST_WRITE_UINT16_BE (data, timestamp->year);
588 GST_WRITE_UINT8 (data + 2, timestamp->month);
589 GST_WRITE_UINT8 (data + 3, timestamp->day);
590 GST_WRITE_UINT8 (data + 4, timestamp->hour);
591 GST_WRITE_UINT8 (data + 5, timestamp->minute);
592 GST_WRITE_UINT8 (data + 6, timestamp->second);
593 GST_WRITE_UINT8 (data + 7, (timestamp->msecond * 256) / 1000);
594 }
595
596 gboolean
mxf_fraction_parse(MXFFraction * fraction,const guint8 * data,guint size)597 mxf_fraction_parse (MXFFraction * fraction, const guint8 * data, guint size)
598 {
599 g_return_val_if_fail (fraction != NULL, FALSE);
600
601 memset (fraction, 0, sizeof (MXFFraction));
602
603 if (size < 8)
604 return FALSE;
605
606 g_return_val_if_fail (data != NULL, FALSE);
607
608 fraction->n = GST_READ_UINT32_BE (data);
609 fraction->d = GST_READ_UINT32_BE (data + 4);
610
611 return TRUE;
612 }
613
614 gdouble
mxf_fraction_to_double(const MXFFraction * fraction)615 mxf_fraction_to_double (const MXFFraction * fraction)
616 {
617 return ((gdouble) fraction->n) / ((gdouble) fraction->d);
618 }
619
620 gchar *
mxf_utf16_to_utf8(const guint8 * data,guint size)621 mxf_utf16_to_utf8 (const guint8 * data, guint size)
622 {
623 gchar *ret;
624 GError *error = NULL;
625
626 ret =
627 g_convert ((const gchar *) data, size, "UTF-8", "UTF-16BE", NULL, NULL,
628 &error);
629
630 if (ret == NULL) {
631 GST_WARNING ("UTF-16-BE to UTF-8 conversion failed: %s", error->message);
632 g_error_free (error);
633 return NULL;
634 }
635
636 return ret;
637 }
638
639 guint8 *
mxf_utf8_to_utf16(const gchar * str,guint16 * size)640 mxf_utf8_to_utf16 (const gchar * str, guint16 * size)
641 {
642 guint8 *ret;
643 GError *error = NULL;
644 gsize s;
645
646 g_return_val_if_fail (size != NULL, NULL);
647
648 if (str == NULL) {
649 *size = 0;
650 return NULL;
651 }
652
653 ret = (guint8 *)
654 g_convert_with_fallback (str, -1, "UTF-16BE", "UTF-8", (char *) "*", NULL,
655 &s, &error);
656
657 if (ret == NULL) {
658 GST_WARNING ("UTF-16-BE to UTF-8 conversion failed: %s", error->message);
659 g_error_free (error);
660 *size = 0;
661 return NULL;
662 }
663
664 *size = s;
665 return (guint8 *) ret;
666 }
667
668 gboolean
mxf_product_version_parse(MXFProductVersion * product_version,const guint8 * data,guint size)669 mxf_product_version_parse (MXFProductVersion * product_version,
670 const guint8 * data, guint size)
671 {
672 g_return_val_if_fail (product_version != NULL, FALSE);
673
674 memset (product_version, 0, sizeof (MXFProductVersion));
675
676 if (size < 9)
677 return FALSE;
678
679 g_return_val_if_fail (data != NULL, FALSE);
680
681 product_version->major = GST_READ_UINT16_BE (data);
682 product_version->minor = GST_READ_UINT16_BE (data + 2);
683 product_version->patch = GST_READ_UINT16_BE (data + 4);
684 product_version->build = GST_READ_UINT16_BE (data + 6);
685
686 /* Avid writes a 9 byte product version */
687 if (size == 9)
688 product_version->release = GST_READ_UINT8 (data + 8);
689 else
690 product_version->release = GST_READ_UINT16_BE (data + 8);
691
692 return TRUE;
693 }
694
695 gboolean
mxf_product_version_is_valid(const MXFProductVersion * version)696 mxf_product_version_is_valid (const MXFProductVersion * version)
697 {
698 static const guint8 null[sizeof (MXFProductVersion)] = { 0, };
699
700 return (memcmp (version, &null, sizeof (MXFProductVersion)) == 0);
701 }
702
703 void
mxf_product_version_write(const MXFProductVersion * version,guint8 * data)704 mxf_product_version_write (const MXFProductVersion * version, guint8 * data)
705 {
706 GST_WRITE_UINT16_BE (data, version->major);
707 GST_WRITE_UINT16_BE (data + 2, version->minor);
708 GST_WRITE_UINT16_BE (data + 4, version->patch);
709 GST_WRITE_UINT16_BE (data + 6, version->build);
710 GST_WRITE_UINT16_BE (data + 8, version->release);
711 }
712
713 void
mxf_op_set_atom(MXFUL * ul,gboolean single_sourceclip,gboolean single_essence_track)714 mxf_op_set_atom (MXFUL * ul, gboolean single_sourceclip,
715 gboolean single_essence_track)
716 {
717 memcpy (&ul->u, MXF_UL (OPERATIONAL_PATTERN_IDENTIFICATION), 12);
718 ul->u[12] = 0x10;
719 ul->u[13] = 0;
720
721 if (!single_sourceclip)
722 ul->u[13] |= 0x80;
723
724 if (!single_essence_track)
725 ul->u[13] |= 0x40;
726
727 ul->u[14] = 0;
728 ul->u[15] = 0;
729 }
730
731 void
mxf_op_set_generalized(MXFUL * ul,MXFOperationalPattern pattern,gboolean internal_essence,gboolean streamable,gboolean single_track)732 mxf_op_set_generalized (MXFUL * ul, MXFOperationalPattern pattern,
733 gboolean internal_essence, gboolean streamable, gboolean single_track)
734 {
735 g_return_if_fail (pattern >= MXF_OP_1a);
736
737 memcpy (&ul->u, MXF_UL (OPERATIONAL_PATTERN_IDENTIFICATION), 12);
738
739 if (pattern == MXF_OP_1a || pattern == MXF_OP_1b || pattern == MXF_OP_1c)
740 ul->u[12] = 0x01;
741 else if (pattern == MXF_OP_2a || pattern == MXF_OP_2b || pattern == MXF_OP_2c)
742 ul->u[12] = 0x02;
743 else if (pattern == MXF_OP_3a || pattern == MXF_OP_3b || pattern == MXF_OP_3c)
744 ul->u[12] = 0x03;
745
746 if (pattern == MXF_OP_1a || pattern == MXF_OP_2a || pattern == MXF_OP_3a)
747 ul->u[13] = 0x01;
748 else if (pattern == MXF_OP_1b || pattern == MXF_OP_2b || pattern == MXF_OP_3b)
749 ul->u[13] = 0x02;
750 else if (pattern == MXF_OP_1c || pattern == MXF_OP_2c || pattern == MXF_OP_3c)
751 ul->u[13] = 0x02;
752
753 ul->u[14] = 0x08;
754 if (!internal_essence)
755 ul->u[14] |= 0x04;
756 if (!streamable)
757 ul->u[14] |= 0x02;
758 if (!single_track)
759 ul->u[14] |= 0x01;
760
761 ul->u[15] = 0;
762 }
763
764 /* SMPTE 377M 6.1, Table 2 */
765 gboolean
mxf_partition_pack_parse(const MXFUL * ul,MXFPartitionPack * pack,const guint8 * data,guint size)766 mxf_partition_pack_parse (const MXFUL * ul, MXFPartitionPack * pack,
767 const guint8 * data, guint size)
768 {
769 #ifndef GST_DISABLE_GST_DEBUG
770 guint i;
771 gchar str[48];
772 #endif
773
774 if (size < 84)
775 return FALSE;
776
777 g_return_val_if_fail (data != NULL, FALSE);
778
779 memset (pack, 0, sizeof (MXFPartitionPack));
780
781 GST_DEBUG ("Parsing partition pack:");
782
783 if (ul->u[13] == 0x02)
784 pack->type = MXF_PARTITION_PACK_HEADER;
785 else if (ul->u[13] == 0x03)
786 pack->type = MXF_PARTITION_PACK_BODY;
787 else if (ul->u[13] == 0x04)
788 pack->type = MXF_PARTITION_PACK_FOOTER;
789
790 GST_DEBUG (" type = %s",
791 (pack->type == MXF_PARTITION_PACK_HEADER) ? "header" : (pack->type ==
792 MXF_PARTITION_PACK_BODY) ? "body" : "footer");
793
794 pack->closed = (ul->u[14] == 0x02 || ul->u[14] == 0x04);
795 pack->complete = (ul->u[14] == 0x03 || ul->u[14] == 0x04);
796
797 GST_DEBUG (" closed = %s, complete = %s", (pack->closed) ? "yes" : "no",
798 (pack->complete) ? "yes" : "no");
799
800 pack->major_version = GST_READ_UINT16_BE (data);
801 if (pack->major_version != 1)
802 goto error;
803 data += 2;
804 size -= 2;
805
806 pack->minor_version = GST_READ_UINT16_BE (data);
807 data += 2;
808 size -= 2;
809
810 GST_DEBUG (" MXF version = %u.%u", pack->major_version, pack->minor_version);
811
812 pack->kag_size = GST_READ_UINT32_BE (data);
813 data += 4;
814 size -= 4;
815
816 GST_DEBUG (" KAG size = %u", pack->kag_size);
817
818 pack->this_partition = GST_READ_UINT64_BE (data);
819 data += 8;
820 size -= 8;
821
822 GST_DEBUG (" this partition offset = %" G_GUINT64_FORMAT,
823 pack->this_partition);
824
825 pack->prev_partition = GST_READ_UINT64_BE (data);
826 data += 8;
827 size -= 8;
828
829 GST_DEBUG (" previous partition offset = %" G_GUINT64_FORMAT,
830 pack->prev_partition);
831
832 pack->footer_partition = GST_READ_UINT64_BE (data);
833 data += 8;
834 size -= 8;
835
836 GST_DEBUG (" footer partition offset = %" G_GUINT64_FORMAT,
837 pack->footer_partition);
838
839 pack->header_byte_count = GST_READ_UINT64_BE (data);
840 data += 8;
841 size -= 8;
842
843 GST_DEBUG (" header byte count = %" G_GUINT64_FORMAT,
844 pack->header_byte_count);
845
846 pack->index_byte_count = GST_READ_UINT64_BE (data);
847 data += 8;
848 size -= 8;
849
850 pack->index_sid = GST_READ_UINT32_BE (data);
851 data += 4;
852 size -= 4;
853
854 GST_DEBUG (" index sid = %u, size = %" G_GUINT64_FORMAT, pack->index_sid,
855 pack->index_byte_count);
856
857 pack->body_offset = GST_READ_UINT64_BE (data);
858 data += 8;
859 size -= 8;
860
861 pack->body_sid = GST_READ_UINT32_BE (data);
862 data += 4;
863 size -= 4;
864
865 GST_DEBUG (" body sid = %u, offset = %" G_GUINT64_FORMAT, pack->body_sid,
866 pack->body_offset);
867
868 memcpy (&pack->operational_pattern, data, 16);
869 data += 16;
870 size -= 16;
871
872 GST_DEBUG (" operational pattern = %s",
873 mxf_ul_to_string (&pack->operational_pattern, str));
874
875 if (!mxf_ul_array_parse (&pack->essence_containers,
876 &pack->n_essence_containers, data, size))
877 goto error;
878
879 #ifndef GST_DISABLE_GST_DEBUG
880 GST_DEBUG (" number of essence containers = %u", pack->n_essence_containers);
881 if (pack->n_essence_containers) {
882 for (i = 0; i < pack->n_essence_containers; i++) {
883 GST_DEBUG (" essence container %u = %s", i,
884 mxf_ul_to_string (&pack->essence_containers[i], str));
885 }
886 }
887 #endif
888
889 return TRUE;
890
891 error:
892 GST_ERROR ("Invalid partition pack");
893
894 mxf_partition_pack_reset (pack);
895 return FALSE;
896 }
897
898 void
mxf_partition_pack_reset(MXFPartitionPack * pack)899 mxf_partition_pack_reset (MXFPartitionPack * pack)
900 {
901 g_return_if_fail (pack != NULL);
902
903 g_free (pack->essence_containers);
904
905 memset (pack, 0, sizeof (MXFPartitionPack));
906 }
907
908 GstBuffer *
mxf_partition_pack_to_buffer(const MXFPartitionPack * pack)909 mxf_partition_pack_to_buffer (const MXFPartitionPack * pack)
910 {
911 guint slen;
912 guint8 ber[9];
913 GstBuffer *ret;
914 GstMapInfo map;
915 guint8 *data;
916 guint i;
917 guint size =
918 8 + 16 * pack->n_essence_containers + 16 + 4 + 8 + 4 + 8 + 8 + 8 + 8 + 8 +
919 4 + 2 + 2;
920
921 slen = mxf_ber_encode_size (size, ber);
922
923 ret = gst_buffer_new_and_alloc (16 + slen + size);
924 gst_buffer_map (ret, &map, GST_MAP_WRITE);
925
926 memcpy (map.data, MXF_UL (PARTITION_PACK), 13);
927 if (pack->type == MXF_PARTITION_PACK_HEADER)
928 map.data[13] = 0x02;
929 else if (pack->type == MXF_PARTITION_PACK_BODY)
930 map.data[13] = 0x03;
931 else if (pack->type == MXF_PARTITION_PACK_FOOTER)
932 map.data[13] = 0x04;
933 map.data[14] = 0;
934 if (pack->complete)
935 map.data[14] |= 0x02;
936 if (pack->closed)
937 map.data[14] |= 0x01;
938 map.data[14] += 1;
939 map.data[15] = 0;
940 memcpy (map.data + 16, &ber, slen);
941
942 data = map.data + 16 + slen;
943
944 GST_WRITE_UINT16_BE (data, pack->major_version);
945 GST_WRITE_UINT16_BE (data + 2, pack->minor_version);
946 data += 4;
947
948 GST_WRITE_UINT32_BE (data, pack->kag_size);
949 data += 4;
950
951 GST_WRITE_UINT64_BE (data, pack->this_partition);
952 data += 8;
953
954 GST_WRITE_UINT64_BE (data, pack->prev_partition);
955 data += 8;
956
957 GST_WRITE_UINT64_BE (data, pack->footer_partition);
958 data += 8;
959
960 GST_WRITE_UINT64_BE (data, pack->header_byte_count);
961 data += 8;
962
963 GST_WRITE_UINT64_BE (data, pack->index_byte_count);
964 data += 8;
965
966 GST_WRITE_UINT32_BE (data, pack->index_sid);
967 data += 4;
968
969 GST_WRITE_UINT64_BE (data, pack->body_offset);
970 data += 8;
971
972 GST_WRITE_UINT32_BE (data, pack->body_sid);
973 data += 4;
974
975 memcpy (data, &pack->operational_pattern, 16);
976 data += 16;
977
978 GST_WRITE_UINT32_BE (data, pack->n_essence_containers);
979 GST_WRITE_UINT32_BE (data + 4, 16);
980 data += 8;
981
982 for (i = 0; i < pack->n_essence_containers; i++)
983 memcpy (data + 16 * i, &pack->essence_containers[i], 16);
984
985 gst_buffer_unmap (ret, &map);
986
987 return ret;
988 }
989
990 /* SMPTE 377M 11.1 */
991 gboolean
mxf_random_index_pack_parse(const MXFUL * ul,const guint8 * data,guint size,GArray ** array)992 mxf_random_index_pack_parse (const MXFUL * ul, const guint8 * data, guint size,
993 GArray ** array)
994 {
995 guint len, i;
996 MXFRandomIndexPackEntry entry;
997
998 g_return_val_if_fail (array != NULL, FALSE);
999
1000 if (size < 4)
1001 return FALSE;
1002
1003 g_return_val_if_fail (data != NULL, FALSE);
1004
1005 if ((size - 4) % 12 != 0)
1006 return FALSE;
1007
1008 GST_DEBUG ("Parsing random index pack:");
1009
1010 len = (size - 4) / 12;
1011
1012 GST_DEBUG (" number of entries = %u", len);
1013
1014 *array =
1015 g_array_sized_new (FALSE, FALSE, sizeof (MXFRandomIndexPackEntry), len);
1016
1017 for (i = 0; i < len; i++) {
1018 entry.body_sid = GST_READ_UINT32_BE (data);
1019 entry.offset = GST_READ_UINT64_BE (data + 4);
1020 data += 12;
1021
1022 GST_DEBUG (" entry %u = body sid %u at offset %" G_GUINT64_FORMAT, i,
1023 entry.body_sid, entry.offset);
1024
1025 g_array_append_val (*array, entry);
1026 }
1027
1028 return TRUE;
1029 }
1030
1031 GstBuffer *
mxf_random_index_pack_to_buffer(const GArray * array)1032 mxf_random_index_pack_to_buffer (const GArray * array)
1033 {
1034 MXFRandomIndexPackEntry *entry;
1035 guint i;
1036 GstBuffer *ret;
1037 GstMapInfo map;
1038 guint8 slen, ber[9];
1039 guint size;
1040 guint8 *data;
1041
1042 if (array->len == 0)
1043 return NULL;
1044
1045 size = array->len * 12 + 4;
1046 slen = mxf_ber_encode_size (size, ber);
1047 ret = gst_buffer_new_and_alloc (16 + slen + size);
1048 gst_buffer_map (ret, &map, GST_MAP_WRITE);
1049
1050 memcpy (map.data, MXF_UL (RANDOM_INDEX_PACK), 16);
1051 memcpy (map.data + 16, ber, slen);
1052
1053 data = map.data + 16 + slen;
1054
1055 for (i = 0; i < array->len; i++) {
1056 entry = &g_array_index (array, MXFRandomIndexPackEntry, i);
1057 GST_WRITE_UINT32_BE (data, entry->body_sid);
1058 GST_WRITE_UINT64_BE (data + 4, entry->offset);
1059 data += 12;
1060 }
1061 GST_WRITE_UINT32_BE (data, gst_buffer_get_size (ret));
1062
1063 gst_buffer_unmap (ret, &map);
1064
1065 return ret;
1066 }
1067
1068 /* SMPTE 377M 10.2.3 */
1069 gboolean
mxf_index_table_segment_parse(const MXFUL * ul,MXFIndexTableSegment * segment,const guint8 * data,guint size)1070 mxf_index_table_segment_parse (const MXFUL * ul,
1071 MXFIndexTableSegment * segment, const guint8 * data, guint size)
1072 {
1073 #ifndef GST_DISABLE_GST_DEBUG
1074 gchar str[48];
1075 #endif
1076 guint16 tag, tag_size;
1077 const guint8 *tag_data;
1078
1079 g_return_val_if_fail (ul != NULL, FALSE);
1080
1081 memset (segment, 0, sizeof (MXFIndexTableSegment));
1082
1083 if (size < 70)
1084 return FALSE;
1085
1086 g_return_val_if_fail (data != NULL, FALSE);
1087
1088 GST_DEBUG ("Parsing index table segment:");
1089
1090 while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) {
1091 data += 4 + tag_size;
1092 size -= 4 + tag_size;
1093
1094 if (tag_size == 0 || tag == 0x0000)
1095 continue;
1096
1097 switch (tag) {
1098 case 0x3c0a:
1099 if (tag_size != 16)
1100 goto error;
1101 memcpy (&segment->instance_id, tag_data, 16);
1102 GST_DEBUG (" instance id = %s",
1103 mxf_uuid_to_string (&segment->instance_id, str));
1104 break;
1105 case 0x3f0b:
1106 if (!mxf_fraction_parse (&segment->index_edit_rate, tag_data, tag_size))
1107 goto error;
1108 GST_DEBUG (" index edit rate = %d/%d", segment->index_edit_rate.n,
1109 segment->index_edit_rate.d);
1110 break;
1111 case 0x3f0c:
1112 if (tag_size != 8)
1113 goto error;
1114 segment->index_start_position = GST_READ_UINT64_BE (tag_data);
1115 GST_DEBUG (" index start position = %" G_GINT64_FORMAT,
1116 segment->index_start_position);
1117 break;
1118 case 0x3f0d:
1119 if (tag_size != 8)
1120 goto error;
1121 segment->index_duration = GST_READ_UINT64_BE (tag_data);
1122 GST_DEBUG (" index duration = %" G_GINT64_FORMAT,
1123 segment->index_duration);
1124 break;
1125 case 0x3f05:
1126 if (tag_size != 4)
1127 goto error;
1128 segment->edit_unit_byte_count = GST_READ_UINT32_BE (tag_data);
1129 GST_DEBUG (" edit unit byte count = %u",
1130 segment->edit_unit_byte_count);
1131 break;
1132 case 0x3f06:
1133 if (tag_size != 4)
1134 goto error;
1135 segment->index_sid = GST_READ_UINT32_BE (tag_data);
1136 GST_DEBUG (" index sid = %u", segment->index_sid);
1137 break;
1138 case 0x3f07:
1139 if (tag_size != 4)
1140 goto error;
1141 segment->body_sid = GST_READ_UINT32_BE (tag_data);
1142 GST_DEBUG (" body sid = %u", segment->body_sid);
1143 break;
1144 case 0x3f08:
1145 if (tag_size != 1)
1146 goto error;
1147 segment->slice_count = GST_READ_UINT8 (tag_data);
1148 GST_DEBUG (" slice count = %u", segment->slice_count);
1149 break;
1150 case 0x3f0e:
1151 if (tag_size != 1)
1152 goto error;
1153 segment->pos_table_count = GST_READ_UINT8 (tag_data);
1154 GST_DEBUG (" pos table count = %u", segment->pos_table_count);
1155 break;
1156 case 0x3f09:{
1157 guint len, i;
1158
1159 if (tag_size < 8)
1160 goto error;
1161
1162 len = GST_READ_UINT32_BE (tag_data);
1163 segment->n_delta_entries = len;
1164 GST_DEBUG (" number of delta entries = %u", segment->n_delta_entries);
1165 if (len == 0)
1166 continue;
1167 tag_data += 4;
1168 tag_size -= 4;
1169
1170 if (GST_READ_UINT32_BE (tag_data) != 6)
1171 goto error;
1172
1173 tag_data += 4;
1174 tag_size -= 4;
1175
1176 if (tag_size / 6 < len)
1177 goto error;
1178
1179 segment->delta_entries = g_new (MXFDeltaEntry, len);
1180
1181 for (i = 0; i < len; i++) {
1182 GST_DEBUG (" delta entry %u:", i);
1183
1184 segment->delta_entries[i].pos_table_index = GST_READ_UINT8 (tag_data);
1185 tag_data += 1;
1186 tag_size -= 1;
1187 GST_DEBUG (" pos table index = %d",
1188 segment->delta_entries[i].pos_table_index);
1189
1190 segment->delta_entries[i].slice = GST_READ_UINT8 (tag_data);
1191 tag_data += 1;
1192 tag_size -= 1;
1193 GST_DEBUG (" slice = %u", segment->delta_entries[i].slice);
1194
1195 segment->delta_entries[i].element_delta =
1196 GST_READ_UINT32_BE (tag_data);
1197 tag_data += 4;
1198 tag_size -= 4;
1199 GST_DEBUG (" element delta = %u",
1200 segment->delta_entries[i].element_delta);
1201 }
1202 break;
1203 }
1204 case 0x3f0a:{
1205 guint len, i, j;
1206
1207 if (tag_size < 8)
1208 goto error;
1209
1210 len = GST_READ_UINT32_BE (tag_data);
1211 segment->n_index_entries = len;
1212 GST_DEBUG (" number of index entries = %u", segment->n_index_entries);
1213 if (len == 0)
1214 continue;
1215 tag_data += 4;
1216 tag_size -= 4;
1217
1218 if (GST_READ_UINT32_BE (tag_data) !=
1219 (11 + 4 * segment->slice_count + 8 * segment->pos_table_count))
1220 goto error;
1221
1222 tag_data += 4;
1223 tag_size -= 4;
1224
1225 if (tag_size / (11 + 4 * segment->slice_count +
1226 8 * segment->pos_table_count) < len)
1227 goto error;
1228
1229 segment->index_entries = g_new0 (MXFIndexEntry, len);
1230
1231 for (i = 0; i < len; i++) {
1232 MXFIndexEntry *entry = &segment->index_entries[i];
1233
1234 GST_DEBUG (" index entry %u:", i);
1235
1236 entry->temporal_offset = GST_READ_UINT8 (tag_data);
1237 tag_data += 1;
1238 tag_size -= 1;
1239 GST_DEBUG (" temporal offset = %d", entry->temporal_offset);
1240
1241 entry->key_frame_offset = GST_READ_UINT8 (tag_data);
1242 tag_data += 1;
1243 tag_size -= 1;
1244 GST_DEBUG (" keyframe offset = %d", entry->key_frame_offset);
1245
1246 entry->flags = GST_READ_UINT8 (tag_data);
1247 tag_data += 1;
1248 tag_size -= 1;
1249 GST_DEBUG (" flags = 0x%02x (%s%s%s%s)", entry->flags,
1250 entry->flags & 0x80 ? "Random-Access " : "",
1251 entry->flags & 0x40 ? "Sequence-Header " : "",
1252 entry->flags & 0x20 ? "Forward-Prediction " : "",
1253 entry->flags & 0x10 ? "Backward-Prediction " : "");
1254
1255 entry->stream_offset = GST_READ_UINT64_BE (tag_data);
1256 tag_data += 8;
1257 tag_size -= 8;
1258 GST_DEBUG (" stream offset = %" G_GUINT64_FORMAT,
1259 entry->stream_offset);
1260
1261 entry->slice_offset = g_new0 (guint32, segment->slice_count);
1262 for (j = 0; j < segment->slice_count; j++) {
1263 entry->slice_offset[j] = GST_READ_UINT32_BE (tag_data);
1264 tag_data += 4;
1265 tag_size -= 4;
1266 GST_DEBUG (" slice %u offset = %u", j, entry->slice_offset[j]);
1267 }
1268
1269 entry->pos_table = g_new0 (MXFFraction, segment->pos_table_count);
1270 for (j = 0; j < segment->pos_table_count; j++) {
1271 if (!mxf_fraction_parse (&entry->pos_table[j], tag_data, tag_size))
1272 goto error;
1273 tag_data += 8;
1274 tag_size -= 8;
1275 GST_DEBUG (" pos table %u = %d/%d", j, entry->pos_table[j].n,
1276 entry->pos_table[j].d);
1277 }
1278 }
1279 break;
1280 }
1281 default:
1282 GST_WARNING
1283 ("Unknown local tag 0x%04x of size %d in index table segment", tag,
1284 tag_size);
1285 break;
1286 }
1287 }
1288
1289 /* If edit unit byte count is 0 there *must* be entries */
1290 if (segment->edit_unit_byte_count == 0 && segment->n_index_entries == 0) {
1291 GST_WARNING
1292 ("Invalid IndexTableSegment, No entries and no specified edit unit byte count");
1293 goto error;
1294 }
1295
1296 /* Compute initial essence offset */
1297 if (segment->edit_unit_byte_count)
1298 segment->segment_start_offset =
1299 segment->index_start_position * segment->edit_unit_byte_count;
1300 else
1301 segment->segment_start_offset = segment->index_entries[0].stream_offset;
1302
1303 return TRUE;
1304
1305 error:
1306 GST_ERROR ("Invalid index table segment");
1307 mxf_index_table_segment_reset (segment);
1308 return FALSE;
1309 }
1310
1311 void
mxf_index_table_segment_reset(MXFIndexTableSegment * segment)1312 mxf_index_table_segment_reset (MXFIndexTableSegment * segment)
1313 {
1314 guint i;
1315
1316 g_return_if_fail (segment != NULL);
1317
1318 if (segment->index_entries) {
1319 for (i = 0; i < segment->n_index_entries; i++) {
1320 g_free (segment->index_entries[i].slice_offset);
1321 g_free (segment->index_entries[i].pos_table);
1322 }
1323 }
1324
1325 g_free (segment->index_entries);
1326 g_free (segment->delta_entries);
1327
1328 memset (segment, 0, sizeof (MXFIndexTableSegment));
1329 }
1330
1331 GstBuffer *
mxf_index_table_segment_to_buffer(const MXFIndexTableSegment * segment)1332 mxf_index_table_segment_to_buffer (const MXFIndexTableSegment * segment)
1333 {
1334 guint len, slen, i;
1335 guint8 ber[9];
1336 GstBuffer *ret;
1337 GstMapInfo map;
1338 GstByteWriter bw;
1339
1340 g_return_val_if_fail (segment != NULL, NULL);
1341 g_return_val_if_fail (segment->n_delta_entries * 6 < G_MAXUINT16, NULL);
1342 g_return_val_if_fail (segment->n_index_entries * (11 +
1343 4 * segment->slice_count + 8 * segment->pos_table_count) <
1344 G_MAXUINT16, NULL);
1345
1346 len =
1347 16 + 4 + 8 + 4 + 8 + 4 + 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 1 + 4 + 1 + 4 +
1348 4 + 8 + segment->n_delta_entries * 6 + 4 + 8 +
1349 segment->n_index_entries * (11 + 4 * segment->slice_count +
1350 8 * segment->pos_table_count);
1351 slen = mxf_ber_encode_size (len, ber);
1352
1353 ret = gst_buffer_new_and_alloc (16 + slen + len);
1354 gst_buffer_map (ret, &map, GST_MAP_WRITE);
1355
1356 gst_byte_writer_init_with_data (&bw, map.data, map.size, FALSE);
1357
1358 gst_byte_writer_put_data_unchecked (&bw,
1359 (const guint8 *) MXF_UL (INDEX_TABLE_SEGMENT), 16);
1360 gst_byte_writer_put_data_unchecked (&bw, ber, slen);
1361
1362 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3c0a);
1363 gst_byte_writer_put_uint16_be_unchecked (&bw, 16);
1364 gst_byte_writer_put_data_unchecked (&bw,
1365 (const guint8 *) &segment->instance_id, 16);
1366
1367 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f0b);
1368 gst_byte_writer_put_uint16_be_unchecked (&bw, 8);
1369 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->index_edit_rate.n);
1370 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->index_edit_rate.d);
1371
1372 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f0c);
1373 gst_byte_writer_put_uint16_be_unchecked (&bw, 8);
1374 gst_byte_writer_put_uint64_be_unchecked (&bw, segment->index_start_position);
1375
1376 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f0d);
1377 gst_byte_writer_put_uint16_be_unchecked (&bw, 8);
1378 gst_byte_writer_put_uint64_be_unchecked (&bw, segment->index_duration);
1379
1380 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f05);
1381 gst_byte_writer_put_uint16_be_unchecked (&bw, 4);
1382 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->edit_unit_byte_count);
1383
1384 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f06);
1385 gst_byte_writer_put_uint16_be_unchecked (&bw, 4);
1386 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->index_sid);
1387
1388 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f07);
1389 gst_byte_writer_put_uint16_be_unchecked (&bw, 4);
1390 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->body_sid);
1391
1392 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f08);
1393 gst_byte_writer_put_uint16_be_unchecked (&bw, 1);
1394 gst_byte_writer_put_uint8 (&bw, segment->slice_count);
1395
1396 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f0e);
1397 gst_byte_writer_put_uint16_be_unchecked (&bw, 1);
1398 gst_byte_writer_put_uint8 (&bw, segment->pos_table_count);
1399
1400 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f09);
1401 gst_byte_writer_put_uint16_be_unchecked (&bw,
1402 8 + segment->n_delta_entries * 6);
1403 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->n_delta_entries);
1404 gst_byte_writer_put_uint32_be_unchecked (&bw, 6);
1405 for (i = 0; i < segment->n_delta_entries; i++) {
1406 gst_byte_writer_put_uint8_unchecked (&bw,
1407 segment->delta_entries[i].pos_table_index);
1408 gst_byte_writer_put_uint8_unchecked (&bw, segment->delta_entries[i].slice);
1409 gst_byte_writer_put_uint32_be_unchecked (&bw,
1410 segment->delta_entries[i].element_delta);
1411 }
1412
1413 gst_byte_writer_put_uint16_be_unchecked (&bw, 0x3f0a);
1414 gst_byte_writer_put_uint16_be_unchecked (&bw,
1415 8 + segment->n_index_entries * (11 + 4 * segment->slice_count +
1416 8 * segment->pos_table_count));
1417 gst_byte_writer_put_uint32_be_unchecked (&bw, segment->n_index_entries);
1418 gst_byte_writer_put_uint32_be_unchecked (&bw,
1419 (11 + 4 * segment->slice_count + 8 * segment->pos_table_count));
1420 for (i = 0; i < segment->n_index_entries; i++) {
1421 guint j;
1422
1423 gst_byte_writer_put_uint8_unchecked (&bw,
1424 segment->index_entries[i].temporal_offset);
1425 gst_byte_writer_put_uint8_unchecked (&bw,
1426 segment->index_entries[i].key_frame_offset);
1427 gst_byte_writer_put_uint8_unchecked (&bw, segment->index_entries[i].flags);
1428 gst_byte_writer_put_uint64_be_unchecked (&bw,
1429 segment->index_entries[i].stream_offset);
1430
1431 for (j = 0; j < segment->slice_count; j++)
1432 gst_byte_writer_put_uint32_be_unchecked (&bw,
1433 segment->index_entries[i].slice_offset[j]);
1434
1435 for (j = 0; j < segment->pos_table_count; j++) {
1436 gst_byte_writer_put_uint32_be_unchecked (&bw,
1437 segment->index_entries[i].pos_table[j].n);
1438 gst_byte_writer_put_uint32_be_unchecked (&bw,
1439 segment->index_entries[i].pos_table[j].d);
1440 }
1441 }
1442
1443 g_assert (gst_byte_writer_get_pos (&bw) == map.size);
1444
1445 gst_buffer_unmap (ret, &map);
1446
1447 return ret;
1448 }
1449
1450 /* SMPTE 377M 8.2 Table 1 and 2 */
1451
1452 static void
_mxf_mapping_ul_free(MXFUL * ul)1453 _mxf_mapping_ul_free (MXFUL * ul)
1454 {
1455 g_slice_free (MXFUL, ul);
1456 }
1457
1458 gboolean
mxf_primer_pack_parse(const MXFUL * ul,MXFPrimerPack * pack,const guint8 * data,guint size)1459 mxf_primer_pack_parse (const MXFUL * ul, MXFPrimerPack * pack,
1460 const guint8 * data, guint size)
1461 {
1462 guint i;
1463 guint32 n;
1464
1465 if (size < 8)
1466 return FALSE;
1467
1468 g_return_val_if_fail (data != NULL, FALSE);
1469
1470 memset (pack, 0, sizeof (MXFPrimerPack));
1471
1472 GST_DEBUG ("Parsing primer pack:");
1473
1474 pack->mappings =
1475 g_hash_table_new_full (g_direct_hash, g_direct_equal,
1476 (GDestroyNotify) NULL, (GDestroyNotify) _mxf_mapping_ul_free);
1477
1478 n = GST_READ_UINT32_BE (data);
1479 data += 4;
1480 size -= 4;
1481
1482 GST_DEBUG (" number of mappings = %u", n);
1483
1484 if (GST_READ_UINT32_BE (data) != 18)
1485 goto error;
1486 data += 4;
1487 size -= 4;
1488
1489 if (size / 18 < n)
1490 goto error;
1491
1492 for (i = 0; i < n; i++) {
1493 guint local_tag;
1494 #ifndef GST_DISABLE_GST_DEBUG
1495 gchar str[48];
1496 #endif
1497 MXFUL *uid;
1498
1499 local_tag = GST_READ_UINT16_BE (data);
1500 data += 2;
1501
1502 if (g_hash_table_lookup (pack->mappings, GUINT_TO_POINTER (local_tag)))
1503 continue;
1504
1505 uid = g_slice_new (MXFUL);
1506 memcpy (uid, data, 16);
1507 data += 16;
1508
1509 g_hash_table_insert (pack->mappings, GUINT_TO_POINTER (local_tag), uid);
1510 GST_DEBUG (" Adding mapping = 0x%04x -> %s", local_tag,
1511 mxf_ul_to_string (uid, str));
1512 }
1513
1514 return TRUE;
1515
1516 error:
1517 GST_DEBUG ("Invalid primer pack");
1518 mxf_primer_pack_reset (pack);
1519 return FALSE;
1520 }
1521
1522 void
mxf_primer_pack_reset(MXFPrimerPack * pack)1523 mxf_primer_pack_reset (MXFPrimerPack * pack)
1524 {
1525 g_return_if_fail (pack != NULL);
1526
1527 if (pack->mappings)
1528 g_hash_table_destroy (pack->mappings);
1529 if (pack->reverse_mappings)
1530 g_hash_table_destroy (pack->reverse_mappings);
1531
1532 memset (pack, 0, sizeof (MXFPrimerPack));
1533
1534 pack->next_free_tag = 0x8000;
1535 }
1536
1537 guint16
mxf_primer_pack_add_mapping(MXFPrimerPack * primer,guint16 local_tag,const MXFUL * ul)1538 mxf_primer_pack_add_mapping (MXFPrimerPack * primer, guint16 local_tag,
1539 const MXFUL * ul)
1540 {
1541 MXFUL *uid;
1542 #ifndef GST_DISABLE_GST_DEBUG
1543 gchar str[48];
1544 #endif
1545 guint ltag_tmp = local_tag;
1546
1547 if (primer->mappings == NULL) {
1548 primer->mappings = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1549 (GDestroyNotify) NULL, (GDestroyNotify) _mxf_mapping_ul_free);
1550 }
1551
1552 if (primer->reverse_mappings == NULL) {
1553 primer->reverse_mappings = g_hash_table_new_full ((GHashFunc) mxf_ul_hash,
1554 (GEqualFunc) mxf_ul_is_equal, (GDestroyNotify) _mxf_mapping_ul_free,
1555 (GDestroyNotify) NULL);
1556 }
1557
1558 if (primer->next_free_tag == 0xffff && ltag_tmp == 0) {
1559 GST_ERROR ("Used too many dynamic tags");
1560 return 0;
1561 }
1562
1563 if (ltag_tmp == 0) {
1564 guint tmp;
1565
1566 tmp = GPOINTER_TO_UINT (g_hash_table_lookup (primer->reverse_mappings, ul));
1567 if (tmp == 0) {
1568 ltag_tmp = primer->next_free_tag;
1569 primer->next_free_tag++;
1570 }
1571 } else {
1572 if (g_hash_table_lookup (primer->mappings, GUINT_TO_POINTER (ltag_tmp)))
1573 return ltag_tmp;
1574 }
1575
1576 g_assert (ltag_tmp != 0);
1577
1578 uid = g_slice_new (MXFUL);
1579 memcpy (uid, ul, 16);
1580
1581 GST_DEBUG ("Adding mapping = 0x%04x -> %s", ltag_tmp,
1582 mxf_ul_to_string (uid, str));
1583 g_hash_table_insert (primer->mappings, GUINT_TO_POINTER (ltag_tmp), uid);
1584 uid = g_slice_dup (MXFUL, uid);
1585 g_hash_table_insert (primer->reverse_mappings, uid,
1586 GUINT_TO_POINTER (ltag_tmp));
1587
1588 return ltag_tmp;
1589 }
1590
1591 GstBuffer *
mxf_primer_pack_to_buffer(const MXFPrimerPack * pack)1592 mxf_primer_pack_to_buffer (const MXFPrimerPack * pack)
1593 {
1594 guint slen;
1595 guint8 ber[9];
1596 GstBuffer *ret;
1597 GstMapInfo map;
1598 guint n;
1599 guint8 *data;
1600
1601 if (pack->mappings)
1602 n = g_hash_table_size (pack->mappings);
1603 else
1604 n = 0;
1605
1606 slen = mxf_ber_encode_size (8 + 18 * n, ber);
1607
1608 ret = gst_buffer_new_and_alloc (16 + slen + 8 + 18 * n);
1609 gst_buffer_map (ret, &map, GST_MAP_WRITE);
1610
1611 memcpy (map.data, MXF_UL (PRIMER_PACK), 16);
1612 memcpy (map.data + 16, &ber, slen);
1613
1614 data = map.data + 16 + slen;
1615
1616 GST_WRITE_UINT32_BE (data, n);
1617 GST_WRITE_UINT32_BE (data + 4, 18);
1618 data += 8;
1619
1620 if (pack->mappings) {
1621 gpointer local_tag;
1622 MXFUL *ul;
1623 GHashTableIter iter;
1624
1625 g_hash_table_iter_init (&iter, pack->mappings);
1626
1627 while (g_hash_table_iter_next (&iter, &local_tag, (gpointer) & ul)) {
1628 GST_WRITE_UINT16_BE (data, GPOINTER_TO_UINT (local_tag));
1629 memcpy (data + 2, ul, 16);
1630 data += 18;
1631 }
1632 }
1633
1634 gst_buffer_unmap (ret, &map);
1635
1636 return ret;
1637 }
1638
1639 /* structural metadata parsing */
1640
1641 gboolean
mxf_local_tag_parse(const guint8 * data,guint size,guint16 * tag,guint16 * tag_size,const guint8 ** tag_data)1642 mxf_local_tag_parse (const guint8 * data, guint size, guint16 * tag,
1643 guint16 * tag_size, const guint8 ** tag_data)
1644 {
1645 if (size < 4)
1646 return FALSE;
1647
1648 g_return_val_if_fail (data != NULL, FALSE);
1649
1650 *tag = GST_READ_UINT16_BE (data);
1651 *tag_size = GST_READ_UINT16_BE (data + 2);
1652
1653 data += 4;
1654 size -= 4;
1655
1656 if (size < *tag_size)
1657 return FALSE;
1658
1659 *tag_data = data;
1660
1661 return TRUE;
1662 }
1663
1664 void
mxf_local_tag_free(MXFLocalTag * tag)1665 mxf_local_tag_free (MXFLocalTag * tag)
1666 {
1667 if (tag->g_slice)
1668 g_slice_free1 (tag->size, tag->data);
1669 else
1670 g_free (tag->data);
1671 g_slice_free (MXFLocalTag, tag);
1672 }
1673
1674 gboolean
mxf_local_tag_add_to_hash_table(const MXFPrimerPack * primer,guint16 tag,const guint8 * tag_data,guint16 tag_size,GHashTable ** hash_table)1675 mxf_local_tag_add_to_hash_table (const MXFPrimerPack * primer,
1676 guint16 tag, const guint8 * tag_data, guint16 tag_size,
1677 GHashTable ** hash_table)
1678 {
1679 MXFLocalTag *local_tag;
1680 MXFUL *ul;
1681
1682 g_return_val_if_fail (primer != NULL, FALSE);
1683 g_return_val_if_fail (tag_size == 0 || tag_data != NULL, FALSE);
1684 g_return_val_if_fail (hash_table != NULL, FALSE);
1685 g_return_val_if_fail (primer->mappings != NULL, FALSE);
1686
1687 if (*hash_table == NULL)
1688 *hash_table =
1689 g_hash_table_new_full ((GHashFunc) mxf_ul_hash,
1690 (GEqualFunc) mxf_ul_is_equal, (GDestroyNotify) NULL,
1691 (GDestroyNotify) mxf_local_tag_free);
1692
1693 g_return_val_if_fail (*hash_table != NULL, FALSE);
1694
1695 ul = (MXFUL *) g_hash_table_lookup (primer->mappings,
1696 GUINT_TO_POINTER (((guint) tag)));
1697
1698 if (ul) {
1699 #ifndef GST_DISABLE_GST_DEBUG
1700 gchar str[48];
1701 #endif
1702
1703 GST_DEBUG ("Adding local tag 0x%04x with UL %s and size %u", tag,
1704 mxf_ul_to_string (ul, str), tag_size);
1705
1706 local_tag = g_slice_new0 (MXFLocalTag);
1707 memcpy (&local_tag->ul, ul, sizeof (MXFUL));
1708 local_tag->size = tag_size;
1709 local_tag->data = tag_size == 0 ? NULL : g_memdup2 (tag_data, tag_size);
1710 local_tag->g_slice = FALSE;
1711
1712 g_hash_table_insert (*hash_table, &local_tag->ul, local_tag);
1713 } else {
1714 GST_WARNING ("Local tag with no entry in primer pack: 0x%04x", tag);
1715 }
1716
1717 return TRUE;
1718 }
1719
1720 gboolean
mxf_local_tag_insert(MXFLocalTag * tag,GHashTable ** hash_table)1721 mxf_local_tag_insert (MXFLocalTag * tag, GHashTable ** hash_table)
1722 {
1723 #ifndef GST_DISABLE_GST_DEBUG
1724 gchar str[48];
1725 #endif
1726
1727 g_return_val_if_fail (tag != NULL, FALSE);
1728 g_return_val_if_fail (hash_table != NULL, FALSE);
1729
1730 if (*hash_table == NULL)
1731 *hash_table =
1732 g_hash_table_new_full ((GHashFunc) mxf_ul_hash,
1733 (GEqualFunc) mxf_ul_is_equal, (GDestroyNotify) NULL,
1734 (GDestroyNotify) mxf_local_tag_free);
1735
1736 g_return_val_if_fail (*hash_table != NULL, FALSE);
1737
1738 GST_DEBUG ("Adding local tag with UL %s and size %u",
1739 mxf_ul_to_string (&tag->ul, str), tag->size);
1740
1741 g_hash_table_insert (*hash_table, &tag->ul, tag);
1742
1743 return TRUE;
1744 }
1745