2 Copyright (c) 2005-2006, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
32 #define ASDCP_DECLARE_MDD
37 #include <hex_utils.h>
39 //------------------------------------------------------------------------------------------
42 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
44 const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
47 const ASDCP::MDDEntry*
48 ASDCP::GetMDDEntry(const byte_t* ul_buf)
53 // must be a pointer to a SMPTE UL
54 if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
57 // advance to first matching element
58 // TODO: optimize using binary search
59 while ( s_MDD_Table[t_idx].ul != 0
60 && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
63 if ( s_MDD_Table[t_idx].ul == 0 )
66 // match successive elements
67 while ( s_MDD_Table[t_idx].ul != 0
68 && k_idx < SMPTE_UL_LENGTH - 1
69 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
71 if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
77 while ( s_MDD_Table[t_idx].ul != 0
78 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
79 && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
82 while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
87 return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
90 //------------------------------------------------------------------------------------------
95 ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
97 ASDCP::fpos_t end_pos;
99 // go to the end - 4 bytes
100 Result_t result = Reader.Seek(0, ASDCP::SP_END);
102 if ( ASDCP_SUCCESS(result) )
103 result = Reader.Tell(&end_pos);
105 if ( ASDCP_SUCCESS(result)
106 && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
107 result = RESULT_FAIL; // File is smaller than an empty packet!
109 if ( ASDCP_SUCCESS(result) )
110 result = Reader.Seek(end_pos - 4);
112 // get the ui32_t RIP length
114 byte_t intbuf[MXF_BER_LENGTH];
117 if ( ASDCP_SUCCESS(result) )
119 result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
121 if ( ASDCP_SUCCESS(result) && read_count != 4 )
122 result = RESULT_FAIL;
125 if ( ASDCP_SUCCESS(result) )
127 rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
129 if ( rip_size > end_pos ) // RIP can't be bigger than the file
133 // reposition to start of RIP
134 if ( ASDCP_SUCCESS(result) )
135 result = Reader.Seek(end_pos - rip_size);
142 ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
144 Result_t result = KLVFilePacket::InitFromFile(Reader, s_MDD_Table[MDDindex_RandomIndexMetadata].ul);
146 if ( ASDCP_SUCCESS(result) )
148 MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
149 result = PairArray.ReadFrom(MemRDR);
152 if ( ASDCP_FAILURE(result) )
153 DefaultLogSink().Error("Failed to initialize RIP\n");
160 ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
162 Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_RandomIndexMetadata].ul, 0);
168 ASDCP::MXF::RIP::Dump(FILE* stream)
173 KLVFilePacket::Dump(stream, false);
174 PairArray.Dump(stream, false);
176 fputs("==========================================================================\n", stream);
179 //------------------------------------------------------------------------------------------
184 ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
186 Result_t result = KLVFilePacket::InitFromFile(Reader);
188 // could be one of several values
190 if ( ASDCP_SUCCESS(result) )
192 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
193 result = MemRDR.ReadUi16BE(&MajorVersion);
194 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion);
195 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize);
196 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition);
197 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition);
198 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition);
199 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount);
200 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount);
201 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID);
202 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset);
203 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID);
204 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.ReadFrom(MemRDR);
205 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.ReadFrom(MemRDR);
208 if ( ASDCP_FAILURE(result) )
209 DefaultLogSink().Error("Failed to initialize Partition\n");
216 ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer)
218 Result_t result = m_Buffer.Capacity(1024);
220 if ( ASDCP_SUCCESS(result) )
222 MemIOWriter MemWRT(m_Buffer.Data(), m_Buffer.Capacity());
223 result = MemWRT.WriteUi16BE(MajorVersion);
224 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion);
225 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize);
226 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition);
227 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition);
228 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition);
229 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount);
230 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount);
231 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID);
232 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset);
233 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID);
234 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.WriteTo(MemWRT);
235 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.WriteTo(MemWRT);
236 if ( ASDCP_SUCCESS(result) ) m_Buffer.Size(MemWRT.Size());
239 if ( ASDCP_SUCCESS(result) )
241 ui32_t write_count; // this is subclassed, so the UL is only right some of the time
242 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_ClosedCompleteHeader].ul, m_Buffer.Size());
244 if ( ASDCP_SUCCESS(result) )
245 result = Writer.Write(m_Buffer.RoData(), m_Buffer.Size(), &write_count);
253 ASDCP::MXF::Partition::Dump(FILE* stream)
255 char identbuf[IdentBufferLen];
256 char intbuf[IntBufferLen];
261 KLVFilePacket::Dump(stream, false);
262 fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
263 fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
264 fprintf(stream, " KAGSize = %lu\n", KAGSize);
265 fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf));
266 fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf));
267 fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf));
268 fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf));
269 fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf));
270 fprintf(stream, " IndexSID = %lu\n", IndexSID);
271 fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf));
272 fprintf(stream, " BodySID = %lu\n", BodySID);
273 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
274 fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
276 fputs("==========================================================================\n", stream);
280 //------------------------------------------------------------------------------------------
283 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
286 void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
288 ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
290 for ( ; i != Batch.end(); i++ )
291 insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
297 ASDCP::MXF::Primer::Primer() {}
300 ASDCP::MXF::Primer::~Primer() {}
304 ASDCP::MXF::Primer::ClearTagList()
306 LocalTagEntryBatch.clear();
307 m_Lookup = new h__PrimerLookup;
312 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
314 Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Primer].ul);
316 if ( ASDCP_SUCCESS(result) )
318 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
319 result = LocalTagEntryBatch.ReadFrom(MemRDR);
322 if ( ASDCP_SUCCESS(result) )
324 m_Lookup = new h__PrimerLookup;
325 m_Lookup->InitWithBatch(LocalTagEntryBatch);
328 if ( ASDCP_FAILURE(result) )
329 DefaultLogSink().Error("Failed to initialize Primer\n");
336 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
338 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
339 Result_t result = LocalTagEntryBatch.WriteTo(MemWRT);
340 Buffer.Size(MemWRT.Size());
342 if ( ASDCP_SUCCESS(result) )
345 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_Primer].ul, Buffer.Size());
347 if ( ASDCP_SUCCESS(result) )
348 result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
357 ASDCP::MXF::Primer::InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
361 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
363 if ( i == m_Lookup->end() )
365 const MDDEntry* mdde = GetMDDEntry(Key.Data());
368 LocalTagEntry TmpEntry;
370 TmpEntry.Tag = mdde->tag;
372 LocalTagEntryBatch.push_back(TmpEntry);
373 m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
381 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
384 if ( m_Lookup.empty() )
386 DefaultLogSink().Error("Primer lookup is empty\n");
390 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
392 if ( i == m_Lookup->end() )
401 ASDCP::MXF::Primer::Dump(FILE* stream)
403 char identbuf[IdentBufferLen];
408 KLVPacket::Dump(stream, false);
409 fprintf(stream, "Primer: %lu %s\n",
410 LocalTagEntryBatch.ItemCount,
411 ( LocalTagEntryBatch.ItemCount == 1 ? "entry" : "entries" ));
413 Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
414 for ( ; i != LocalTagEntryBatch.end(); i++ )
416 const MDDEntry* Entry = GetMDDEntry((*i).UL.Data());
417 fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
420 fputs("==========================================================================\n", stream);
424 //------------------------------------------------------------------------------------------
429 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
433 Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Preface].ul);
435 if ( ASDCP_SUCCESS(result) )
437 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
439 result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
440 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
441 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
442 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Preface, Version));
443 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
444 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
445 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
446 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
447 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
448 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
449 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
452 if ( ASDCP_FAILURE(result) )
453 DefaultLogSink().Error("Failed to initialize Preface\n");
460 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
462 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
463 Result_t result = MemWRT.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
464 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
465 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
466 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
467 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
468 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
469 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
470 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
471 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
472 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
473 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
475 if ( ASDCP_SUCCESS(result) )
477 ui32_t packet_length = MemWRT.Size();
478 result = WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Preface].ul, packet_length);
480 if ( ASDCP_SUCCESS(result) )
481 Buffer.Size(Buffer.Size() + packet_length);
489 ASDCP::MXF::Preface::Dump(FILE* stream)
491 char identbuf[IdentBufferLen];
496 KLVPacket::Dump(stream, false);
497 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
498 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
499 fprintf(stream, " LastModifiedDate = %s\n", LastModifiedDate.ToString(identbuf));
500 fprintf(stream, " Version = %hu\n", Version);
501 fprintf(stream, " ObjectModelVersion = %lu\n", ObjectModelVersion);
502 fprintf(stream, " PrimaryPackage = %s\n", PrimaryPackage.ToString(identbuf));
503 fprintf(stream, " Identifications:\n"); Identifications.Dump(stream);
504 fprintf(stream, " ContentStorage = %s\n", ContentStorage.ToString(identbuf));
505 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
506 fprintf(stream, " EssenceContainers:\n"); EssenceContainers.Dump(stream);
507 fprintf(stream, " DMSchemes:\n"); DMSchemes.Dump(stream);
509 fputs("==========================================================================\n", stream);
512 //------------------------------------------------------------------------------------------
516 class ASDCP::MXF::h__PacketList
519 std::list<InterchangeObject*> m_List;
520 std::map<UL, InterchangeObject*> m_Map;
523 while ( ! m_List.empty() )
525 delete m_List.back();
531 void AddPacket(InterchangeObject* ThePacket)
534 m_Map.insert(std::map<UID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
535 m_List.push_back(ThePacket);
539 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
541 ASDCP_TEST_NULL(ObjectID);
542 ASDCP_TEST_NULL(Object);
543 std::list<InterchangeObject*>::iterator li;
546 for ( li = m_List.begin(); li != m_List.end(); li++ )
548 if ( (*li)->HasUL(ObjectID) )
559 //------------------------------------------------------------------------------------------
562 ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false)
564 m_PacketList = new h__PacketList;
568 ASDCP::MXF::OPAtomHeader::~OPAtomHeader()
574 ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
577 Result_t result = SeekToRIP(Reader);
579 if ( ASDCP_SUCCESS(result) )
581 result = m_RIP.InitFromFile(Reader);
583 if ( ASDCP_FAILURE(result) )
585 DefaultLogSink().Error("File contains no RIP\n");
594 if ( ASDCP_SUCCESS(result) )
595 result = Reader.Seek(0);
597 if ( ASDCP_SUCCESS(result) )
598 result = Partition::InitFromFile(Reader); // test UL and OP
600 // slurp up the remainder of the header
603 if ( ASDCP_SUCCESS(result) )
605 ui32_t buf_len = HeaderByteCount;
606 result = m_Buffer.Capacity(buf_len);
609 if ( ASDCP_SUCCESS(result) )
610 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
612 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
614 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
615 m_Buffer.Capacity(), read_count);
619 const byte_t* p = m_Buffer.RoData();
620 const byte_t* end_p = p + m_Buffer.Capacity();
622 while ( ASDCP_SUCCESS(result) && p < end_p )
624 // parse the packets and index them by uid, discard KLVFill items
625 InterchangeObject* object = CreateObject(p);
628 object->m_Lookup = &m_Primer;
629 result = object->InitFromBuffer(p, end_p - p);
630 const byte_t* redo_p = p;
631 p += object->PacketLength();
632 // hexdump(p, object->PacketLength());
634 if ( ASDCP_SUCCESS(result) )
636 if ( object->IsA(s_MDD_Table[MDDindex_KLVFill].ul) )
640 else if ( object->IsA(s_MDD_Table[MDDindex_Primer].ul) )
643 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
645 else if ( object->IsA(s_MDD_Table[MDDindex_Preface].ul) )
651 m_PacketList->AddPacket(object);
656 DefaultLogSink().Error("Error initializing packet\n");
666 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
668 InterchangeObject* TmpObject;
673 return m_PacketList->GetMDObjectByType(ObjectID, Object);
677 ASDCP::MXF::Identification*
678 ASDCP::MXF::OPAtomHeader::GetIdentification()
680 InterchangeObject* Object;
682 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
683 return (Identification*)Object;
689 ASDCP::MXF::SourcePackage*
690 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
692 InterchangeObject* Object;
694 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
695 return (SourcePackage*)Object;
702 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
704 if ( HeaderSize < 4096 )
706 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
710 ASDCP::FrameBuffer HeaderBuffer;
712 Result_t result = HeaderBuffer.Capacity(HeaderSize);
713 HeaderByteCount = HeaderSize;
715 if ( ASDCP_SUCCESS(result) )
718 m_Preface->m_Lookup = &m_Primer;
719 result = m_Preface->WriteToBuffer(HeaderBuffer);
722 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
723 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
725 InterchangeObject* object = *pl_i;
726 object->m_Lookup = &m_Primer;
727 result = object->WriteToBuffer(HeaderBuffer);
730 if ( ASDCP_SUCCESS(result) )
731 result = Partition::WriteToFile(Writer);
733 // if ( ASDCP_SUCCESS(result) )
734 // result = m_Primer.WriteToFile(Writer);
736 if ( ASDCP_SUCCESS(result) )
739 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
740 assert(write_count == HeaderBuffer.Size());
744 if ( ASDCP_SUCCESS(result) )
746 ASDCP::fpos_t pos = Writer.Tell();
748 if ( pos > HeaderSize )
750 char intbuf[IntBufferLen];
751 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
757 ASDCP::FrameBuffer NilBuf;
758 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
760 if ( klv_fill_length < kl_length )
762 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
766 klv_fill_length -= kl_length;
767 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
769 if ( ASDCP_SUCCESS(result) )
770 result = NilBuf.Capacity(klv_fill_length);
772 if ( ASDCP_SUCCESS(result) )
774 memset(NilBuf.Data(), 0, klv_fill_length);
776 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
777 assert(write_count == klv_fill_length);
786 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
794 Partition::Dump(stream);
795 m_Primer.Dump(stream);
797 m_Preface->Dump(stream);
799 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
800 for ( ; i != m_PacketList->m_List.end(); i++ )
804 //------------------------------------------------------------------------------------------
807 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
809 m_PacketList = new h__PacketList;
813 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
819 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
821 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
823 // slurp up the remainder of the footer
826 if ( ASDCP_SUCCESS(result) )
827 result = m_Buffer.Capacity(IndexByteCount);
829 if ( ASDCP_SUCCESS(result) )
830 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
832 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
834 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
835 read_count, m_Buffer.Capacity());
839 const byte_t* p = m_Buffer.RoData();
840 const byte_t* end_p = p + m_Buffer.Capacity();
842 while ( ASDCP_SUCCESS(result) && p < end_p )
844 // parse the packets and index them by uid, discard KLVFill items
845 InterchangeObject* object = CreateObject(p);
848 object->m_Lookup = m_Lookup;
849 result = object->InitFromBuffer(p, end_p - p);
850 p += object->PacketLength();
852 if ( ASDCP_SUCCESS(result) )
854 m_PacketList->AddPacket(object);
858 DefaultLogSink().Error("Error initializing packet\n");
863 if ( ASDCP_FAILURE(result) )
864 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
871 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
873 Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
879 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
884 Partition::Dump(stream);
886 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
887 for ( ; i != m_PacketList->m_List.end(); i++ )
893 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
895 std::list<InterchangeObject*>::iterator li;
896 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
898 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
900 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
901 ui64_t start_pos = Segment->IndexStartPosition;
903 if ( Segment->EditUnitByteCount > 0 )
905 if ( m_PacketList->m_List.size() > 1 )
906 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
908 if ( ! Segment->IndexEntryArray.empty() )
909 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
911 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
914 else if ( (ui64_t)frame_num >= start_pos
915 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
917 Entry = Segment->IndexEntryArray[frame_num];
927 //------------------------------------------------------------------------------------------
932 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
934 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
935 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
941 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
943 if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
945 DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
947 return RESULT_READFAIL;
950 Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
952 if ( ASDCP_SUCCESS(result) )
954 memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
955 Buffer.Size(Buffer.Size() + m_ValueLength);
963 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
965 if ( m_KLLength == 0 )
968 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
972 //------------------------------------------------------------------------------------------
986 FLT_TimecodeComponent,
988 FLT_WaveAudioDescriptor,
989 FLT_GenericPictureEssenceDescriptor,
990 FLT_MPEG2VideoDescriptor,
991 FLT_RGBAEssenceDescriptor,
992 FLT_JPEG2000PictureSubDescriptor,
993 FLT_IndexTableSegment,
994 FLT_CryptographicFramework,
995 FLT_CryptographicContext
999 typedef std::map<ASDCP::UL, FLT_t>::iterator FLi_t;
1001 class FactoryList : public std::map<ASDCP::UL, FLT_t>
1003 ASDCP::Mutex m_Lock;
1010 ASDCP::AutoMutex BlockLock(m_Lock);
1014 FLi_t Find(const byte_t* label) {
1015 ASDCP::AutoMutex BlockLock(m_Lock);
1020 ASDCP::AutoMutex BlockLock(m_Lock);
1027 static FactoryList s_FactoryList;
1029 #define SETUP_IDX(t) const ui32_t FLT_##t = v;
1030 #define SETUP_FACTORY(t) s_FactoryList.insert(FactoryList::value_type(s_MDD_Table[MDDindex_##t].ul, FLT_##t));
1031 #define CASE_FACTORY(t) case FLT_##t: return new t
1034 ASDCP::MXF::InterchangeObject*
1035 ASDCP::MXF::CreateObject(const byte_t* label)
1040 if ( s_FactoryList.empty() )
1042 SETUP_FACTORY(Preface);
1043 SETUP_FACTORY(Identification);
1044 SETUP_FACTORY(ContentStorage);
1045 SETUP_FACTORY(MaterialPackage);
1046 SETUP_FACTORY(SourcePackage);
1047 SETUP_FACTORY(Track);
1048 SETUP_FACTORY(Sequence);
1049 SETUP_FACTORY(SourceClip);
1050 SETUP_FACTORY(TimecodeComponent);
1051 SETUP_FACTORY(FileDescriptor);
1052 SETUP_FACTORY(WaveAudioDescriptor);
1053 SETUP_FACTORY(GenericPictureEssenceDescriptor);
1054 SETUP_FACTORY(MPEG2VideoDescriptor);
1055 SETUP_FACTORY(RGBAEssenceDescriptor);
1056 SETUP_FACTORY(JPEG2000PictureSubDescriptor);
1057 SETUP_FACTORY(IndexTableSegment);
1058 SETUP_FACTORY(CryptographicFramework);
1059 SETUP_FACTORY(CryptographicContext);
1062 FLi_t i = s_FactoryList.find(label);
1064 if ( i == s_FactoryList.end() )
1065 return new InterchangeObject;
1067 switch ( i->second )
1069 CASE_FACTORY(Preface);
1070 CASE_FACTORY(Identification);
1071 CASE_FACTORY(ContentStorage);
1072 CASE_FACTORY(MaterialPackage);
1073 CASE_FACTORY(SourcePackage);
1074 CASE_FACTORY(Track);
1075 CASE_FACTORY(Sequence);
1076 CASE_FACTORY(SourceClip);
1077 CASE_FACTORY(TimecodeComponent);
1078 CASE_FACTORY(FileDescriptor);
1079 CASE_FACTORY(WaveAudioDescriptor);
1080 CASE_FACTORY(GenericPictureEssenceDescriptor);
1081 CASE_FACTORY(MPEG2VideoDescriptor);
1082 CASE_FACTORY(RGBAEssenceDescriptor);
1083 CASE_FACTORY(JPEG2000PictureSubDescriptor);
1084 CASE_FACTORY(IndexTableSegment);
1085 CASE_FACTORY(CryptographicFramework);
1086 CASE_FACTORY(CryptographicContext);
1089 return new InterchangeObject;