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));
643 if ( ! ( OperationalPattern == OPAtomUL ) )
645 char strbuf[IntBufferLen];
646 const MDDEntry* Entry = Dict::FindUL(m_KeyStart);
648 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s.\n", OperationalPattern.ToString(strbuf));
650 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s.\n", Entry->name);
653 // slurp up the remainder of the header
654 if ( ASDCP_SUCCESS(result) )
656 if ( HeaderByteCount < 1024 )
657 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %lu\n", HeaderByteCount);
659 result = m_Buffer.Capacity(HeaderByteCount);
662 if ( ASDCP_SUCCESS(result) )
665 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
667 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
669 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
670 m_Buffer.Capacity(), read_count);
675 const byte_t* p = m_Buffer.RoData();
676 const byte_t* end_p = p + m_Buffer.Capacity();
678 while ( ASDCP_SUCCESS(result) && p < end_p )
680 // parse the packets and index them by uid, discard KLVFill items
681 InterchangeObject* object = CreateObject(p);
684 object->m_Lookup = &m_Primer;
685 result = object->InitFromBuffer(p, end_p - p);
686 const byte_t* redo_p = p;
687 p += object->PacketLength();
688 // hexdump(p, object->PacketLength());
690 if ( ASDCP_SUCCESS(result) )
692 if ( object->IsA(Dict::ul(MDD_KLVFill)) )
696 else if ( object->IsA(Dict::ul(MDD_Primer)) )
699 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
701 else if ( object->IsA(Dict::ul(MDD_Preface)) )
703 assert(m_Preface == 0);
704 m_Preface = (Preface*)object;
708 m_PacketList->AddPacket(object);
713 DefaultLogSink().Error("Error initializing packet\n");
723 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
725 InterchangeObject* TmpObject;
730 return m_PacketList->GetMDObjectByType(ObjectID, Object);
734 ASDCP::MXF::Identification*
735 ASDCP::MXF::OPAtomHeader::GetIdentification()
737 InterchangeObject* Object;
739 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
740 return (Identification*)Object;
746 ASDCP::MXF::SourcePackage*
747 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
749 InterchangeObject* Object;
751 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
752 return (SourcePackage*)Object;
760 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
762 if ( m_Preface == 0 )
765 if ( HeaderSize < 4096 )
767 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n", HeaderSize);
771 ASDCP::FrameBuffer HeaderBuffer;
772 HeaderByteCount = HeaderSize - ArchiveSize();
773 Result_t result = HeaderBuffer.Capacity(HeaderByteCount);
774 m_Preface->m_Lookup = &m_Primer;
776 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
777 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
779 InterchangeObject* object = *pl_i;
780 object->m_Lookup = &m_Primer;
782 ASDCP::FrameBuffer WriteWrapper;
783 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
784 HeaderBuffer.Capacity() - HeaderBuffer.Size());
785 result = object->WriteToBuffer(WriteWrapper);
786 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
789 if ( ASDCP_SUCCESS(result) )
791 UL TmpUL(Dict::ul(MDD_ClosedCompleteHeader));
792 result = Partition::WriteToFile(Writer, TmpUL);
795 if ( ASDCP_SUCCESS(result) )
796 result = m_Primer.WriteToFile(Writer);
798 if ( ASDCP_SUCCESS(result) )
801 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
802 assert(write_count == HeaderBuffer.Size());
806 if ( ASDCP_SUCCESS(result) )
808 ASDCP::fpos_t pos = Writer.Tell();
810 if ( pos > (ASDCP::fpos_t)HeaderByteCount )
812 char intbuf[IntBufferLen];
813 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
819 ASDCP::FrameBuffer NilBuf;
820 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
822 if ( klv_fill_length < kl_length )
824 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
828 klv_fill_length -= kl_length;
829 result = WriteKLToFile(Writer, Dict::ul(MDD_KLVFill), klv_fill_length);
831 if ( ASDCP_SUCCESS(result) )
832 result = NilBuf.Capacity(klv_fill_length);
834 if ( ASDCP_SUCCESS(result) )
836 memset(NilBuf.Data(), 0, klv_fill_length);
838 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
839 assert(write_count == klv_fill_length);
848 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
856 Partition::Dump(stream);
857 m_Primer.Dump(stream);
859 if ( m_Preface == 0 )
860 fputs("No Preface loaded\n", stream);
862 m_Preface->Dump(stream);
864 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
865 for ( ; i != m_PacketList->m_List.end(); i++ )
869 //------------------------------------------------------------------------------------------
872 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() :
873 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
874 m_ECOffset(0), m_Lookup(0)
880 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
884 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
886 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
888 // slurp up the remainder of the footer
891 if ( ASDCP_SUCCESS(result) )
892 result = m_Buffer.Capacity(IndexByteCount);
894 if ( ASDCP_SUCCESS(result) )
895 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
897 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
899 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
900 read_count, m_Buffer.Capacity());
904 const byte_t* p = m_Buffer.RoData();
905 const byte_t* end_p = p + m_Buffer.Capacity();
907 while ( ASDCP_SUCCESS(result) && p < end_p )
909 // parse the packets and index them by uid, discard KLVFill items
910 InterchangeObject* object = CreateObject(p);
913 object->m_Lookup = m_Lookup;
914 result = object->InitFromBuffer(p, end_p - p);
915 p += object->PacketLength();
917 if ( ASDCP_SUCCESS(result) )
919 m_PacketList->AddPacket(object);
923 DefaultLogSink().Error("Error initializing packet\n");
928 if ( ASDCP_FAILURE(result) )
929 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
936 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration)
938 ASDCP::FrameBuffer FooterBuffer;
939 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
940 Result_t result = FooterBuffer.Capacity(footer_size);
941 ui32_t iseg_count = 0;
943 if ( m_CurrentSegment != 0 )
945 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
946 m_CurrentSegment = 0;
949 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
950 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
952 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
955 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
957 if ( m_BytesPerEditUnit != 0 )
959 if ( iseg_count != 1 )
962 Segment->IndexDuration = duration;
966 InterchangeObject* object = *pl_i;
967 object->m_Lookup = m_Lookup;
969 ASDCP::FrameBuffer WriteWrapper;
970 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
971 FooterBuffer.Capacity() - FooterBuffer.Size());
972 result = object->WriteToBuffer(WriteWrapper);
973 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
976 if ( ASDCP_SUCCESS(result) )
978 IndexByteCount = FooterBuffer.Size();
979 UL FooterUL(Dict::ul(MDD_CompleteFooter));
980 result = Partition::WriteToFile(Writer, FooterUL);
983 if ( ASDCP_SUCCESS(result) )
986 Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
987 assert(write_count == FooterBuffer.Size());
995 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1000 Partition::Dump(stream);
1002 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1003 for ( ; i != m_PacketList->m_List.end(); i++ )
1009 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
1011 std::list<InterchangeObject*>::iterator li;
1012 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1014 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1016 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1017 ui64_t start_pos = Segment->IndexStartPosition;
1019 if ( Segment->EditUnitByteCount > 0 )
1021 if ( m_PacketList->m_List.size() > 1 )
1022 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1024 if ( ! Segment->IndexEntryArray.empty() )
1025 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1027 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1030 else if ( (ui64_t)frame_num >= start_pos
1031 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1033 Entry = Segment->IndexEntryArray[frame_num-start_pos];
1044 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1048 m_BytesPerEditUnit = size;
1051 IndexTableSegment* Index = new IndexTableSegment;
1052 AddChildObject(Index);
1053 Index->EditUnitByteCount = m_BytesPerEditUnit;
1054 Index->IndexEditRate = Rate;
1059 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, fpos_t offset)
1063 m_BytesPerEditUnit = 0;
1065 m_ECOffset = offset;
1070 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1072 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1074 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1078 // do we have an available segment?
1079 if ( m_CurrentSegment == 0 )
1080 { // no, set up a new segment
1081 m_CurrentSegment = new IndexTableSegment;
1082 assert(m_CurrentSegment);
1083 AddChildObject(m_CurrentSegment);
1084 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1085 m_CurrentSegment->IndexEditRate = m_EditRate;
1086 m_CurrentSegment->IndexStartPosition = 0;
1088 else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
1089 { // no, this one is full, start another
1090 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1091 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1093 m_CurrentSegment = new IndexTableSegment;
1094 assert(m_CurrentSegment);
1095 AddChildObject(m_CurrentSegment);
1096 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1097 m_CurrentSegment->IndexEditRate = m_EditRate;
1098 m_CurrentSegment->IndexStartPosition = StartPosition;
1101 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1104 //------------------------------------------------------------------------------------------
1109 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1111 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1112 if ( ASDCP_SUCCESS(result) )
1113 result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
1119 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1121 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1122 if ( ASDCP_SUCCESS(result) )
1123 result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
1129 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1134 if ( m_Typeinfo == 0 )
1136 result = KLVPacket::InitFromBuffer(p, l);
1140 result = KLVPacket::InitFromBuffer(p, l, m_Typeinfo->ul);
1142 if ( ASDCP_SUCCESS(result) )
1144 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1145 result = InitFromTLVSet(MemRDR);
1154 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1156 if ( m_Typeinfo == 0 )
1157 return RESULT_STATE;
1159 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1160 Result_t result = WriteToTLVSet(MemWRT);
1162 if ( ASDCP_SUCCESS(result) )
1164 ui32_t packet_length = MemWRT.Size();
1165 result = WriteKLToBuffer(Buffer, m_Typeinfo->ul, packet_length);
1167 if ( ASDCP_SUCCESS(result) )
1168 Buffer.Size(Buffer.Size() + packet_length);
1176 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1178 char identbuf[IdentBufferLen];
1180 fputc('\n', stream);
1181 KLVPacket::Dump(stream, false);
1182 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
1183 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
1188 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1190 if ( m_KLLength == 0 )
1193 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );