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.
33 #include "hex_utils.h"
36 //------------------------------------------------------------------------------------------
39 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
43 ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
45 ASDCP::fpos_t end_pos;
47 // go to the end - 4 bytes
48 Result_t result = Reader.Seek(0, ASDCP::SP_END);
50 if ( ASDCP_SUCCESS(result) )
51 result = Reader.Tell(&end_pos);
53 if ( ASDCP_SUCCESS(result)
54 && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
55 result = RESULT_FAIL; // File is smaller than an empty packet!
57 if ( ASDCP_SUCCESS(result) )
58 result = Reader.Seek(end_pos - 4);
60 // get the ui32_t RIP length
62 byte_t intbuf[MXF_BER_LENGTH];
65 if ( ASDCP_SUCCESS(result) )
67 result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
69 if ( ASDCP_SUCCESS(result) && read_count != 4 )
73 if ( ASDCP_SUCCESS(result) )
75 rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
77 if ( rip_size > end_pos ) // RIP can't be bigger than the file
81 // reposition to start of RIP
82 if ( ASDCP_SUCCESS(result) )
83 result = Reader.Seek(end_pos - rip_size);
90 ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
92 Result_t result = KLVFilePacket::InitFromFile(Reader, Dict::ul(MDD_RandomIndexMetadata));
94 if ( ASDCP_SUCCESS(result) )
96 MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
97 result = PairArray.Unarchive(MemRDR);
100 if ( ASDCP_FAILURE(result) )
101 DefaultLogSink().Error("Failed to initialize RIP\n");
108 ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
110 ASDCP::FrameBuffer Buffer;
111 ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4;
112 Result_t result = Buffer.Capacity(RIPSize);
114 if ( ASDCP_SUCCESS(result) )
115 result = WriteKLToFile(Writer, Dict::ul(MDD_RandomIndexMetadata), RIPSize);
117 if ( ASDCP_SUCCESS(result) )
119 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
120 result = PairArray.Archive(MemWRT);
122 if ( ASDCP_SUCCESS(result) )
123 MemWRT.WriteUi32BE(RIPSize + 20);
125 if ( ASDCP_SUCCESS(result) )
126 Buffer.Size(MemWRT.Size());
129 if ( ASDCP_SUCCESS(result) )
130 result = Writer.Write(Buffer.RoData(), Buffer.Size());
137 ASDCP::MXF::RIP::Dump(FILE* stream)
142 KLVFilePacket::Dump(stream, false);
143 PairArray.Dump(stream, false);
145 fputs("==========================================================================\n", stream);
148 //------------------------------------------------------------------------------------------
152 class ASDCP::MXF::Partition::h__PacketList
155 std::list<InterchangeObject*> m_List;
156 std::map<UUID, InterchangeObject*> m_Map;
159 while ( ! m_List.empty() )
161 delete m_List.back();
167 void AddPacket(InterchangeObject* ThePacket)
170 m_Map.insert(std::map<UUID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
171 m_List.push_back(ThePacket);
175 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
177 ASDCP_TEST_NULL(ObjectID);
178 ASDCP_TEST_NULL(Object);
179 std::list<InterchangeObject*>::iterator li;
182 for ( li = m_List.begin(); li != m_List.end(); li++ )
184 if ( (*li)->HasUL(ObjectID) )
195 //------------------------------------------------------------------------------------------
199 ASDCP::MXF::Partition::Partition() :
200 MajorVersion(1), MinorVersion(2),
201 KAGSize(1), ThisPartition(0), PreviousPartition(0),
202 FooterPartition(0), HeaderByteCount(0), IndexByteCount(0), IndexSID(0),
203 BodyOffset(0), BodySID(1)
205 m_PacketList = new h__PacketList;
208 ASDCP::MXF::Partition::~Partition()
214 ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object)
218 TmpID.GenRandomValue();
219 Object->InstanceUID = TmpID;
220 m_PacketList->AddPacket(Object);
225 ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
227 Result_t result = KLVFilePacket::InitFromFile(Reader);
229 // could be one of several values
231 if ( ASDCP_SUCCESS(result) )
233 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
234 result = MemRDR.ReadUi16BE(&MajorVersion);
235 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion);
236 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize);
237 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition);
238 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition);
239 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition);
240 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount);
241 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount);
242 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID);
243 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset);
244 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID);
245 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Unarchive(MemRDR);
246 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Unarchive(MemRDR);
249 if ( ASDCP_FAILURE(result) )
250 DefaultLogSink().Error("Failed to initialize Partition\n");
257 ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer, UL& PartitionLabel)
259 ASDCP::FrameBuffer Buffer;
260 Result_t result = Buffer.Capacity(1024);
262 if ( ASDCP_SUCCESS(result) )
264 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
265 result = MemWRT.WriteUi16BE(MajorVersion);
266 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion);
267 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize);
268 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition);
269 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition);
270 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition);
271 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount);
272 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount);
273 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID);
274 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset);
275 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID);
276 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Archive(MemWRT);
277 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Archive(MemWRT);
278 if ( ASDCP_SUCCESS(result) ) Buffer.Size(MemWRT.Size());
281 if ( ASDCP_SUCCESS(result) )
284 result = WriteKLToFile(Writer, PartitionLabel.Value(), Buffer.Size());
286 if ( ASDCP_SUCCESS(result) )
287 result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
295 ASDCP::MXF::Partition::ArchiveSize()
298 + sizeof(ui16_t) + sizeof(ui16_t)
300 + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t)
305 + sizeof(ui32_t) + sizeof(ui32_t) + ( UUIDlen * EssenceContainers.size() ) );
310 ASDCP::MXF::Partition::Dump(FILE* stream)
312 char identbuf[IdentBufferLen];
313 char intbuf[IntBufferLen];
318 KLVFilePacket::Dump(stream, false);
319 fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
320 fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
321 fprintf(stream, " KAGSize = %lu\n", KAGSize);
322 fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf));
323 fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf));
324 fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf));
325 fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf));
326 fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf));
327 fprintf(stream, " IndexSID = %lu\n", IndexSID);
328 fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf));
329 fprintf(stream, " BodySID = %lu\n", BodySID);
330 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
331 fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
333 fputs("==========================================================================\n", stream);
337 //------------------------------------------------------------------------------------------
340 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
343 void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
345 ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
347 for ( ; i != Batch.end(); i++ )
348 insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
354 ASDCP::MXF::Primer::Primer() : m_LocalTag(0xff) {}
357 ASDCP::MXF::Primer::~Primer() {}
361 ASDCP::MXF::Primer::ClearTagList()
363 LocalTagEntryBatch.clear();
364 m_Lookup = new h__PrimerLookup;
369 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
371 Result_t result = KLVPacket::InitFromBuffer(p, l, Dict::ul(MDD_Primer));
373 if ( ASDCP_SUCCESS(result) )
375 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
376 result = LocalTagEntryBatch.Unarchive(MemRDR);
379 if ( ASDCP_SUCCESS(result) )
381 m_Lookup = new h__PrimerLookup;
382 m_Lookup->InitWithBatch(LocalTagEntryBatch);
385 if ( ASDCP_FAILURE(result) )
386 DefaultLogSink().Error("Failed to initialize Primer\n");
393 ASDCP::MXF::Primer::WriteToFile(ASDCP::FileWriter& Writer)
395 ASDCP::FrameBuffer Buffer;
396 Result_t result = Buffer.Capacity(128*1024);
398 if ( ASDCP_SUCCESS(result) )
399 result = WriteToBuffer(Buffer);
401 if ( ASDCP_SUCCESS(result) )
402 result = Writer.Write(Buffer.RoData(), Buffer.Size());
409 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
411 ASDCP::FrameBuffer LocalTagBuffer;
412 MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length);
413 Result_t result = LocalTagEntryBatch.Archive(MemWRT);
415 if ( ASDCP_SUCCESS(result) )
417 ui32_t packet_length = MemWRT.Size();
418 result = WriteKLToBuffer(Buffer, Dict::ul(MDD_Primer), packet_length);
420 if ( ASDCP_SUCCESS(result) )
421 Buffer.Size(Buffer.Size() + packet_length);
429 ASDCP::MXF::Primer::InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag)
433 std::map<UL, TagValue>::iterator i = m_Lookup->find(TestUL);
435 if ( i == m_Lookup->end() )
437 if ( Entry.tag.a == 0 && Entry.tag.b == 0 )
440 Tag.b = m_LocalTag--;
448 LocalTagEntry TmpEntry;
449 TmpEntry.UL = TestUL;
452 LocalTagEntryBatch.push_back(TmpEntry);
453 m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
465 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
468 if ( m_Lookup.empty() )
470 DefaultLogSink().Error("Primer lookup is empty\n");
474 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
476 if ( i == m_Lookup->end() )
485 ASDCP::MXF::Primer::Dump(FILE* stream)
487 char identbuf[IdentBufferLen];
492 KLVPacket::Dump(stream, false);
493 fprintf(stream, "Primer: %lu %s\n",
494 LocalTagEntryBatch.size(),
495 ( LocalTagEntryBatch.size() == 1 ? "entry" : "entries" ));
497 Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
498 for ( ; i != LocalTagEntryBatch.end(); i++ )
500 const MDDEntry* Entry = Dict::FindUL((*i).UL.Value());
501 fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
504 fputs("==========================================================================\n", stream);
508 //------------------------------------------------------------------------------------------
513 ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
515 Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
516 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
517 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version));
518 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
519 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
520 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
521 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
522 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
523 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
524 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
530 ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
532 Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
533 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
534 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
535 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
536 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
537 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
538 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
539 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
540 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
541 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
547 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
549 m_Typeinfo = &Dict::Type(MDD_Preface);
550 return InterchangeObject::InitFromBuffer(p, l);
555 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
557 m_Typeinfo = &Dict::Type(MDD_Preface);
558 return InterchangeObject::WriteToBuffer(Buffer);
563 ASDCP::MXF::Preface::Dump(FILE* stream)
565 char identbuf[IdentBufferLen];
570 InterchangeObject::Dump(stream);
571 fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.ToString(identbuf));
572 fprintf(stream, " %22s = %hu\n", "Version", Version);
573 fprintf(stream, " %22s = %lu\n", "ObjectModelVersion", ObjectModelVersion);
574 fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.ToString(identbuf));
575 fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream);
576 fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.ToString(identbuf));
577 fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.ToString(identbuf));
578 fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream);
579 fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream);
582 //------------------------------------------------------------------------------------------
585 ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false) {}
586 ASDCP::MXF::OPAtomHeader::~OPAtomHeader() {}
590 ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
593 Result_t result = SeekToRIP(Reader);
595 if ( ASDCP_SUCCESS(result) )
597 result = m_RIP.InitFromFile(Reader);
598 ui32_t test_s = m_RIP.PairArray.size();
600 if ( ASDCP_FAILURE(result) )
602 DefaultLogSink().Error("File contains no RIP\n");
605 else if ( test_s == 0 )
607 DefaultLogSink().Error("RIP contains no Pairs.\n");
608 result = RESULT_FORMAT;
610 else if ( test_s < 2 || test_s > 3 )
612 // OP-Atom states that there will be either two or three partitions,
613 // one closed header and one closed footer with an optional body
614 DefaultLogSink().Error("RIP count is not 2 or 3: %lu\n", test_s);
615 return RESULT_FORMAT;
623 if ( ASDCP_SUCCESS(result) )
625 Array<RIP::Pair>::iterator r_i = m_RIP.PairArray.begin();
627 if ( (*r_i).ByteOffset != 0 )
629 DefaultLogSink().Error("First Partition in RIP is not at offset 0.\n");
630 result = RESULT_FORMAT;
634 if ( ASDCP_SUCCESS(result) )
635 result = Reader.Seek(0);
637 if ( ASDCP_SUCCESS(result) )
638 result = Partition::InitFromFile(Reader); // test UL and OP
640 // is it really OP-Atom?
641 UL OPAtomUL(Dict::ul(MDD_OPAtom));
642 UL InteropOPAtomUL(Dict::ul(MDD_MXFInterop_OPAtom));
644 if ( ! ( OperationalPattern == OPAtomUL || OperationalPattern == InteropOPAtomUL ) )
646 char strbuf[IntBufferLen];
647 const MDDEntry* Entry = Dict::FindUL(OperationalPattern.Value());
649 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", OperationalPattern.ToString(strbuf));
651 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", Entry->name);
654 // slurp up the remainder of the header
655 if ( ASDCP_SUCCESS(result) )
657 if ( HeaderByteCount < 1024 )
658 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %lu\n", HeaderByteCount);
660 result = m_Buffer.Capacity(HeaderByteCount);
663 if ( ASDCP_SUCCESS(result) )
666 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
668 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
670 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
671 m_Buffer.Capacity(), read_count);
676 const byte_t* p = m_Buffer.RoData();
677 const byte_t* end_p = p + m_Buffer.Capacity();
679 while ( ASDCP_SUCCESS(result) && p < end_p )
681 // parse the packets and index them by uid, discard KLVFill items
682 InterchangeObject* object = CreateObject(p);
685 object->m_Lookup = &m_Primer;
686 result = object->InitFromBuffer(p, end_p - p);
687 const byte_t* redo_p = p;
688 p += object->PacketLength();
689 // hexdump(p, object->PacketLength());
691 if ( ASDCP_SUCCESS(result) )
693 if ( object->IsA(Dict::ul(MDD_KLVFill)) )
697 else if ( object->IsA(Dict::ul(MDD_Primer)) )
700 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
702 else if ( object->IsA(Dict::ul(MDD_Preface)) )
704 assert(m_Preface == 0);
705 m_Preface = (Preface*)object;
709 m_PacketList->AddPacket(object);
714 DefaultLogSink().Error("Error initializing packet\n");
724 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
726 InterchangeObject* TmpObject;
731 return m_PacketList->GetMDObjectByType(ObjectID, Object);
735 ASDCP::MXF::Identification*
736 ASDCP::MXF::OPAtomHeader::GetIdentification()
738 InterchangeObject* Object;
740 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
741 return (Identification*)Object;
747 ASDCP::MXF::SourcePackage*
748 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
750 InterchangeObject* Object;
752 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
753 return (SourcePackage*)Object;
761 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
763 if ( m_Preface == 0 )
766 if ( HeaderSize < 4096 )
768 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n", HeaderSize);
772 ASDCP::FrameBuffer HeaderBuffer;
773 HeaderByteCount = HeaderSize - ArchiveSize();
774 Result_t result = HeaderBuffer.Capacity(HeaderByteCount);
775 m_Preface->m_Lookup = &m_Primer;
777 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
778 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
780 InterchangeObject* object = *pl_i;
781 object->m_Lookup = &m_Primer;
783 ASDCP::FrameBuffer WriteWrapper;
784 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
785 HeaderBuffer.Capacity() - HeaderBuffer.Size());
786 result = object->WriteToBuffer(WriteWrapper);
787 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
790 if ( ASDCP_SUCCESS(result) )
792 UL TmpUL(Dict::ul(MDD_ClosedCompleteHeader));
793 result = Partition::WriteToFile(Writer, TmpUL);
796 if ( ASDCP_SUCCESS(result) )
797 result = m_Primer.WriteToFile(Writer);
799 if ( ASDCP_SUCCESS(result) )
802 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
803 assert(write_count == HeaderBuffer.Size());
807 if ( ASDCP_SUCCESS(result) )
809 ASDCP::fpos_t pos = Writer.Tell();
811 if ( pos > (ASDCP::fpos_t)HeaderByteCount )
813 char intbuf[IntBufferLen];
814 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
820 ASDCP::FrameBuffer NilBuf;
821 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
823 if ( klv_fill_length < kl_length )
825 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
829 klv_fill_length -= kl_length;
830 result = WriteKLToFile(Writer, Dict::ul(MDD_KLVFill), klv_fill_length);
832 if ( ASDCP_SUCCESS(result) )
833 result = NilBuf.Capacity(klv_fill_length);
835 if ( ASDCP_SUCCESS(result) )
837 memset(NilBuf.Data(), 0, klv_fill_length);
839 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
840 assert(write_count == klv_fill_length);
849 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
857 Partition::Dump(stream);
858 m_Primer.Dump(stream);
860 if ( m_Preface == 0 )
861 fputs("No Preface loaded\n", stream);
863 m_Preface->Dump(stream);
865 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
866 for ( ; i != m_PacketList->m_List.end(); i++ )
870 //------------------------------------------------------------------------------------------
873 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() :
874 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
875 m_ECOffset(0), m_Lookup(0)
881 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
885 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
887 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
889 // slurp up the remainder of the footer
892 if ( ASDCP_SUCCESS(result) )
893 result = m_Buffer.Capacity(IndexByteCount);
895 if ( ASDCP_SUCCESS(result) )
896 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
898 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
900 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
901 read_count, m_Buffer.Capacity());
905 const byte_t* p = m_Buffer.RoData();
906 const byte_t* end_p = p + m_Buffer.Capacity();
908 while ( ASDCP_SUCCESS(result) && p < end_p )
910 // parse the packets and index them by uid, discard KLVFill items
911 InterchangeObject* object = CreateObject(p);
914 object->m_Lookup = m_Lookup;
915 result = object->InitFromBuffer(p, end_p - p);
916 p += object->PacketLength();
918 if ( ASDCP_SUCCESS(result) )
920 m_PacketList->AddPacket(object);
924 DefaultLogSink().Error("Error initializing packet\n");
929 if ( ASDCP_FAILURE(result) )
930 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
937 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration)
939 ASDCP::FrameBuffer FooterBuffer;
940 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
941 Result_t result = FooterBuffer.Capacity(footer_size);
942 ui32_t iseg_count = 0;
944 if ( m_CurrentSegment != 0 )
946 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
947 m_CurrentSegment = 0;
950 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
951 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
953 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
956 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
958 if ( m_BytesPerEditUnit != 0 )
960 if ( iseg_count != 1 )
963 Segment->IndexDuration = duration;
967 InterchangeObject* object = *pl_i;
968 object->m_Lookup = m_Lookup;
970 ASDCP::FrameBuffer WriteWrapper;
971 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
972 FooterBuffer.Capacity() - FooterBuffer.Size());
973 result = object->WriteToBuffer(WriteWrapper);
974 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
977 if ( ASDCP_SUCCESS(result) )
979 IndexByteCount = FooterBuffer.Size();
980 UL FooterUL(Dict::ul(MDD_CompleteFooter));
981 result = Partition::WriteToFile(Writer, FooterUL);
984 if ( ASDCP_SUCCESS(result) )
987 Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
988 assert(write_count == FooterBuffer.Size());
996 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1001 Partition::Dump(stream);
1003 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1004 for ( ; i != m_PacketList->m_List.end(); i++ )
1010 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
1012 std::list<InterchangeObject*>::iterator li;
1013 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1015 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1017 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1018 ui64_t start_pos = Segment->IndexStartPosition;
1020 if ( Segment->EditUnitByteCount > 0 )
1022 if ( m_PacketList->m_List.size() > 1 )
1023 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1025 if ( ! Segment->IndexEntryArray.empty() )
1026 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1028 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1031 else if ( (ui64_t)frame_num >= start_pos
1032 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1034 Entry = Segment->IndexEntryArray[frame_num-start_pos];
1045 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1049 m_BytesPerEditUnit = size;
1052 IndexTableSegment* Index = new IndexTableSegment;
1053 AddChildObject(Index);
1054 Index->EditUnitByteCount = m_BytesPerEditUnit;
1055 Index->IndexEditRate = Rate;
1060 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, fpos_t offset)
1064 m_BytesPerEditUnit = 0;
1066 m_ECOffset = offset;
1071 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1073 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1075 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1079 // do we have an available segment?
1080 if ( m_CurrentSegment == 0 )
1081 { // no, set up a new segment
1082 m_CurrentSegment = new IndexTableSegment;
1083 assert(m_CurrentSegment);
1084 AddChildObject(m_CurrentSegment);
1085 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1086 m_CurrentSegment->IndexEditRate = m_EditRate;
1087 m_CurrentSegment->IndexStartPosition = 0;
1089 else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
1090 { // no, this one is full, start another
1091 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1092 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1094 m_CurrentSegment = new IndexTableSegment;
1095 assert(m_CurrentSegment);
1096 AddChildObject(m_CurrentSegment);
1097 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1098 m_CurrentSegment->IndexEditRate = m_EditRate;
1099 m_CurrentSegment->IndexStartPosition = StartPosition;
1102 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1105 //------------------------------------------------------------------------------------------
1110 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1112 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1113 if ( ASDCP_SUCCESS(result) )
1114 result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
1120 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1122 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1123 if ( ASDCP_SUCCESS(result) )
1124 result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
1130 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1135 if ( m_Typeinfo == 0 )
1137 result = KLVPacket::InitFromBuffer(p, l);
1141 result = KLVPacket::InitFromBuffer(p, l, m_Typeinfo->ul);
1143 if ( ASDCP_SUCCESS(result) )
1145 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1146 result = InitFromTLVSet(MemRDR);
1155 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1157 if ( m_Typeinfo == 0 )
1158 return RESULT_STATE;
1160 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1161 Result_t result = WriteToTLVSet(MemWRT);
1163 if ( ASDCP_SUCCESS(result) )
1165 ui32_t packet_length = MemWRT.Size();
1166 result = WriteKLToBuffer(Buffer, m_Typeinfo->ul, packet_length);
1168 if ( ASDCP_SUCCESS(result) )
1169 Buffer.Size(Buffer.Size() + packet_length);
1177 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1179 char identbuf[IdentBufferLen];
1181 fputc('\n', stream);
1182 KLVPacket::Dump(stream, false);
1183 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
1184 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
1189 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1191 if ( m_KLLength == 0 )
1194 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );