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);
676 ASDCP::MXF::Identification*
677 ASDCP::MXF::OPAtomHeader::GetIdentification()
679 InterchangeObject* Object;
681 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
682 return (Identification*)Object;
689 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
691 if ( HeaderSize < 4096 )
693 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
697 ASDCP::FrameBuffer HeaderBuffer;
699 Result_t result = HeaderBuffer.Capacity(HeaderSize);
700 HeaderByteCount = HeaderSize;
702 if ( ASDCP_SUCCESS(result) )
705 m_Preface->m_Lookup = &m_Primer;
706 result = m_Preface->WriteToBuffer(HeaderBuffer);
709 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
710 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
712 InterchangeObject* object = *pl_i;
713 object->m_Lookup = &m_Primer;
714 result = object->WriteToBuffer(HeaderBuffer);
717 if ( ASDCP_SUCCESS(result) )
718 result = Partition::WriteToFile(Writer);
720 // if ( ASDCP_SUCCESS(result) )
721 // result = m_Primer.WriteToFile(Writer);
723 if ( ASDCP_SUCCESS(result) )
726 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
727 assert(write_count == HeaderBuffer.Size());
731 if ( ASDCP_SUCCESS(result) )
733 ASDCP::fpos_t pos = Writer.Tell();
735 if ( pos > HeaderSize )
737 char intbuf[IntBufferLen];
738 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
744 ASDCP::FrameBuffer NilBuf;
745 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
747 if ( klv_fill_length < kl_length )
749 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
753 klv_fill_length -= kl_length;
754 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
756 if ( ASDCP_SUCCESS(result) )
757 result = NilBuf.Capacity(klv_fill_length);
759 if ( ASDCP_SUCCESS(result) )
761 memset(NilBuf.Data(), 0, klv_fill_length);
763 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
764 assert(write_count == klv_fill_length);
773 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
781 Partition::Dump(stream);
782 m_Primer.Dump(stream);
784 m_Preface->Dump(stream);
786 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
787 for ( ; i != m_PacketList->m_List.end(); i++ )
791 //------------------------------------------------------------------------------------------
794 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
796 m_PacketList = new h__PacketList;
800 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
806 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
808 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
810 // slurp up the remainder of the footer
813 if ( ASDCP_SUCCESS(result) )
814 result = m_Buffer.Capacity(IndexByteCount);
816 if ( ASDCP_SUCCESS(result) )
817 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
819 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
821 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
822 read_count, m_Buffer.Capacity());
826 const byte_t* p = m_Buffer.RoData();
827 const byte_t* end_p = p + m_Buffer.Capacity();
829 while ( ASDCP_SUCCESS(result) && p < end_p )
831 // parse the packets and index them by uid, discard KLVFill items
832 InterchangeObject* object = CreateObject(p);
835 object->m_Lookup = m_Lookup;
836 result = object->InitFromBuffer(p, end_p - p);
837 p += object->PacketLength();
839 if ( ASDCP_SUCCESS(result) )
841 m_PacketList->AddPacket(object);
845 DefaultLogSink().Error("Error initializing packet\n");
850 if ( ASDCP_FAILURE(result) )
851 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
858 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
860 Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
866 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
871 Partition::Dump(stream);
873 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
874 for ( ; i != m_PacketList->m_List.end(); i++ )
880 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
882 std::list<InterchangeObject*>::iterator li;
883 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
885 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
887 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
888 ui64_t start_pos = Segment->IndexStartPosition;
890 if ( Segment->EditUnitByteCount > 0 )
892 if ( m_PacketList->m_List.size() > 1 )
893 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
895 if ( ! Segment->IndexEntryArray.empty() )
896 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
898 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
901 else if ( (ui64_t)frame_num >= start_pos
902 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
904 Entry = Segment->IndexEntryArray[frame_num];
914 //------------------------------------------------------------------------------------------
919 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
921 if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
923 DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
925 return RESULT_READFAIL;
928 Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
930 if ( ASDCP_SUCCESS(result) )
932 memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
933 Buffer.Size(Buffer.Size() + m_ValueLength);
941 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
943 if ( m_KLLength == 0 )
946 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
950 //------------------------------------------------------------------------------------------
964 FLT_TimecodeComponent,
966 FLT_WaveAudioDescriptor,
967 FLT_GenericPictureEssenceDescriptor,
968 FLT_MPEG2VideoDescriptor,
969 FLT_RGBAEssenceDescriptor,
970 FLT_JPEG2000PictureSubDescriptor,
971 FLT_IndexTableSegment,
972 FLT_CryptographicFramework,
973 FLT_CryptographicContext
977 typedef std::map<ASDCP::UL, FLT_t> FactoryList;
978 #define SETUP_IDX(t) const ui32_t FLT_##t = v;
980 static FactoryList s_FactoryList;
981 #define SETUP_FACTORY(t) s_FactoryList.insert(FactoryList::value_type(s_MDD_Table[MDDindex_##t].ul, FLT_##t));
982 #define CASE_FACTORY(t) case FLT_##t: return new t
985 ASDCP::MXF::InterchangeObject*
986 ASDCP::MXF::CreateObject(const byte_t* label)
991 if ( s_FactoryList.empty() )
993 SETUP_FACTORY(Preface);
994 SETUP_FACTORY(Identification);
995 SETUP_FACTORY(ContentStorage);
996 SETUP_FACTORY(MaterialPackage);
997 SETUP_FACTORY(SourcePackage);
998 SETUP_FACTORY(Track);
999 SETUP_FACTORY(Sequence);
1000 SETUP_FACTORY(SourceClip);
1001 SETUP_FACTORY(TimecodeComponent);
1002 SETUP_FACTORY(FileDescriptor);
1003 SETUP_FACTORY(WaveAudioDescriptor);
1004 SETUP_FACTORY(GenericPictureEssenceDescriptor);
1005 SETUP_FACTORY(MPEG2VideoDescriptor);
1006 SETUP_FACTORY(RGBAEssenceDescriptor);
1007 SETUP_FACTORY(JPEG2000PictureSubDescriptor);
1008 SETUP_FACTORY(IndexTableSegment);
1009 SETUP_FACTORY(CryptographicFramework);
1010 SETUP_FACTORY(CryptographicContext);
1013 FactoryList::iterator i = s_FactoryList.find(label);
1015 if ( i == s_FactoryList.end() )
1016 return new InterchangeObject;
1018 switch ( i->second )
1020 CASE_FACTORY(Preface);
1021 CASE_FACTORY(Identification);
1022 CASE_FACTORY(ContentStorage);
1023 CASE_FACTORY(MaterialPackage);
1024 CASE_FACTORY(SourcePackage);
1025 CASE_FACTORY(Track);
1026 CASE_FACTORY(Sequence);
1027 CASE_FACTORY(SourceClip);
1028 CASE_FACTORY(TimecodeComponent);
1029 CASE_FACTORY(FileDescriptor);
1030 CASE_FACTORY(WaveAudioDescriptor);
1031 CASE_FACTORY(GenericPictureEssenceDescriptor);
1032 CASE_FACTORY(MPEG2VideoDescriptor);
1033 CASE_FACTORY(RGBAEssenceDescriptor);
1034 CASE_FACTORY(JPEG2000PictureSubDescriptor);
1035 CASE_FACTORY(IndexTableSegment);
1036 CASE_FACTORY(CryptographicFramework);
1037 CASE_FACTORY(CryptographicContext);
1040 return new InterchangeObject;