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"
35 //------------------------------------------------------------------------------------------
38 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
40 const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
43 const ASDCP::MDDEntry*
44 ASDCP::GetMDDEntry(const byte_t* ul_buf)
49 // must be a pointer to a SMPTE UL
50 if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
53 // advance to first matching element
54 // TODO: optimize using binary search
55 while ( s_MDD_Table[t_idx].ul != 0
56 && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
59 if ( s_MDD_Table[t_idx].ul == 0 )
62 // match successive elements
63 while ( s_MDD_Table[t_idx].ul != 0
64 && k_idx < SMPTE_UL_LENGTH - 1
65 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
67 if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
73 while ( s_MDD_Table[t_idx].ul != 0
74 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
75 && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
78 while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
83 return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
86 //------------------------------------------------------------------------------------------
91 ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
93 ASDCP::fpos_t end_pos;
95 // go to the end - 4 bytes
96 Result_t result = Reader.Seek(0, ASDCP::SP_END);
98 if ( ASDCP_SUCCESS(result) )
99 result = Reader.Tell(&end_pos);
101 if ( ASDCP_SUCCESS(result)
102 && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
103 result = RESULT_FAIL; // File is smaller than an empty packet!
105 if ( ASDCP_SUCCESS(result) )
106 result = Reader.Seek(end_pos - 4);
108 // get the ui32_t RIP length
110 byte_t intbuf[MXF_BER_LENGTH];
113 if ( ASDCP_SUCCESS(result) )
115 result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
117 if ( ASDCP_SUCCESS(result) && read_count != 4 )
118 result = RESULT_FAIL;
121 if ( ASDCP_SUCCESS(result) )
123 rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
125 if ( rip_size > end_pos ) // RIP can't be bigger than the file
129 // reposition to start of RIP
130 if ( ASDCP_SUCCESS(result) )
131 result = Reader.Seek(end_pos - rip_size);
138 ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
140 Result_t result = KLVFilePacket::InitFromFile(Reader, Dict::ul(MDD_RandomIndexMetadata));
142 if ( ASDCP_SUCCESS(result) )
144 MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
145 result = PairArray.Unarchive(MemRDR);
148 if ( ASDCP_FAILURE(result) )
149 DefaultLogSink().Error("Failed to initialize RIP\n");
156 ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
158 ASDCP::FrameBuffer Buffer;
159 ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4;
160 Result_t result = Buffer.Capacity(RIPSize);
162 if ( ASDCP_SUCCESS(result) )
163 result = WriteKLToFile(Writer, Dict::ul(MDD_RandomIndexMetadata), RIPSize);
165 if ( ASDCP_SUCCESS(result) )
167 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
168 result = PairArray.Archive(MemWRT);
170 if ( ASDCP_SUCCESS(result) )
171 MemWRT.WriteUi32BE(RIPSize + 20);
173 if ( ASDCP_SUCCESS(result) )
174 Buffer.Size(MemWRT.Size());
177 if ( ASDCP_SUCCESS(result) )
178 result = Writer.Write(Buffer.RoData(), Buffer.Size());
185 ASDCP::MXF::RIP::Dump(FILE* stream)
190 KLVFilePacket::Dump(stream, false);
191 PairArray.Dump(stream, false);
193 fputs("==========================================================================\n", stream);
196 //------------------------------------------------------------------------------------------
200 class ASDCP::MXF::Partition::h__PacketList
203 std::list<InterchangeObject*> m_List;
204 std::map<UUID, InterchangeObject*> m_Map;
207 while ( ! m_List.empty() )
209 delete m_List.back();
215 void AddPacket(InterchangeObject* ThePacket)
218 m_Map.insert(std::map<UUID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
219 m_List.push_back(ThePacket);
223 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
225 ASDCP_TEST_NULL(ObjectID);
226 ASDCP_TEST_NULL(Object);
227 std::list<InterchangeObject*>::iterator li;
230 for ( li = m_List.begin(); li != m_List.end(); li++ )
232 if ( (*li)->HasUL(ObjectID) )
243 //------------------------------------------------------------------------------------------
247 ASDCP::MXF::Partition::Partition() :
248 MajorVersion(1), MinorVersion(2),
249 KAGSize(1), ThisPartition(0), PreviousPartition(0),
250 FooterPartition(0), HeaderByteCount(0), IndexByteCount(0), IndexSID(0),
251 BodyOffset(0), BodySID(1)
253 m_PacketList = new h__PacketList;
256 ASDCP::MXF::Partition::~Partition()
262 ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object)
266 TmpID.GenRandomValue();
267 Object->InstanceUID = TmpID;
268 m_PacketList->AddPacket(Object);
273 ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
275 Result_t result = KLVFilePacket::InitFromFile(Reader);
277 // could be one of several values
279 if ( ASDCP_SUCCESS(result) )
281 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
282 result = MemRDR.ReadUi16BE(&MajorVersion);
283 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion);
284 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize);
285 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition);
286 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition);
287 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition);
288 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount);
289 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount);
290 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID);
291 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset);
292 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID);
293 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Unarchive(MemRDR);
294 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Unarchive(MemRDR);
297 if ( ASDCP_FAILURE(result) )
298 DefaultLogSink().Error("Failed to initialize Partition\n");
305 ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer, UL& PartitionLabel)
307 ASDCP::FrameBuffer Buffer;
308 Result_t result = Buffer.Capacity(1024);
310 if ( ASDCP_SUCCESS(result) )
312 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
313 result = MemWRT.WriteUi16BE(MajorVersion);
314 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion);
315 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize);
316 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition);
317 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition);
318 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition);
319 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount);
320 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount);
321 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID);
322 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset);
323 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID);
324 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.Archive(MemWRT);
325 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.Archive(MemWRT);
326 if ( ASDCP_SUCCESS(result) ) Buffer.Size(MemWRT.Size());
329 if ( ASDCP_SUCCESS(result) )
331 ui32_t write_count; // this is subclassed, so the UL is only right some of the time
332 result = WriteKLToFile(Writer, PartitionLabel.Value(), Buffer.Size());
334 if ( ASDCP_SUCCESS(result) )
335 result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
343 ASDCP::MXF::Partition::Dump(FILE* stream)
345 char identbuf[IdentBufferLen];
346 char intbuf[IntBufferLen];
351 KLVFilePacket::Dump(stream, false);
352 fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
353 fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
354 fprintf(stream, " KAGSize = %lu\n", KAGSize);
355 fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf));
356 fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf));
357 fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf));
358 fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf));
359 fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf));
360 fprintf(stream, " IndexSID = %lu\n", IndexSID);
361 fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf));
362 fprintf(stream, " BodySID = %lu\n", BodySID);
363 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
364 fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
366 fputs("==========================================================================\n", stream);
370 //------------------------------------------------------------------------------------------
373 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
376 void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
378 ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
380 for ( ; i != Batch.end(); i++ )
381 insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
387 ASDCP::MXF::Primer::Primer() : m_LocalTag(0xff) {}
390 ASDCP::MXF::Primer::~Primer() {}
394 ASDCP::MXF::Primer::ClearTagList()
396 LocalTagEntryBatch.clear();
397 m_Lookup = new h__PrimerLookup;
402 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
404 Result_t result = KLVPacket::InitFromBuffer(p, l, Dict::ul(MDD_Primer));
406 if ( ASDCP_SUCCESS(result) )
408 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
409 result = LocalTagEntryBatch.Unarchive(MemRDR);
412 if ( ASDCP_SUCCESS(result) )
414 m_Lookup = new h__PrimerLookup;
415 m_Lookup->InitWithBatch(LocalTagEntryBatch);
418 if ( ASDCP_FAILURE(result) )
419 DefaultLogSink().Error("Failed to initialize Primer\n");
426 ASDCP::MXF::Primer::WriteToFile(ASDCP::FileWriter& Writer)
428 ASDCP::FrameBuffer Buffer;
429 Result_t result = Buffer.Capacity(128*1024);
431 if ( ASDCP_SUCCESS(result) )
432 result = WriteToBuffer(Buffer);
434 if ( ASDCP_SUCCESS(result) )
435 result = Writer.Write(Buffer.RoData(), Buffer.Size());
442 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
444 ASDCP::FrameBuffer LocalTagBuffer;
445 MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length);
446 Result_t result = LocalTagEntryBatch.Archive(MemWRT);
448 if ( ASDCP_SUCCESS(result) )
450 ui32_t packet_length = MemWRT.Size();
451 result = WriteKLToBuffer(Buffer, Dict::ul(MDD_Primer), packet_length);
453 if ( ASDCP_SUCCESS(result) )
454 Buffer.Size(Buffer.Size() + packet_length);
462 ASDCP::MXF::Primer::InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag)
466 std::map<UL, TagValue>::iterator i = m_Lookup->find(TestUL);
468 if ( i == m_Lookup->end() )
470 if ( Entry.tag.a == 0 && Entry.tag.b == 0 )
473 Tag.b = m_LocalTag--;
481 LocalTagEntry TmpEntry;
482 TmpEntry.UL = TestUL;
485 LocalTagEntryBatch.push_back(TmpEntry);
486 m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
498 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
501 if ( m_Lookup.empty() )
503 DefaultLogSink().Error("Primer lookup is empty\n");
507 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
509 if ( i == m_Lookup->end() )
518 ASDCP::MXF::Primer::Dump(FILE* stream)
520 char identbuf[IdentBufferLen];
525 KLVPacket::Dump(stream, false);
526 fprintf(stream, "Primer: %lu %s\n",
527 LocalTagEntryBatch.ItemCount,
528 ( LocalTagEntryBatch.ItemCount == 1 ? "entry" : "entries" ));
530 Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
531 for ( ; i != LocalTagEntryBatch.end(); i++ )
533 const MDDEntry* Entry = Dict::FindUL((*i).UL.Value());
534 fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
537 fputs("==========================================================================\n", stream);
541 //------------------------------------------------------------------------------------------
546 ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
548 Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
549 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
550 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version));
551 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
552 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
553 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
554 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
555 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
556 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
557 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
563 ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
565 Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
566 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
567 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
568 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
569 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
570 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
571 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
572 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
573 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
574 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
580 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
582 m_Typeinfo = &Dict::Type(MDD_Preface);
583 return InterchangeObject::InitFromBuffer(p, l);
588 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
590 m_Typeinfo = &Dict::Type(MDD_Preface);
591 return InterchangeObject::WriteToBuffer(Buffer);
596 ASDCP::MXF::Preface::Dump(FILE* stream)
598 char identbuf[IdentBufferLen];
603 InterchangeObject::Dump(stream);
604 fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.ToString(identbuf));
605 fprintf(stream, " %22s = %hu\n", "Version", Version);
606 fprintf(stream, " %22s = %lu\n", "ObjectModelVersion", ObjectModelVersion);
607 fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.ToString(identbuf));
608 fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream);
609 fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.ToString(identbuf));
610 fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.ToString(identbuf));
611 fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream);
612 fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream);
615 //------------------------------------------------------------------------------------------
618 ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false) {}
619 ASDCP::MXF::OPAtomHeader::~OPAtomHeader() {}
623 ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
626 Result_t result = SeekToRIP(Reader);
628 if ( ASDCP_SUCCESS(result) )
630 result = m_RIP.InitFromFile(Reader);
632 if ( ASDCP_FAILURE(result) )
634 DefaultLogSink().Error("File contains no RIP\n");
643 if ( ASDCP_SUCCESS(result) )
644 result = Reader.Seek(0);
646 if ( ASDCP_SUCCESS(result) )
647 result = Partition::InitFromFile(Reader); // test UL and OP
649 // slurp up the remainder of the header
652 if ( ASDCP_SUCCESS(result) )
654 ui32_t here = (ui32_t)Reader.Tell();
656 if ( HeaderByteCount < here )
658 DefaultLogSink().Error("HeaderByteCount less than Partition size\n");
662 result = m_Buffer.Capacity(HeaderByteCount - here);
665 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);
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;
759 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
761 if ( m_Preface == 0 )
764 if ( HeaderSize < 4096 )
766 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n", HeaderSize);
770 ASDCP::FrameBuffer HeaderBuffer;
771 HeaderByteCount = HeaderSize;
772 Result_t result = HeaderBuffer.Capacity(HeaderSize);
773 m_Preface->m_Lookup = &m_Primer;
775 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
776 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
778 InterchangeObject* object = *pl_i;
779 object->m_Lookup = &m_Primer;
781 ASDCP::FrameBuffer WriteWrapper;
782 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
783 HeaderBuffer.Capacity() - HeaderBuffer.Size());
784 result = object->WriteToBuffer(WriteWrapper);
785 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
788 if ( ASDCP_SUCCESS(result) )
790 UL TmpUL(Dict::ul(MDD_ClosedCompleteHeader));
791 result = Partition::WriteToFile(Writer, TmpUL);
794 if ( ASDCP_SUCCESS(result) )
795 result = m_Primer.WriteToFile(Writer);
797 if ( ASDCP_SUCCESS(result) )
800 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
801 assert(write_count == HeaderBuffer.Size());
805 if ( ASDCP_SUCCESS(result) )
807 ASDCP::fpos_t pos = Writer.Tell();
809 if ( pos > HeaderSize )
811 char intbuf[IntBufferLen];
812 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
818 ASDCP::FrameBuffer NilBuf;
819 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
821 if ( klv_fill_length < kl_length )
823 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
827 klv_fill_length -= kl_length;
828 result = WriteKLToFile(Writer, Dict::ul(MDD_KLVFill), klv_fill_length);
830 if ( ASDCP_SUCCESS(result) )
831 result = NilBuf.Capacity(klv_fill_length);
833 if ( ASDCP_SUCCESS(result) )
835 memset(NilBuf.Data(), 0, klv_fill_length);
837 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
838 assert(write_count == klv_fill_length);
847 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
855 Partition::Dump(stream);
856 m_Primer.Dump(stream);
858 if ( m_Preface == 0 )
859 fputs("No Preface loaded\n", stream);
861 m_Preface->Dump(stream);
863 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
864 for ( ; i != m_PacketList->m_List.end(); i++ )
868 //------------------------------------------------------------------------------------------
871 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() :
872 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
873 m_ECOffset(0), m_Lookup(0)
879 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
883 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
885 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
887 // slurp up the remainder of the footer
890 if ( ASDCP_SUCCESS(result) )
891 result = m_Buffer.Capacity(IndexByteCount);
893 if ( ASDCP_SUCCESS(result) )
894 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
896 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
898 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
899 read_count, m_Buffer.Capacity());
903 const byte_t* p = m_Buffer.RoData();
904 const byte_t* end_p = p + m_Buffer.Capacity();
906 while ( ASDCP_SUCCESS(result) && p < end_p )
908 // parse the packets and index them by uid, discard KLVFill items
909 InterchangeObject* object = CreateObject(p);
912 object->m_Lookup = m_Lookup;
913 result = object->InitFromBuffer(p, end_p - p);
914 p += object->PacketLength();
916 if ( ASDCP_SUCCESS(result) )
918 m_PacketList->AddPacket(object);
922 DefaultLogSink().Error("Error initializing packet\n");
927 if ( ASDCP_FAILURE(result) )
928 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
935 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer, ui64_t duration)
937 ASDCP::FrameBuffer FooterBuffer;
938 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
939 Result_t result = FooterBuffer.Capacity(footer_size);
940 ui32_t iseg_count = 0;
942 if ( m_CurrentSegment != 0 )
944 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
945 m_CurrentSegment = 0;
948 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
949 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
951 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
954 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
956 if ( m_BytesPerEditUnit != 0 )
958 if ( iseg_count != 1 )
961 Segment->IndexDuration = duration;
965 InterchangeObject* object = *pl_i;
966 object->m_Lookup = m_Lookup;
968 ASDCP::FrameBuffer WriteWrapper;
969 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
970 FooterBuffer.Capacity() - FooterBuffer.Size());
971 result = object->WriteToBuffer(WriteWrapper);
972 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
975 if ( ASDCP_SUCCESS(result) )
977 IndexByteCount = FooterBuffer.Size();
978 UL FooterUL(Dict::ul(MDD_CompleteFooter));
979 result = Partition::WriteToFile(Writer, FooterUL);
982 if ( ASDCP_SUCCESS(result) )
985 Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
986 assert(write_count == FooterBuffer.Size());
994 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
999 Partition::Dump(stream);
1001 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1002 for ( ; i != m_PacketList->m_List.end(); i++ )
1008 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
1010 std::list<InterchangeObject*>::iterator li;
1011 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1013 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1015 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1016 ui64_t start_pos = Segment->IndexStartPosition;
1018 if ( Segment->EditUnitByteCount > 0 )
1020 if ( m_PacketList->m_List.size() > 1 )
1021 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1023 if ( ! Segment->IndexEntryArray.empty() )
1024 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1026 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1029 else if ( (ui64_t)frame_num >= start_pos
1030 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1032 Entry = Segment->IndexEntryArray[frame_num-start_pos];
1043 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1047 m_BytesPerEditUnit = size;
1050 IndexTableSegment* Index = new IndexTableSegment;
1051 AddChildObject(Index);
1052 Index->EditUnitByteCount = m_BytesPerEditUnit;
1053 Index->IndexEditRate = Rate;
1058 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, fpos_t offset)
1062 m_BytesPerEditUnit = 0;
1064 m_ECOffset = offset;
1069 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1071 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1073 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1077 // do we have an available segment?
1078 if ( m_CurrentSegment == 0 )
1080 m_CurrentSegment = new IndexTableSegment;
1081 assert(m_CurrentSegment);
1082 AddChildObject(m_CurrentSegment);
1083 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1084 m_CurrentSegment->IndexEditRate = m_EditRate;
1085 m_CurrentSegment->IndexStartPosition = 0;
1087 else if ( m_CurrentSegment->IndexEntryArray.size() >= 1486 ) // 1486 gets us 16K packets
1089 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1090 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1092 m_CurrentSegment = new IndexTableSegment;
1093 assert(m_CurrentSegment);
1094 AddChildObject(m_CurrentSegment);
1095 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1096 m_CurrentSegment->IndexEditRate = m_EditRate;
1097 m_CurrentSegment->IndexStartPosition = StartPosition;
1100 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1103 //------------------------------------------------------------------------------------------
1108 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1110 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1111 if ( ASDCP_SUCCESS(result) )
1112 result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
1118 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1120 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1121 if ( ASDCP_SUCCESS(result) )
1122 result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
1128 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1133 if ( m_Typeinfo == 0 )
1135 result = KLVPacket::InitFromBuffer(p, l);
1139 result = KLVPacket::InitFromBuffer(p, l, m_Typeinfo->ul);
1141 if ( ASDCP_SUCCESS(result) )
1143 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1144 result = InitFromTLVSet(MemRDR);
1153 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1155 if ( m_Typeinfo == 0 )
1156 return RESULT_STATE;
1158 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1159 Result_t result = WriteToTLVSet(MemWRT);
1161 if ( ASDCP_SUCCESS(result) )
1163 ui32_t packet_length = MemWRT.Size();
1164 result = WriteKLToBuffer(Buffer, m_Typeinfo->ul, packet_length);
1166 if ( ASDCP_SUCCESS(result) )
1167 Buffer.Size(Buffer.Size() + packet_length);
1175 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1177 char identbuf[IdentBufferLen];
1179 fputc('\n', stream);
1180 KLVPacket::Dump(stream, false);
1181 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
1182 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
1187 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1189 if ( m_KLLength == 0 )
1192 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );