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(0)
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
642 // is it really OP-Atom?
643 UL OPAtomUL(Dict::ul(MDD_OPAtom));
644 UL InteropOPAtomUL(Dict::ul(MDD_MXFInterop_OPAtom));
646 if ( ! ( OperationalPattern == OPAtomUL || OperationalPattern == InteropOPAtomUL ) )
648 char strbuf[IntBufferLen];
649 const MDDEntry* Entry = Dict::FindUL(OperationalPattern.Value());
651 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", OperationalPattern.ToString(strbuf));
653 DefaultLogSink().Warn("Operational pattern is not OP-Atom: %s\n", Entry->name);
656 // slurp up the remainder of the header
657 if ( ASDCP_SUCCESS(result) )
659 if ( HeaderByteCount < 1024 )
660 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %lu\n", HeaderByteCount);
662 result = m_Buffer.Capacity(HeaderByteCount);
665 if ( ASDCP_SUCCESS(result) )
668 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
670 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
672 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
673 m_Buffer.Capacity(), read_count);
678 const byte_t* p = m_Buffer.RoData();
679 const byte_t* end_p = p + m_Buffer.Capacity();
681 while ( ASDCP_SUCCESS(result) && p < end_p )
683 // parse the packets and index them by uid, discard KLVFill items
684 InterchangeObject* object = CreateObject(p);
687 object->m_Lookup = &m_Primer;
688 result = object->InitFromBuffer(p, end_p - p);
689 const byte_t* redo_p = p;
690 p += object->PacketLength();
691 // hexdump(p, object->PacketLength());
693 if ( ASDCP_SUCCESS(result) )
695 if ( object->IsA(Dict::ul(MDD_KLVFill)) )
699 else if ( object->IsA(Dict::ul(MDD_Primer)) )
702 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
704 else if ( object->IsA(Dict::ul(MDD_Preface)) )
706 assert(m_Preface == 0);
707 m_Preface = (Preface*)object;
711 m_PacketList->AddPacket(object);
716 DefaultLogSink().Error("Error initializing packet\n");
726 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
728 InterchangeObject* TmpObject;
733 return m_PacketList->GetMDObjectByType(ObjectID, Object);
737 ASDCP::MXF::Identification*
738 ASDCP::MXF::OPAtomHeader::GetIdentification()
740 InterchangeObject* Object;
742 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
743 return (Identification*)Object;
749 ASDCP::MXF::SourcePackage*
750 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
752 InterchangeObject* Object;
754 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
755 return (SourcePackage*)Object;
763 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
765 if ( m_Preface == 0 )
768 if ( HeaderSize < 4096 )
770 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n", HeaderSize);
774 ASDCP::FrameBuffer HeaderBuffer;
775 HeaderByteCount = HeaderSize - ArchiveSize();
776 Result_t result = HeaderBuffer.Capacity(HeaderByteCount);
777 m_Preface->m_Lookup = &m_Primer;
779 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
780 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
782 InterchangeObject* object = *pl_i;
783 object->m_Lookup = &m_Primer;
785 ASDCP::FrameBuffer WriteWrapper;
786 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
787 HeaderBuffer.Capacity() - HeaderBuffer.Size());
788 result = object->WriteToBuffer(WriteWrapper);
789 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
792 if ( ASDCP_SUCCESS(result) )
794 UL TmpUL(Dict::ul(MDD_ClosedCompleteHeader));
795 result = Partition::WriteToFile(Writer, TmpUL);
798 if ( ASDCP_SUCCESS(result) )
799 result = m_Primer.WriteToFile(Writer);
801 if ( ASDCP_SUCCESS(result) )
804 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
805 assert(write_count == HeaderBuffer.Size());
809 if ( ASDCP_SUCCESS(result) )
811 ASDCP::fpos_t pos = Writer.Tell();
813 if ( pos > (ASDCP::fpos_t)HeaderByteCount )
815 char intbuf[IntBufferLen];
816 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
822 ASDCP::FrameBuffer NilBuf;
823 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
825 if ( klv_fill_length < kl_length )
827 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
831 klv_fill_length -= kl_length;
832 result = WriteKLToFile(Writer, Dict::ul(MDD_KLVFill), klv_fill_length);
834 if ( ASDCP_SUCCESS(result) )
835 result = NilBuf.Capacity(klv_fill_length);
837 if ( ASDCP_SUCCESS(result) )
839 memset(NilBuf.Data(), 0, klv_fill_length);
841 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
842 assert(write_count == klv_fill_length);
851 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
859 Partition::Dump(stream);
860 m_Primer.Dump(stream);
862 if ( m_Preface == 0 )
863 fputs("No Preface loaded\n", stream);
865 m_Preface->Dump(stream);
867 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
868 for ( ; i != m_PacketList->m_List.end(); i++ )
872 //------------------------------------------------------------------------------------------
875 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() :
876 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
877 m_ECOffset(0), m_Lookup(0)
883 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
887 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
889 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
891 // slurp up the remainder of the footer
894 if ( ASDCP_SUCCESS(result) )
895 result = m_Buffer.Capacity(IndexByteCount);
897 if ( ASDCP_SUCCESS(result) )
898 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
900 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
902 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
903 read_count, m_Buffer.Capacity());
907 const byte_t* p = m_Buffer.RoData();
908 const byte_t* end_p = p + m_Buffer.Capacity();
910 while ( ASDCP_SUCCESS(result) && p < end_p )
912 // parse the packets and index them by uid, discard KLVFill items
913 InterchangeObject* object = CreateObject(p);
916 object->m_Lookup = m_Lookup;
917 result = object->InitFromBuffer(p, end_p - p);
918 p += object->PacketLength();
920 if ( ASDCP_SUCCESS(result) )
922 m_PacketList->AddPacket(object);
926 DefaultLogSink().Error("Error initializing packet\n");
931 if ( ASDCP_FAILURE(result) )
932 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
939 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration)
941 ASDCP::FrameBuffer FooterBuffer;
942 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
943 Result_t result = FooterBuffer.Capacity(footer_size);
944 ui32_t iseg_count = 0;
946 if ( m_CurrentSegment != 0 )
948 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
949 m_CurrentSegment = 0;
952 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
953 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
955 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
958 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
960 if ( m_BytesPerEditUnit != 0 )
962 if ( iseg_count != 1 )
965 Segment->IndexDuration = duration;
969 InterchangeObject* object = *pl_i;
970 object->m_Lookup = m_Lookup;
972 ASDCP::FrameBuffer WriteWrapper;
973 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
974 FooterBuffer.Capacity() - FooterBuffer.Size());
975 result = object->WriteToBuffer(WriteWrapper);
976 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
979 if ( ASDCP_SUCCESS(result) )
981 IndexByteCount = FooterBuffer.Size();
982 UL FooterUL(Dict::ul(MDD_CompleteFooter));
983 result = Partition::WriteToFile(Writer, FooterUL);
986 if ( ASDCP_SUCCESS(result) )
989 Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
990 assert(write_count == FooterBuffer.Size());
998 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1003 Partition::Dump(stream);
1005 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1006 for ( ; i != m_PacketList->m_List.end(); i++ )
1012 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
1014 std::list<InterchangeObject*>::iterator li;
1015 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1017 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1019 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1020 ui64_t start_pos = Segment->IndexStartPosition;
1022 if ( Segment->EditUnitByteCount > 0 )
1024 if ( m_PacketList->m_List.size() > 1 )
1025 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1027 if ( ! Segment->IndexEntryArray.empty() )
1028 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1030 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1033 else if ( (ui64_t)frame_num >= start_pos
1034 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1036 Entry = Segment->IndexEntryArray[frame_num-start_pos];
1047 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1051 m_BytesPerEditUnit = size;
1054 IndexTableSegment* Index = new IndexTableSegment;
1055 AddChildObject(Index);
1056 Index->EditUnitByteCount = m_BytesPerEditUnit;
1057 Index->IndexEditRate = Rate;
1062 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, fpos_t offset)
1066 m_BytesPerEditUnit = 0;
1068 m_ECOffset = offset;
1073 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1075 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1077 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1081 // do we have an available segment?
1082 if ( m_CurrentSegment == 0 )
1083 { // no, set up a new segment
1084 m_CurrentSegment = new IndexTableSegment;
1085 assert(m_CurrentSegment);
1086 AddChildObject(m_CurrentSegment);
1087 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1088 m_CurrentSegment->IndexEditRate = m_EditRate;
1089 m_CurrentSegment->IndexStartPosition = 0;
1091 else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
1092 { // no, this one is full, start another
1093 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1094 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1096 m_CurrentSegment = new IndexTableSegment;
1097 assert(m_CurrentSegment);
1098 AddChildObject(m_CurrentSegment);
1099 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1100 m_CurrentSegment->IndexEditRate = m_EditRate;
1101 m_CurrentSegment->IndexStartPosition = StartPosition;
1104 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1107 //------------------------------------------------------------------------------------------
1112 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1114 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1115 if ( ASDCP_SUCCESS(result) )
1116 result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
1122 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1124 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1125 if ( ASDCP_SUCCESS(result) )
1126 result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
1132 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1137 if ( m_Typeinfo == 0 )
1139 result = KLVPacket::InitFromBuffer(p, l);
1143 result = KLVPacket::InitFromBuffer(p, l, m_Typeinfo->ul);
1145 if ( ASDCP_SUCCESS(result) )
1147 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1148 result = InitFromTLVSet(MemRDR);
1157 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1159 if ( m_Typeinfo == 0 )
1160 return RESULT_STATE;
1162 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1163 Result_t result = WriteToTLVSet(MemWRT);
1165 if ( ASDCP_SUCCESS(result) )
1167 ui32_t packet_length = MemWRT.Size();
1168 result = WriteKLToBuffer(Buffer, m_Typeinfo->ul, packet_length);
1170 if ( ASDCP_SUCCESS(result) )
1171 Buffer.Size(Buffer.Size() + packet_length);
1179 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1181 char identbuf[IdentBufferLen];
1183 fputc('\n', stream);
1184 KLVPacket::Dump(stream, false);
1185 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
1186 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
1191 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1193 if ( m_KLLength == 0 )
1196 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );