2 Copyright (c) 2005-2006, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #define ASDCP_DECLARE_MDD
35 #include <hex_utils.h>
37 //------------------------------------------------------------------------------------------
40 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
42 const byte_t mdd_key[] = { 0x06, 0x0e, 0x2b, 0x34 };
45 const ASDCP::MDDEntry*
46 ASDCP::GetMDDEntry(const byte_t* ul_buf)
51 // must be a pointer to a SMPTE UL
52 if ( ul_buf == 0 || memcmp(mdd_key, ul_buf, 4) != 0 )
55 // advance to first matching element
56 // TODO: optimize using binary search
57 while ( s_MDD_Table[t_idx].ul != 0
58 && s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
61 if ( s_MDD_Table[t_idx].ul == 0 )
64 // match successive elements
65 while ( s_MDD_Table[t_idx].ul != 0
66 && k_idx < SMPTE_UL_LENGTH - 1
67 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx] )
69 if ( s_MDD_Table[t_idx].ul[k_idx+1] == ul_buf[k_idx+1] )
75 while ( s_MDD_Table[t_idx].ul != 0
76 && s_MDD_Table[t_idx].ul[k_idx] == ul_buf[k_idx]
77 && s_MDD_Table[t_idx].ul[k_idx+1] != ul_buf[k_idx+1] )
80 while ( s_MDD_Table[t_idx].ul[k_idx] != ul_buf[k_idx] )
85 return (s_MDD_Table[t_idx].ul == 0 ? 0 : &s_MDD_Table[t_idx]);
88 //------------------------------------------------------------------------------------------
93 ASDCP::MXF::SeekToRIP(const ASDCP::FileReader& Reader)
95 ASDCP::fpos_t end_pos;
97 // go to the end - 4 bytes
98 Result_t result = Reader.Seek(0, ASDCP::SP_END);
100 if ( ASDCP_SUCCESS(result) )
101 result = Reader.Tell(&end_pos);
103 if ( ASDCP_SUCCESS(result)
104 && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
105 result = RESULT_FAIL; // File is smaller than an empty packet!
107 if ( ASDCP_SUCCESS(result) )
108 result = Reader.Seek(end_pos - 4);
110 // get the ui32_t RIP length
112 byte_t intbuf[MXF_BER_LENGTH];
115 if ( ASDCP_SUCCESS(result) )
117 result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
119 if ( ASDCP_SUCCESS(result) && read_count != 4 )
120 result = RESULT_FAIL;
123 if ( ASDCP_SUCCESS(result) )
125 rip_size = ASDCP_i32_BE(cp2i<ui32_t>(intbuf));
127 if ( rip_size > end_pos ) // RIP can't be bigger than the file
131 // reposition to start of RIP
132 if ( ASDCP_SUCCESS(result) )
133 result = Reader.Seek(end_pos - rip_size);
140 ASDCP::MXF::RIP::InitFromFile(const ASDCP::FileReader& Reader)
142 Result_t result = KLVFilePacket::InitFromFile(Reader, s_MDD_Table[MDDindex_RandomIndexMetadata].ul);
144 if ( ASDCP_SUCCESS(result) )
146 MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
147 result = PairArray.ReadFrom(MemRDR);
150 if ( ASDCP_FAILURE(result) )
151 DefaultLogSink().Error("Failed to initialize RIP\n");
158 ASDCP::MXF::RIP::WriteToFile(ASDCP::FileWriter& Writer)
160 Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_RandomIndexMetadata].ul, 0);
166 ASDCP::MXF::RIP::Dump(FILE* stream)
171 KLVFilePacket::Dump(stream, false);
172 PairArray.Dump(stream, false);
174 fputs("==========================================================================\n", stream);
177 //------------------------------------------------------------------------------------------
182 ASDCP::MXF::Partition::InitFromFile(const ASDCP::FileReader& Reader)
184 Result_t result = KLVFilePacket::InitFromFile(Reader);
186 // could be one of several values
188 if ( ASDCP_SUCCESS(result) )
190 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
191 result = MemRDR.ReadUi16BE(&MajorVersion);
192 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16BE(&MinorVersion);
193 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&KAGSize);
194 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&ThisPartition);
195 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&PreviousPartition);
196 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&FooterPartition);
197 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&HeaderByteCount);
198 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&IndexByteCount);
199 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&IndexSID);
200 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi64BE(&BodyOffset);
201 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32BE(&BodySID);
202 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.ReadFrom(MemRDR);
203 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.ReadFrom(MemRDR);
206 if ( ASDCP_FAILURE(result) )
207 DefaultLogSink().Error("Failed to initialize Partition\n");
214 ASDCP::MXF::Partition::WriteToFile(ASDCP::FileWriter& Writer)
216 Result_t result = m_Buffer.Capacity(1024);
218 if ( ASDCP_SUCCESS(result) )
220 MemIOWriter MemWRT(m_Buffer.Data(), m_Buffer.Capacity());
221 result = MemWRT.WriteUi16BE(MajorVersion);
222 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16BE(MinorVersion);
223 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(KAGSize);
224 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(ThisPartition);
225 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(PreviousPartition);
226 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(FooterPartition);
227 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(HeaderByteCount);
228 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(IndexByteCount);
229 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(IndexSID);
230 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi64BE(BodyOffset);
231 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32BE(BodySID);
232 if ( ASDCP_SUCCESS(result) ) result = OperationalPattern.WriteTo(MemWRT);
233 if ( ASDCP_SUCCESS(result) ) result = EssenceContainers.WriteTo(MemWRT);
234 if ( ASDCP_SUCCESS(result) ) m_Buffer.Size(MemWRT.Size());
237 if ( ASDCP_SUCCESS(result) )
239 ui32_t write_count; // this is subclassed, so the UL is only right some of the time
240 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_ClosedCompleteHeader].ul, m_Buffer.Size());
242 if ( ASDCP_SUCCESS(result) )
243 result = Writer.Write(m_Buffer.RoData(), m_Buffer.Size(), &write_count);
251 ASDCP::MXF::Partition::Dump(FILE* stream)
253 char identbuf[IdentBufferLen];
254 char intbuf[IntBufferLen];
259 KLVFilePacket::Dump(stream, false);
260 fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
261 fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
262 fprintf(stream, " KAGSize = %lu\n", KAGSize);
263 fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, intbuf));
264 fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, intbuf));
265 fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, intbuf));
266 fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, intbuf));
267 fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, intbuf));
268 fprintf(stream, " IndexSID = %lu\n", IndexSID);
269 fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, intbuf));
270 fprintf(stream, " BodySID = %lu\n", BodySID);
271 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
272 fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream, false);
274 fputs("==========================================================================\n", stream);
278 //------------------------------------------------------------------------------------------
281 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
284 void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
286 ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
288 for ( ; i != Batch.end(); i++ )
289 insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
295 ASDCP::MXF::Primer::Primer() {}
298 ASDCP::MXF::Primer::~Primer() {}
302 ASDCP::MXF::Primer::ClearTagList()
304 LocalTagEntryBatch.clear();
305 m_Lookup = new h__PrimerLookup;
310 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
312 Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Primer].ul);
314 if ( ASDCP_SUCCESS(result) )
316 MemIOReader MemRDR(m_ValueStart, m_ValueLength);
317 result = LocalTagEntryBatch.ReadFrom(MemRDR);
320 if ( ASDCP_SUCCESS(result) )
322 m_Lookup = new h__PrimerLookup;
323 m_Lookup->InitWithBatch(LocalTagEntryBatch);
326 if ( ASDCP_FAILURE(result) )
327 DefaultLogSink().Error("Failed to initialize Primer\n");
334 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
336 MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
337 Result_t result = LocalTagEntryBatch.WriteTo(MemWRT);
338 Buffer.Size(MemWRT.Size());
340 if ( ASDCP_SUCCESS(result) )
343 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_Primer].ul, Buffer.Size());
345 if ( ASDCP_SUCCESS(result) )
346 result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
355 ASDCP::MXF::Primer::InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
359 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
361 if ( i == m_Lookup->end() )
363 const MDDEntry* mdde = GetMDDEntry(Key.Value());
366 LocalTagEntry TmpEntry;
368 TmpEntry.Tag = mdde->tag;
370 LocalTagEntryBatch.push_back(TmpEntry);
371 m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
379 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
382 if ( m_Lookup.empty() )
384 DefaultLogSink().Error("Primer lookup is empty\n");
388 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
390 if ( i == m_Lookup->end() )
399 ASDCP::MXF::Primer::Dump(FILE* stream)
401 char identbuf[IdentBufferLen];
406 KLVPacket::Dump(stream, false);
407 fprintf(stream, "Primer: %lu %s\n",
408 LocalTagEntryBatch.ItemCount,
409 ( LocalTagEntryBatch.ItemCount == 1 ? "entry" : "entries" ));
411 Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
412 for ( ; i != LocalTagEntryBatch.end(); i++ )
414 const MDDEntry* Entry = GetMDDEntry((*i).UL.Value());
415 fprintf(stream, " %s %s\n", (*i).ToString(identbuf), (Entry ? Entry->name : "Unknown"));
418 fputs("==========================================================================\n", stream);
422 //------------------------------------------------------------------------------------------
427 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
431 Result_t result = KLVPacket::InitFromBuffer(p, l, s_MDD_Table[MDDindex_Preface].ul);
433 if ( ASDCP_SUCCESS(result) )
435 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
437 result = MemRDR.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
438 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
439 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
440 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi16(OBJ_READ_ARGS(Preface, Version));
441 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
442 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
443 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
444 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
445 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
446 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
447 if ( ASDCP_SUCCESS(result) ) result = MemRDR.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
450 if ( ASDCP_FAILURE(result) )
451 DefaultLogSink().Error("Failed to initialize Preface\n");
458 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
460 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
461 Result_t result = MemWRT.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
462 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
463 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
464 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
465 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
466 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
467 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
468 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
469 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
470 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
471 if ( ASDCP_SUCCESS(result) ) result = MemWRT.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
473 if ( ASDCP_SUCCESS(result) )
475 ui32_t packet_length = MemWRT.Size();
476 result = WriteKLToBuffer(Buffer, s_MDD_Table[MDDindex_Preface].ul, packet_length);
478 if ( ASDCP_SUCCESS(result) )
479 Buffer.Size(Buffer.Size() + packet_length);
487 ASDCP::MXF::Preface::Dump(FILE* stream)
489 char identbuf[IdentBufferLen];
494 KLVPacket::Dump(stream, false);
495 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
496 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
497 fprintf(stream, " LastModifiedDate = %s\n", LastModifiedDate.ToString(identbuf));
498 fprintf(stream, " Version = %hu\n", Version);
499 fprintf(stream, " ObjectModelVersion = %lu\n", ObjectModelVersion);
500 fprintf(stream, " PrimaryPackage = %s\n", PrimaryPackage.ToString(identbuf));
501 fprintf(stream, " Identifications:\n"); Identifications.Dump(stream);
502 fprintf(stream, " ContentStorage = %s\n", ContentStorage.ToString(identbuf));
503 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.ToString(identbuf));
504 fprintf(stream, " EssenceContainers:\n"); EssenceContainers.Dump(stream);
505 fprintf(stream, " DMSchemes:\n"); DMSchemes.Dump(stream);
507 fputs("==========================================================================\n", stream);
510 //------------------------------------------------------------------------------------------
514 class ASDCP::MXF::h__PacketList
517 std::list<InterchangeObject*> m_List;
518 std::map<UL, InterchangeObject*> m_Map;
521 while ( ! m_List.empty() )
523 delete m_List.back();
529 void AddPacket(InterchangeObject* ThePacket)
532 m_Map.insert(std::map<UID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
533 m_List.push_back(ThePacket);
537 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
539 ASDCP_TEST_NULL(ObjectID);
540 ASDCP_TEST_NULL(Object);
541 std::list<InterchangeObject*>::iterator li;
544 for ( li = m_List.begin(); li != m_List.end(); li++ )
546 if ( (*li)->HasUL(ObjectID) )
557 //------------------------------------------------------------------------------------------
560 ASDCP::MXF::OPAtomHeader::OPAtomHeader() : m_Preface(0), m_HasRIP(false)
562 m_PacketList = new h__PacketList;
566 ASDCP::MXF::OPAtomHeader::~OPAtomHeader()
572 ASDCP::MXF::OPAtomHeader::InitFromFile(const ASDCP::FileReader& Reader)
575 Result_t result = SeekToRIP(Reader);
577 if ( ASDCP_SUCCESS(result) )
579 result = m_RIP.InitFromFile(Reader);
581 if ( ASDCP_FAILURE(result) )
583 DefaultLogSink().Error("File contains no RIP\n");
592 if ( ASDCP_SUCCESS(result) )
593 result = Reader.Seek(0);
595 if ( ASDCP_SUCCESS(result) )
596 result = Partition::InitFromFile(Reader); // test UL and OP
598 // slurp up the remainder of the header
601 if ( ASDCP_SUCCESS(result) )
603 ui32_t buf_len = HeaderByteCount;
604 result = m_Buffer.Capacity(buf_len);
607 if ( ASDCP_SUCCESS(result) )
608 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
610 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
612 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %lu, got %lu\n",
613 m_Buffer.Capacity(), read_count);
617 const byte_t* p = m_Buffer.RoData();
618 const byte_t* end_p = p + m_Buffer.Capacity();
620 while ( ASDCP_SUCCESS(result) && p < end_p )
622 // parse the packets and index them by uid, discard KLVFill items
623 InterchangeObject* object = CreateObject(p);
626 object->m_Lookup = &m_Primer;
627 result = object->InitFromBuffer(p, end_p - p);
628 const byte_t* redo_p = p;
629 p += object->PacketLength();
630 // hexdump(p, object->PacketLength());
632 if ( ASDCP_SUCCESS(result) )
634 if ( object->IsA(s_MDD_Table[MDDindex_KLVFill].ul) )
638 else if ( object->IsA(s_MDD_Table[MDDindex_Primer].ul) )
641 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
643 else if ( object->IsA(s_MDD_Table[MDDindex_Preface].ul) )
649 m_PacketList->AddPacket(object);
654 DefaultLogSink().Error("Error initializing packet\n");
664 ASDCP::MXF::OPAtomHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
666 InterchangeObject* TmpObject;
671 return m_PacketList->GetMDObjectByType(ObjectID, Object);
675 ASDCP::MXF::Identification*
676 ASDCP::MXF::OPAtomHeader::GetIdentification()
678 InterchangeObject* Object;
680 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
681 return (Identification*)Object;
687 ASDCP::MXF::SourcePackage*
688 ASDCP::MXF::OPAtomHeader::GetSourcePackage()
690 InterchangeObject* Object;
692 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
693 return (SourcePackage*)Object;
700 ASDCP::MXF::OPAtomHeader::WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderSize)
702 if ( HeaderSize < 4096 )
704 DefaultLogSink().Error("HeaderSize %lu is too small. Must be >= 4096\n");
708 ASDCP::FrameBuffer HeaderBuffer;
710 Result_t result = HeaderBuffer.Capacity(HeaderSize);
711 HeaderByteCount = HeaderSize;
713 if ( ASDCP_SUCCESS(result) )
716 m_Preface->m_Lookup = &m_Primer;
717 result = m_Preface->WriteToBuffer(HeaderBuffer);
720 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
721 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
723 InterchangeObject* object = *pl_i;
724 object->m_Lookup = &m_Primer;
725 result = object->WriteToBuffer(HeaderBuffer);
728 if ( ASDCP_SUCCESS(result) )
729 result = Partition::WriteToFile(Writer);
731 // if ( ASDCP_SUCCESS(result) )
732 // result = m_Primer.WriteToFile(Writer);
734 if ( ASDCP_SUCCESS(result) )
737 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
738 assert(write_count == HeaderBuffer.Size());
742 if ( ASDCP_SUCCESS(result) )
744 ASDCP::fpos_t pos = Writer.Tell();
746 if ( pos > HeaderSize )
748 char intbuf[IntBufferLen];
749 DefaultLogSink().Error("Header size %s exceeds specified value %lu\n",
755 ASDCP::FrameBuffer NilBuf;
756 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
758 if ( klv_fill_length < kl_length )
760 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
764 klv_fill_length -= kl_length;
765 result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_KLVFill].ul, klv_fill_length);
767 if ( ASDCP_SUCCESS(result) )
768 result = NilBuf.Capacity(klv_fill_length);
770 if ( ASDCP_SUCCESS(result) )
772 memset(NilBuf.Data(), 0, klv_fill_length);
774 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
775 assert(write_count == klv_fill_length);
784 ASDCP::MXF::OPAtomHeader::Dump(FILE* stream)
792 Partition::Dump(stream);
793 m_Primer.Dump(stream);
795 m_Preface->Dump(stream);
797 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
798 for ( ; i != m_PacketList->m_List.end(); i++ )
802 //------------------------------------------------------------------------------------------
805 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter() : m_Lookup(0)
807 m_PacketList = new h__PacketList;
811 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter()
817 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const ASDCP::FileReader& Reader)
819 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
821 // slurp up the remainder of the footer
824 if ( ASDCP_SUCCESS(result) )
825 result = m_Buffer.Capacity(IndexByteCount);
827 if ( ASDCP_SUCCESS(result) )
828 result = Reader.Read(m_Buffer.Data(), m_Buffer.Capacity(), &read_count);
830 if ( ASDCP_SUCCESS(result) && read_count != m_Buffer.Capacity() )
832 DefaultLogSink().Error("Short read of footer partition: got %lu, expecting %lu\n",
833 read_count, m_Buffer.Capacity());
837 const byte_t* p = m_Buffer.RoData();
838 const byte_t* end_p = p + m_Buffer.Capacity();
840 while ( ASDCP_SUCCESS(result) && p < end_p )
842 // parse the packets and index them by uid, discard KLVFill items
843 InterchangeObject* object = CreateObject(p);
846 object->m_Lookup = m_Lookup;
847 result = object->InitFromBuffer(p, end_p - p);
848 p += object->PacketLength();
850 if ( ASDCP_SUCCESS(result) )
852 m_PacketList->AddPacket(object);
856 DefaultLogSink().Error("Error initializing packet\n");
861 if ( ASDCP_FAILURE(result) )
862 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
869 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(ASDCP::FileWriter& Writer)
871 Result_t result = WriteKLToFile(Writer, s_MDD_Table[MDDindex_CompleteFooter].ul, 0);
877 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
882 Partition::Dump(stream);
884 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
885 for ( ; i != m_PacketList->m_List.end(); i++ )
891 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry)
893 std::list<InterchangeObject*>::iterator li;
894 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
896 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
898 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
899 ui64_t start_pos = Segment->IndexStartPosition;
901 if ( Segment->EditUnitByteCount > 0 )
903 if ( m_PacketList->m_List.size() > 1 )
904 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
906 if ( ! Segment->IndexEntryArray.empty() )
907 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
909 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
912 else if ( (ui64_t)frame_num >= start_pos
913 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
915 Entry = Segment->IndexEntryArray[frame_num-start_pos];
925 //------------------------------------------------------------------------------------------
930 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
932 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
933 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
939 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
941 if ( Buffer.Capacity() < (Buffer.Size() + m_KLLength + m_ValueLength) )
943 DefaultLogSink().Error("InterchangeObject::WriteToBuffer: Buffer too small\n");
945 return RESULT_READFAIL;
948 Result_t result = WriteKLToBuffer(Buffer, m_KeyStart, m_ValueLength);
950 if ( ASDCP_SUCCESS(result) )
952 memcpy(Buffer.Data() + Buffer.Size(), m_ValueStart, m_ValueLength);
953 Buffer.Size(Buffer.Size() + m_ValueLength);
961 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
963 char identbuf[IdentBufferLen];
966 KLVPacket::Dump(stream, false);
967 fprintf(stream, " InstanceUID = %s\n", InstanceUID.ToString(identbuf));
968 fprintf(stream, " GenerationUID = %s\n", GenerationUID.ToString(identbuf));
973 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
975 if ( m_KLLength == 0 )
978 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );