metadata reformed...
[asdcplib.git] / src / MXFTypes.cpp
1 /*
2 Copyright (c) 2005-2006, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*! \file    MXFTypes.cpp
28     \version $Id$
29     \brief   MXF objects
30 */
31
32 #include "MXFTypes.h"
33 #include "FortunaRNG.h"
34
35 //------------------------------------------------------------------------------------------
36 //
37
38 const ASDCP::UID&
39 ASDCP::UID::operator=(const UMID& rhs)
40 {
41   // TODO
42   return *this;
43 }
44
45 //
46 void
47 ASDCP::UMID::MakeUMID(int Type)
48 {
49   UUID AssetID;
50   AssetID.GenRandomValue();
51   MakeUMID(Type, AssetID);
52 }
53
54 //
55 void
56 ASDCP::UMID::MakeUMID(int Type, const UUID& AssetID)
57 {
58   // Set the non-varying base of the UMID
59   static const byte_t UMIDBase[10] = { 0x06, 0x0a, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
60   memcpy(m_Value, UMIDBase, 10);
61
62   // Correct to v5 dictionary for new (330M-2003) types
63   if( Type > 4 )
64     m_Value[7] = 5;
65
66   // Set the type
67   m_Value[10] = Type;
68
69   // We are using a GUID for material number, and no defined instance method
70   m_Value[11] = 0x20;
71
72   // Length of UMID "Value" is 19 bytes
73   m_Value[12] = 0x13;
74
75   // Set instance number to zero as this is the first instance of this material
76   m_Value[13] = m_Value[14] = m_Value[15] = 0;
77   
78   memcpy(&m_Value[16], AssetID.Value(), AssetID.Size());
79 }
80
81
82 // Write the timestamp value to the given buffer in the form 2004-05-01 13:20:00.000
83 // returns 0 if the buffer is smaller than DateTimeLen
84 const char*
85 ASDCP::UMID::ToString(char* str_buf) const
86 {
87   assert(str_buf);
88
89   snprintf(str_buf, IdentBufferLen, "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x],%02x,%02x,%02x,%02x,",
90            m_Value[0],  m_Value[1],  m_Value[2],  m_Value[3],  m_Value[4],  m_Value[5],  m_Value[6],  m_Value[7],
91            m_Value[8],  m_Value[9],  m_Value[10], m_Value[11], m_Value[12], m_Value[13], m_Value[14], m_Value[15]
92            );
93
94   ui32_t offset = strlen(str_buf);
95
96   if ( ( m_Value[8] & 0x80 ) == 0 )
97     {
98       // half-swapped UL, use [bbaa9988.ddcc.ffee.00010203.04050607]
99       snprintf(str_buf + offset, IdentBufferLen - offset,
100                "[%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x]",
101                m_Value[24], m_Value[25], m_Value[26], m_Value[27], m_Value[28], m_Value[29], m_Value[30], m_Value[31],
102                m_Value[16], m_Value[17], m_Value[18], m_Value[19], m_Value[20], m_Value[21], m_Value[22], m_Value[23]
103                );
104     }
105   else
106     {
107       // UUID, use {00112233-4455-6677-8899-aabbccddeeff}
108       snprintf(str_buf + offset, IdentBufferLen - offset,
109                "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
110                m_Value[16], m_Value[17], m_Value[18], m_Value[19], m_Value[20], m_Value[21], m_Value[22], m_Value[23],
111                m_Value[24], m_Value[25], m_Value[26], m_Value[27], m_Value[28], m_Value[29], m_Value[30], m_Value[31]
112                );
113     }
114
115   return str_buf;
116 }
117
118 //
119 void
120 ASDCP::UUID::GenRandomValue()
121 {
122   FortunaRNG RNG;
123   RNG.FillRandom(m_Value, UUIDlen);
124   m_Value[6] &= 0x0f; // clear bits 4-7
125   m_Value[6] |= 0x40; // set UUID version
126   m_Value[8] &= 0x3f; // clear bits 6&7
127   m_Value[8] |= 0x80; // set bit 7
128 }
129
130
131 //------------------------------------------------------------------------------------------
132 //
133
134 const ASDCP::MXF::UTF16String&
135 ASDCP::MXF::UTF16String::operator=(const char* sz)
136 {
137   if ( sz == 0 || *sz == 0 )
138     {
139       m_length = 0;
140       *m_buffer = 0;
141     }
142   else
143     {
144       ui32_t len = xmin((ui32_t)strlen(sz), (IdentBufferLen - 1));
145       m_length = len;
146       memcpy(m_buffer, sz, m_length);
147       m_buffer[m_length] = 0;
148     }
149   
150   return *this;
151 }
152
153
154 //
155 ASDCP::Result_t
156 ASDCP::MXF::UTF16String::Unarchive(ASDCP::MemIOReader& Reader)
157 {
158   const byte_t* p = Reader.Data() + Reader.Offset();
159   /// cheating - for all use cases, we know the previous two bytes are the length
160   m_length = ASDCP_i16_BE(cp2i<ui16_t>(p-2));
161   assert(m_length % 2 == 0);
162   m_length /= 2;
163   assert(IdentBufferLen >= m_length);
164   ui32_t i = 0;
165
166   for ( i = 0; i < m_length; i++ )
167     m_buffer[i] = p[(i*2)+1];
168
169   m_buffer[i] = 0;
170
171   Reader.SkipOffset(m_length*2);
172   return RESULT_OK;
173 }
174
175 //
176 ASDCP::Result_t
177 ASDCP::MXF::UTF16String::Archive(ASDCP::MemIOWriter& Writer)
178 {
179   byte_t* p = Writer.Data() + Writer.Size();
180   ui32_t i = 0;
181   m_length = strlen(m_buffer);
182   memset(p, 0, m_length*2);
183
184   for ( i = 0; i < m_length; i++ )
185     p[(i*2)+1] = m_buffer[i];
186
187   Writer.AddOffset(m_length * 2 );
188   return RESULT_OK;
189 }
190
191
192 //------------------------------------------------------------------------------------------
193 //
194
195 #ifdef WIN32
196
197 #define TIMESTAMP_TO_SYSTIME(ts, t) \
198   (t)->wYear    = (ts).Year;   /* year */ \
199   (t)->wMonth   = (ts).Month;  /* month of year (1 - 12) */ \
200   (t)->wDay     = (ts).Day;    /* day of month (1 - 31) */ \
201   (t)->wHour    = (ts).Hour;   /* hours (0 - 23) */ \
202   (t)->wMinute  = (ts).Minute; /* minutes (0 - 59) */ \
203   (t)->wSecond  = (ts).Second; /* seconds (0 - 60) */ \
204   (t)->wDayOfWeek = 0; \
205   (t)->wMilliseconds = ((ts).Tick * 4);
206
207 #define SYSTIME_TO_TIMESTAMP(t, ts) \
208   (ts).Year   = (t)->wYear;    /* year */ \
209   (ts).Month  = (t)->wMonth;   /* month of year (1 - 12) */ \
210   (ts).Day    = (t)->wDay;     /* day of month (1 - 31) */ \
211   (ts).Hour   = (t)->wHour;    /* hours (0 - 23) */ \
212   (ts).Minute = (t)->wMinute;  /* minutes (0 - 59) */ \
213   (ts).Second = (t)->wSecond;  /* seconds (0 - 60) */ \
214   (ts).Tick   = (t)->wMilliseconds / 4;
215
216 //
217 ASDCP::MXF::Timestamp::Timestamp() :
218   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0), Tick(0)
219 {
220   SYSTEMTIME sys_time;
221   GetSystemTime(&sys_time);
222   SYSTIME_TO_TIMESTAMP(&sys_time, *this);
223 }
224
225 //
226 bool
227 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
228 {
229   SYSTEMTIME lhst, rhst;
230   FILETIME lft, rft;
231
232   TIMESTAMP_TO_SYSTIME(*this, &lhst);
233   TIMESTAMP_TO_SYSTIME(rhs, &rhst);
234   SystemTimeToFileTime(&lhst, &lft);
235   SystemTimeToFileTime(&rhst, &rft);
236   return ( CompareFileTime(&lft, &rft) == -1 );
237 }
238
239 inline ui64_t
240 seconds_to_ns100(ui32_t seconds)
241 {
242   return ((ui64_t)seconds * 10000000);
243 }
244
245 //
246 void
247 ASDCP::MXF::Timestamp::AddDays(i32_t days)
248 {
249   SYSTEMTIME current_st;
250   FILETIME current_ft;
251   ULARGE_INTEGER current_ul;
252
253   if ( days != 0 )
254     {
255       TIMESTAMP_TO_SYSTIME(*this, &current_st);
256       SystemTimeToFileTime(&current_st, &current_ft);
257       memcpy(&current_ul, &current_ft, sizeof(current_ul));
258       current_ul.QuadPart += ( seconds_to_ns100(86400) * (ui64_t)days );
259       memcpy(&current_ft, &current_ul, sizeof(current_ft));
260       FileTimeToSystemTime(&current_ft, &current_st);
261       SYSTIME_TO_TIMESTAMP(&current_st, *this);
262     }
263 }
264
265 //
266 void
267 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
268 {
269   SYSTEMTIME current_st;
270   FILETIME current_ft;
271   ULARGE_INTEGER current_ul;
272
273   if ( hours != 0 )
274     {
275       TIMESTAMP_TO_SYSTIME(*this, &current_st);
276       SystemTimeToFileTime(&current_st, &current_ft);
277       memcpy(&current_ul, &current_ft, sizeof(current_ul));
278       current_ul.QuadPart += ( seconds_to_ns100(3600) * (ui64_t)hours );
279       memcpy(&current_ft, &current_ul, sizeof(current_ft));
280       FileTimeToSystemTime(&current_ft, &current_st);
281       SYSTIME_TO_TIMESTAMP(&current_st, *this);
282     }
283 }
284
285 #else // WM_WIN32
286
287 #include <time.h>
288
289 #define TIMESTAMP_TO_TM(ts, t) \
290   (t)->tm_year = (ts).Year - 1900;   /* year - 1900 */ \
291   (t)->tm_mon  = (ts).Month - 1;     /* month of year (0 - 11) */ \
292   (t)->tm_mday = (ts).Day;           /* day of month (1 - 31) */ \
293   (t)->tm_hour = (ts).Hour;          /* hours (0 - 23) */ \
294   (t)->tm_min  = (ts).Minute;        /* minutes (0 - 59) */ \
295   (t)->tm_sec  = (ts).Second;        /* seconds (0 - 60) */
296
297 #define TM_TO_TIMESTAMP(t, ts) \
298   (ts).Year   = (t)->tm_year + 1900;    /* year - 1900 */ \
299   (ts).Month  = (t)->tm_mon + 1;     /* month of year (0 - 11) */ \
300   (ts).Day    = (t)->tm_mday;    /* day of month (1 - 31) */ \
301   (ts).Hour   = (t)->tm_hour;    /* hours (0 - 23) */ \
302   (ts).Minute = (t)->tm_min;     /* minutes (0 - 59) */ \
303   (ts).Second = (t)->tm_sec;     /* seconds (0 - 60) */
304
305 //
306 ASDCP::MXF::Timestamp::Timestamp() :
307   Year(0), Month(0),  Day(0), Hour(0), Minute(0), Second(0)
308 {
309   time_t t_now = time(0);
310   struct tm*  now = gmtime(&t_now);
311   TM_TO_TIMESTAMP(now, *this);
312 }
313
314 //
315 bool
316 ASDCP::MXF::Timestamp::operator<(const Timestamp& rhs) const
317 {
318   struct tm lhtm, rhtm;
319   TIMESTAMP_TO_TM(*this, &lhtm);
320   TIMESTAMP_TO_TM(rhs, &rhtm);
321   return ( timegm(&lhtm) < timegm(&rhtm) );
322 }
323
324 //
325 void
326 ASDCP::MXF::Timestamp::AddDays(i32_t days)
327 {
328   struct tm current;
329
330   if ( days != 0 )
331     {
332       TIMESTAMP_TO_TM(*this, &current);
333       time_t adj_time = timegm(&current);
334       adj_time += 86400 * days;
335       struct tm*  now = gmtime(&adj_time);
336       TM_TO_TIMESTAMP(now, *this);
337     }
338 }
339
340 //
341 void
342 ASDCP::MXF::Timestamp::AddHours(i32_t hours)
343 {
344   struct tm current;
345
346   if ( hours != 0 )
347     {
348       TIMESTAMP_TO_TM(*this, &current);
349       time_t adj_time = timegm(&current);
350       adj_time += 3600 * hours;
351       struct tm*  now = gmtime(&adj_time);
352       TM_TO_TIMESTAMP(now, *this);
353     }
354 }
355
356 #endif // WM_WIN32
357
358
359 ASDCP::MXF::Timestamp::Timestamp(const Timestamp& rhs)
360 {
361   Year   = rhs.Year;
362   Month  = rhs.Month;
363   Day    = rhs.Day;
364   Hour   = rhs.Hour;
365   Minute = rhs.Minute;
366   Second = rhs.Second;
367 }
368
369 ASDCP::MXF::Timestamp::~Timestamp()
370 {
371 }
372
373 //
374 const ASDCP::MXF::Timestamp&
375 ASDCP::MXF::Timestamp::operator=(const Timestamp& rhs)
376 {
377   Year   = rhs.Year;
378   Month  = rhs.Month;
379   Day    = rhs.Day;
380   Hour   = rhs.Hour;
381   Minute = rhs.Minute;
382   Second = rhs.Second;
383   return *this;
384 }
385
386 //
387 bool
388 ASDCP::MXF::Timestamp::operator==(const Timestamp& rhs) const
389 {
390   if ( Year == rhs.Year
391        && Month  == rhs.Month
392        && Day    == rhs.Day
393        && Hour   == rhs.Hour
394        && Minute == rhs.Minute
395        && Second == rhs.Second )
396     return true;
397
398   return false;
399 }
400
401 //
402 bool
403 ASDCP::MXF::Timestamp::operator!=(const Timestamp& rhs) const
404 {
405   if ( Year != rhs.Year
406        || Month  != rhs.Month
407        || Day    != rhs.Day
408        || Hour   != rhs.Hour
409        || Minute != rhs.Minute
410        || Second != rhs.Second )
411     return true;
412
413   return false;
414 }
415
416 //
417 const char*
418 ASDCP::MXF::Timestamp::ToString(char* str_buf) const
419 {
420   // 2004-05-01 13:20:00.000
421   snprintf(str_buf, IntBufferLen,
422            "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.000",
423            Year, Month, Day, Hour, Minute, Second, Tick);
424   
425   return str_buf;
426 }
427
428 //------------------------------------------------------------------------------------------
429 //
430
431 ASDCP::MXF::TLVReader::TLVReader(const byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
432   MemIOReader(p, c), m_Lookup(PrimerLookup)
433 {
434   Result_t result = RESULT_OK;
435
436   while ( Remainder() > 0 && ASDCP_SUCCESS(result) )
437     {
438       TagValue Tag;
439       ui16_t pkt_len = 0;
440
441       result = MemIOReader::ReadUi8(&Tag.a);
442
443       if ( ASDCP_SUCCESS(result) )
444         result = MemIOReader::ReadUi8(&Tag.b);
445
446       if ( ASDCP_SUCCESS(result) )
447         result = MemIOReader::ReadUi16BE(&pkt_len);
448
449       if ( ASDCP_SUCCESS(result) )
450         {
451           m_ElementMap.insert(TagMap::value_type(Tag, ItemInfo(m_size, pkt_len)));
452           result = SkipOffset(pkt_len);
453         }
454       
455       if ( ASDCP_FAILURE(result) )
456         {
457           DefaultLogSink().Error("Malformed Set\n");
458           m_ElementMap.clear();
459           break;
460         }
461     }
462 }
463
464 //
465 bool
466 ASDCP::MXF::TLVReader::FindTL(const MDDEntry& Entry)
467 {
468   if ( m_Lookup == 0 )
469     {
470       DefaultLogSink().Error("No Lookup service\n");
471       return false;
472     }
473   
474   TagValue TmpTag;
475
476   if ( m_Lookup->TagForKey(Entry.ul, TmpTag) != RESULT_OK )
477     {
478       if ( Entry.tag.a == 0 )
479         {
480           DefaultLogSink().Info("No such UL in this TL list: %s (%02x %02x)\n",
481                                 Entry.name, Entry.tag.a, Entry.tag.b);
482           return false;
483         }
484
485       TmpTag = Entry.tag;
486     }
487
488   TagMap::iterator e_i = m_ElementMap.find(TmpTag);
489
490   if ( e_i != m_ElementMap.end() )
491     {
492       m_size = (*e_i).second.first;
493       m_capacity = m_size + (*e_i).second.second;
494       return true;
495     }
496
497   DefaultLogSink().Info("Not Found (%02x %02x): %s\n", TmpTag.a, TmpTag.b, Entry.name);
498   return false;
499 }
500
501 //
502 ASDCP::Result_t
503 ASDCP::MXF::TLVReader::ReadObject(const MDDEntry& Entry, IArchive* Object)
504 {
505   ASDCP_TEST_NULL(Object);
506
507   if ( FindTL(Entry) )
508     return Object->Unarchive(*this);
509
510   return RESULT_FALSE;
511 }
512
513 //
514 ASDCP::Result_t
515 ASDCP::MXF::TLVReader::ReadUi8(const MDDEntry& Entry, ui8_t* value)
516 {
517   ASDCP_TEST_NULL(value);
518
519   if ( FindTL(Entry) )
520     return MemIOReader::ReadUi8(value);
521
522   return RESULT_FALSE;
523 }
524
525 //
526 ASDCP::Result_t
527 ASDCP::MXF::TLVReader::ReadUi16(const MDDEntry& Entry, ui16_t* value)
528 {
529   ASDCP_TEST_NULL(value);
530
531   if ( FindTL(Entry) )
532     return MemIOReader::ReadUi16BE(value);
533
534   return RESULT_FALSE;
535 }
536
537 //
538 ASDCP::Result_t
539 ASDCP::MXF::TLVReader::ReadUi32(const MDDEntry& Entry, ui32_t* value)
540 {
541   ASDCP_TEST_NULL(value);
542
543   if ( FindTL(Entry) )
544     return MemIOReader::ReadUi32BE(value);
545
546   return RESULT_FALSE;
547 }
548
549 //
550 ASDCP::Result_t
551 ASDCP::MXF::TLVReader::ReadUi64(const MDDEntry& Entry, ui64_t* value)
552 {
553   ASDCP_TEST_NULL(value);
554
555   if ( FindTL(Entry) )
556     return MemIOReader::ReadUi64BE(value);
557
558   return RESULT_FALSE;
559 }
560
561 //------------------------------------------------------------------------------------------
562 //
563
564 ASDCP::MXF::TLVWriter::TLVWriter(byte_t* p, ui32_t c, IPrimerLookup* PrimerLookup) :
565   MemIOWriter(p, c), m_Lookup(PrimerLookup)
566 {
567   assert(c > 3);
568 }
569
570 //
571 ASDCP::Result_t
572 ASDCP::MXF::TLVWriter::WriteTag(const MDDEntry& Entry)
573 {
574   if ( m_Lookup == 0 )
575     {
576       DefaultLogSink().Error("No Primer object available\n");
577       return RESULT_FAIL;
578     }
579
580   TagValue TmpTag;
581
582   if ( m_Lookup->InsertTag(Entry, TmpTag) != RESULT_OK )
583     {
584       DefaultLogSink().Error("No tag for entry %s\n", Entry.name);
585       return RESULT_FAIL;
586     }
587
588   Result_t result = MemIOWriter::WriteUi8(TmpTag.a);
589   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(TmpTag.b);
590
591   return result;
592 }
593
594 //
595 ASDCP::Result_t
596 ASDCP::MXF::TLVWriter::WriteObject(const MDDEntry& Entry, IArchive* Object)
597 {
598   ASDCP_TEST_NULL(Object);
599   Result_t result = WriteTag(Entry);
600
601   // write a temp length
602   byte_t* l_p = CurrentData();
603
604   if ( ASDCP_SUCCESS(result) )
605     MemIOWriter::WriteUi16BE(0);
606
607   if ( ASDCP_SUCCESS(result) )
608     {
609       ui32_t before = Size();
610       result = Object->Archive(*this);
611
612       if ( ASDCP_SUCCESS(result) ) 
613         i2p<ui16_t>(ASDCP_i16_BE( Size() - before), l_p);
614     }
615
616   return result;
617 }
618
619 //
620 ASDCP::Result_t
621 ASDCP::MXF::TLVWriter::WriteUi8(const MDDEntry& Entry, ui8_t* value)
622 {
623   ASDCP_TEST_NULL(value);
624   Result_t result = WriteTag(Entry);
625   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui8_t));
626   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi8(*value);
627   return result;
628 }
629
630 //
631 ASDCP::Result_t
632 ASDCP::MXF::TLVWriter::WriteUi16(const MDDEntry& Entry, ui16_t* value)
633 {
634   ASDCP_TEST_NULL(value);
635   Result_t result = WriteTag(Entry);
636   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui16_t));
637   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(*value);
638   return result;
639 }
640
641 //
642 ASDCP::Result_t
643 ASDCP::MXF::TLVWriter::WriteUi32(const MDDEntry& Entry, ui32_t* value)
644 {
645   ASDCP_TEST_NULL(value);
646   Result_t result = WriteTag(Entry);
647   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui32_t));
648   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi32BE(*value);
649   return result;
650 }
651
652 //
653 ASDCP::Result_t
654 ASDCP::MXF::TLVWriter::WriteUi64(const MDDEntry& Entry, ui64_t* value)
655 {
656   ASDCP_TEST_NULL(value);
657   Result_t result = WriteTag(Entry);
658   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi16BE(sizeof(ui64_t));
659   if ( ASDCP_SUCCESS(result) ) MemIOWriter::WriteUi64BE(*value);
660   return result;
661 }
662
663 //
664 // end MXFTypes.cpp
665 //