• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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