2 Copyright (c) 2005-2013, 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.
36 using Kumu::DefaultLogSink;
37 using Kumu::GenRandomValue;
39 // index segments must be < 64K
40 // NOTE: this value may too high if advanced index entry elements are used.
41 const ui32_t CBRIndexEntriesPerSegment = 5000;
43 //------------------------------------------------------------------------------------------
48 ASDCP::MXF::SeekToRIP(const Kumu::FileReader& Reader)
52 // go to the end - 4 bytes
53 Result_t result = Reader.Seek(0, Kumu::SP_END);
55 if ( ASDCP_SUCCESS(result) )
56 result = Reader.Tell(&end_pos);
58 if ( ASDCP_SUCCESS(result)
59 && end_pos < (SMPTE_UL_LENGTH+MXF_BER_LENGTH) )
61 DefaultLogSink().Error("File is smaller than an empty KLV packet.\n");
65 if ( ASDCP_SUCCESS(result) )
66 result = Reader.Seek(end_pos - 4);
68 // get the ui32_t RIP length
70 byte_t intbuf[MXF_BER_LENGTH];
73 if ( ASDCP_SUCCESS(result) )
75 result = Reader.Read(intbuf, MXF_BER_LENGTH, &read_count);
77 if ( ASDCP_SUCCESS(result) && read_count != 4 )
79 DefaultLogSink().Error("RIP contains fewer than four bytes.\n");
84 if ( ASDCP_SUCCESS(result) )
86 rip_size = KM_i32_BE(Kumu::cp2i<ui32_t>(intbuf));
88 if ( rip_size > end_pos ) // RIP can't be bigger than the file
90 DefaultLogSink().Error("RIP size impossibly large.\n");
95 // reposition to start of RIP
96 if ( ASDCP_SUCCESS(result) )
97 result = Reader.Seek(end_pos - rip_size);
104 ASDCP::MXF::RIP::GetPairBySID(ui32_t SID, Pair& outPair) const
106 Array<Pair>::const_iterator pi = PairArray.begin();
107 for ( ; pi != PairArray.end(); pi++ )
109 if ( (*pi).BodySID == SID )
121 ASDCP::MXF::RIP::InitFromFile(const Kumu::FileReader& Reader)
124 Result_t result = KLVFilePacket::InitFromFile(Reader, m_Dict->ul(MDD_RandomIndexMetadata));
126 if ( ASDCP_SUCCESS(result) )
128 Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength - 4);
129 result = PairArray.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING;
132 if ( ASDCP_FAILURE(result) )
133 DefaultLogSink().Error("Failed to initialize RIP\n");
140 ASDCP::MXF::RIP::WriteToFile(Kumu::FileWriter& Writer)
143 ASDCP::FrameBuffer Buffer;
144 ui32_t RIPSize = ( PairArray.size() * (sizeof(ui32_t) + sizeof(ui64_t)) ) + 4;
145 Result_t result = Buffer.Capacity(RIPSize);
147 if ( ASDCP_SUCCESS(result) )
148 result = WriteKLToFile(Writer, m_Dict->ul(MDD_RandomIndexMetadata), RIPSize);
150 if ( ASDCP_SUCCESS(result) )
152 result = RESULT_KLV_CODING;
154 Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
155 if ( PairArray.Archive(&MemWRT) )
156 if ( MemWRT.WriteUi32BE(RIPSize + 20) )
158 Buffer.Size(MemWRT.Length());
163 if ( ASDCP_SUCCESS(result) )
164 result = Writer.Write(Buffer.RoData(), Buffer.Size());
171 ASDCP::MXF::RIP::Dump(FILE* stream)
176 KLVFilePacket::Dump(stream, *m_Dict, false);
177 PairArray.Dump(stream, false);
180 //------------------------------------------------------------------------------------------
184 ASDCP::MXF::Partition::PacketList::~PacketList() {
185 while ( ! m_List.empty() )
187 delete m_List.back();
194 ASDCP::MXF::Partition::PacketList::AddPacket(InterchangeObject* ThePacket) // takes ownership
197 m_Map.insert(std::map<UUID, InterchangeObject*>::value_type(ThePacket->InstanceUID, ThePacket));
198 m_List.push_back(ThePacket);
203 ASDCP::MXF::Partition::PacketList::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
205 ASDCP_TEST_NULL(Object);
207 std::map<UUID, InterchangeObject*>::iterator mi = m_Map.find(ObjectID);
209 if ( mi == m_Map.end() )
215 *Object = (*mi).second;
221 ASDCP::MXF::Partition::PacketList::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
223 ASDCP_TEST_NULL(ObjectID);
224 ASDCP_TEST_NULL(Object);
225 std::list<InterchangeObject*>::iterator li;
228 for ( li = m_List.begin(); li != m_List.end(); li++ )
230 if ( (*li)->HasUL(ObjectID) )
242 ASDCP::MXF::Partition::PacketList::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
244 ASDCP_TEST_NULL(ObjectID);
245 std::list<InterchangeObject*>::iterator li;
247 for ( li = m_List.begin(); li != m_List.end(); li++ )
249 if ( (*li)->HasUL(ObjectID) )
250 ObjectList.push_back(*li);
253 return ObjectList.empty() ? RESULT_FAIL : RESULT_OK;
256 //------------------------------------------------------------------------------------------
260 ASDCP::MXF::Partition::Partition(const Dictionary*& d) :
262 MajorVersion(1), MinorVersion(2),
263 KAGSize(1), ThisPartition(0), PreviousPartition(0),
264 FooterPartition(0), HeaderByteCount(0), IndexByteCount(0), IndexSID(0),
265 BodyOffset(0), BodySID(0)
267 m_PacketList = new PacketList;
270 ASDCP::MXF::Partition::~Partition()
276 ASDCP::MXF::Partition::AddChildObject(InterchangeObject* Object)
280 if ( ! Object->InstanceUID.HasValue() )
281 GenRandomValue(Object->InstanceUID);
283 m_PacketList->AddPacket(Object);
288 ASDCP::MXF::Partition::InitFromFile(const Kumu::FileReader& Reader)
290 Result_t result = KLVFilePacket::InitFromFile(Reader);
292 // could be one of several values
293 if ( ASDCP_SUCCESS(result) )
294 result = ASDCP::MXF::Partition::InitFromBuffer(m_ValueStart, m_ValueLength);
301 ASDCP::MXF::Partition::InitFromBuffer(const byte_t* p, ui32_t l)
303 Kumu::MemIOReader MemRDR(p, l);
304 Result_t result = RESULT_KLV_CODING;
306 if ( MemRDR.ReadUi16BE(&MajorVersion) )
307 if ( MemRDR.ReadUi16BE(&MinorVersion) )
308 if ( MemRDR.ReadUi32BE(&KAGSize) )
309 if ( MemRDR.ReadUi64BE(&ThisPartition) )
310 if ( MemRDR.ReadUi64BE(&PreviousPartition) )
311 if ( MemRDR.ReadUi64BE(&FooterPartition) )
312 if ( MemRDR.ReadUi64BE(&HeaderByteCount) )
313 if ( MemRDR.ReadUi64BE(&IndexByteCount) )
314 if ( MemRDR.ReadUi32BE(&IndexSID) )
315 if ( MemRDR.ReadUi64BE(&BodyOffset) )
316 if ( MemRDR.ReadUi32BE(&BodySID) )
317 if ( OperationalPattern.Unarchive(&MemRDR) )
318 if ( EssenceContainers.Unarchive(&MemRDR) )
321 if ( ASDCP_FAILURE(result) )
322 DefaultLogSink().Error("Failed to initialize Partition\n");
329 ASDCP::MXF::Partition::WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel)
331 ASDCP::FrameBuffer Buffer;
332 Result_t result = Buffer.Capacity(1024);
334 if ( ASDCP_SUCCESS(result) )
336 Kumu::MemIOWriter MemWRT(Buffer.Data(), Buffer.Capacity());
337 result = RESULT_KLV_CODING;
338 if ( MemWRT.WriteUi16BE(MajorVersion) )
339 if ( MemWRT.WriteUi16BE(MinorVersion) )
340 if ( MemWRT.WriteUi32BE(KAGSize) )
341 if ( MemWRT.WriteUi64BE(ThisPartition) )
342 if ( MemWRT.WriteUi64BE(PreviousPartition) )
343 if ( MemWRT.WriteUi64BE(FooterPartition) )
344 if ( MemWRT.WriteUi64BE(HeaderByteCount) )
345 if ( MemWRT.WriteUi64BE(IndexByteCount) )
346 if ( MemWRT.WriteUi32BE(IndexSID) )
347 if ( MemWRT.WriteUi64BE(BodyOffset) )
348 if ( MemWRT.WriteUi32BE(BodySID) )
349 if ( OperationalPattern.Archive(&MemWRT) )
350 if ( EssenceContainers.Archive(&MemWRT) )
352 Buffer.Size(MemWRT.Length());
357 if ( ASDCP_SUCCESS(result) )
360 result = WriteKLToFile(Writer, PartitionLabel.Value(), Buffer.Size());
362 if ( ASDCP_SUCCESS(result) )
363 result = Writer.Write(Buffer.RoData(), Buffer.Size(), &write_count);
371 ASDCP::MXF::Partition::ArchiveSize()
374 + sizeof(ui16_t) + sizeof(ui16_t)
376 + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t) + sizeof(ui64_t)
381 + sizeof(ui32_t) + sizeof(ui32_t) + ( UUIDlen * EssenceContainers.size() ) );
386 ASDCP::MXF::Partition::Dump(FILE* stream)
388 char identbuf[IdentBufferLen];
393 KLVFilePacket::Dump(stream, *m_Dict, false);
394 fprintf(stream, " MajorVersion = %hu\n", MajorVersion);
395 fprintf(stream, " MinorVersion = %hu\n", MinorVersion);
396 fprintf(stream, " KAGSize = %u\n", KAGSize);
397 fprintf(stream, " ThisPartition = %s\n", ui64sz(ThisPartition, identbuf));
398 fprintf(stream, " PreviousPartition = %s\n", ui64sz(PreviousPartition, identbuf));
399 fprintf(stream, " FooterPartition = %s\n", ui64sz(FooterPartition, identbuf));
400 fprintf(stream, " HeaderByteCount = %s\n", ui64sz(HeaderByteCount, identbuf));
401 fprintf(stream, " IndexByteCount = %s\n", ui64sz(IndexByteCount, identbuf));
402 fprintf(stream, " IndexSID = %u\n", IndexSID);
403 fprintf(stream, " BodyOffset = %s\n", ui64sz(BodyOffset, identbuf));
404 fprintf(stream, " BodySID = %u\n", BodySID);
405 fprintf(stream, " OperationalPattern = %s\n", OperationalPattern.EncodeString(identbuf, IdentBufferLen));
406 fputs("Essence Containers:\n", stream); EssenceContainers.Dump(stream);
410 //------------------------------------------------------------------------------------------
413 class ASDCP::MXF::Primer::h__PrimerLookup : public std::map<UL, TagValue>
416 void InitWithBatch(ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>& Batch)
418 ASDCP::MXF::Batch<ASDCP::MXF::Primer::LocalTagEntry>::iterator i = Batch.begin();
420 for ( ; i != Batch.end(); i++ )
421 insert(std::map<UL, TagValue>::value_type((*i).UL, (*i).Tag));
427 ASDCP::MXF::Primer::Primer(const Dictionary*& d) : m_LocalTag(0xff), m_Dict(d) {
428 m_UL = m_Dict->ul(MDD_Primer);
432 ASDCP::MXF::Primer::~Primer() {}
436 ASDCP::MXF::Primer::ClearTagList()
438 LocalTagEntryBatch.clear();
439 m_Lookup = new h__PrimerLookup;
444 ASDCP::MXF::Primer::InitFromBuffer(const byte_t* p, ui32_t l)
447 Result_t result = KLVPacket::InitFromBuffer(p, l, m_Dict->ul(MDD_Primer));
449 if ( ASDCP_SUCCESS(result) )
451 Kumu::MemIOReader MemRDR(m_ValueStart, m_ValueLength);
452 result = LocalTagEntryBatch.Unarchive(&MemRDR) ? RESULT_OK : RESULT_KLV_CODING;
455 if ( ASDCP_SUCCESS(result) )
457 m_Lookup = new h__PrimerLookup;
458 m_Lookup->InitWithBatch(LocalTagEntryBatch);
461 if ( ASDCP_FAILURE(result) )
462 DefaultLogSink().Error("Failed to initialize Primer\n");
469 ASDCP::MXF::Primer::WriteToFile(Kumu::FileWriter& Writer)
471 ASDCP::FrameBuffer Buffer;
472 Result_t result = Buffer.Capacity(128*1024);
474 if ( ASDCP_SUCCESS(result) )
475 result = WriteToBuffer(Buffer);
477 if ( ASDCP_SUCCESS(result) )
478 result = Writer.Write(Buffer.RoData(), Buffer.Size());
485 ASDCP::MXF::Primer::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
488 ASDCP::FrameBuffer LocalTagBuffer;
489 Kumu::MemIOWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length);
490 Result_t result = LocalTagEntryBatch.Archive(&MemWRT) ? RESULT_OK : RESULT_KLV_CODING;
492 if ( ASDCP_SUCCESS(result) )
494 ui32_t packet_length = MemWRT.Length();
495 result = WriteKLToBuffer(Buffer, packet_length);
497 if ( ASDCP_SUCCESS(result) )
498 Buffer.Size(Buffer.Size() + packet_length);
506 ASDCP::MXF::Primer::InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag)
510 std::map<UL, TagValue>::iterator i = m_Lookup->find(TestUL);
512 if ( i == m_Lookup->end() )
514 if ( Entry.tag.a == 0 && Entry.tag.b == 0 )
517 Tag.b = m_LocalTag--;
525 LocalTagEntry TmpEntry;
526 TmpEntry.UL = TestUL;
529 LocalTagEntryBatch.push_back(TmpEntry);
530 m_Lookup->insert(std::map<UL, TagValue>::value_type(TmpEntry.UL, TmpEntry.Tag));
542 ASDCP::MXF::Primer::TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag)
545 if ( m_Lookup.empty() )
547 DefaultLogSink().Error("Primer lookup is empty\n");
551 std::map<UL, TagValue>::iterator i = m_Lookup->find(Key);
553 if ( i == m_Lookup->end() )
562 ASDCP::MXF::Primer::Dump(FILE* stream)
565 char identbuf[IdentBufferLen];
570 KLVPacket::Dump(stream, *m_Dict, false);
571 fprintf(stream, "Primer: %u %s\n",
572 (ui32_t)LocalTagEntryBatch.size(),
573 ( LocalTagEntryBatch.size() == 1 ? "entry" : "entries" ));
575 Batch<LocalTagEntry>::iterator i = LocalTagEntryBatch.begin();
576 for ( ; i != LocalTagEntryBatch.end(); i++ )
578 const MDDEntry* Entry = m_Dict->FindUL((*i).UL.Value());
579 fprintf(stream, " %s %s\n", (*i).EncodeString(identbuf, IdentBufferLen), (Entry ? Entry->name : "Unknown"));
584 //------------------------------------------------------------------------------------------
588 ASDCP::MXF::Preface::Preface(const Dictionary*& d) :
589 InterchangeObject(d), m_Dict(d), Version(258), ObjectModelVersion(0)
592 m_UL = m_Dict->Type(MDD_Preface).ul;
597 ASDCP::MXF::Preface::Copy(const Preface& rhs)
599 InterchangeObject::Copy(rhs);
601 LastModifiedDate = rhs.LastModifiedDate;
602 Version = rhs.Version;
603 ObjectModelVersion = rhs.ObjectModelVersion;
604 PrimaryPackage = rhs.PrimaryPackage;
605 Identifications = rhs.Identifications;
606 ContentStorage = rhs.ContentStorage;
607 OperationalPattern = rhs.OperationalPattern;
608 EssenceContainers = rhs.EssenceContainers;
609 DMSchemes = rhs.DMSchemes;
614 ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
616 Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
617 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
618 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version));
619 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS(Preface, ObjectModelVersion));
620 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, PrimaryPackage));
621 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
622 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
623 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
624 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
625 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
631 ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
633 Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
634 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
635 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
636 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS(Preface, ObjectModelVersion));
637 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, PrimaryPackage));
638 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
639 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
640 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
641 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
642 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
648 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
650 return InterchangeObject::InitFromBuffer(p, l);
655 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
657 return InterchangeObject::WriteToBuffer(Buffer);
662 ASDCP::MXF::Preface::Dump(FILE* stream)
664 char identbuf[IdentBufferLen];
669 InterchangeObject::Dump(stream);
670 fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.EncodeString(identbuf, IdentBufferLen));
671 fprintf(stream, " %22s = %hu\n", "Version", Version);
672 fprintf(stream, " %22s = %u\n", "ObjectModelVersion", ObjectModelVersion);
673 fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.EncodeHex(identbuf, IdentBufferLen));
674 fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream);
675 fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.EncodeHex(identbuf, IdentBufferLen));
676 fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen));
677 fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream);
678 fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream);
681 //------------------------------------------------------------------------------------------
684 ASDCP::MXF::OP1aHeader::OP1aHeader(const Dictionary*& d) : Partition(d), m_Dict(d), m_Primer(d), m_Preface(0) {}
685 ASDCP::MXF::OP1aHeader::~OP1aHeader() {}
689 ASDCP::MXF::OP1aHeader::InitFromFile(const Kumu::FileReader& Reader)
691 Result_t result = result = Partition::InitFromFile(Reader);
693 if ( ASDCP_FAILURE(result) )
696 if ( m_Dict == &DefaultCompositeDict() )
698 // select more explicit dictionary if one is available
699 if ( OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) )
701 m_Dict = &DefaultInteropDict();
703 else if ( OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) )
705 m_Dict = &DefaultSMPTEDict();
709 // slurp up the remainder of the header
710 if ( HeaderByteCount < 1024 )
711 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %u\n", HeaderByteCount);
713 assert (HeaderByteCount <= 0xFFFFFFFFL);
714 result = m_HeaderData.Capacity((ui32_t)HeaderByteCount);
716 if ( ASDCP_SUCCESS(result) )
719 result = Reader.Read(m_HeaderData.Data(), m_HeaderData.Capacity(), &read_count);
721 if ( ASDCP_FAILURE(result) )
723 DefaultLogSink().Error("OP1aHeader::InitFromFile, Read failed\n");
727 if ( read_count != m_HeaderData.Capacity() )
729 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %u, got %u\n",
730 m_HeaderData.Capacity(), read_count);
731 return RESULT_KLV_CODING;
735 if ( ASDCP_SUCCESS(result) )
736 result = InitFromBuffer(m_HeaderData.RoData(), m_HeaderData.Capacity());
743 ASDCP::MXF::OP1aHeader::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
745 Result_t result = KLVPacket::InitFromBuffer(p, l);
747 if ( ASDCP_SUCCESS(result) )
748 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
750 if ( ASDCP_SUCCESS(result) )
752 ui32_t pp_len = KLVPacket::PacketLength();
753 result = InitFromBuffer(p + pp_len, l - pp_len);
761 ASDCP::MXF::OP1aHeader::InitFromBuffer(const byte_t* p, ui32_t l)
764 Result_t result = RESULT_OK;
765 const byte_t* end_p = p + l;
767 while ( ASDCP_SUCCESS(result) && p < end_p )
769 // parse the packets and index them by uid, discard KLVFill items
770 InterchangeObject* object = CreateObject(m_Dict, p);
773 object->m_Lookup = &m_Primer;
774 result = object->InitFromBuffer(p, end_p - p);
775 const byte_t* redo_p = p;
776 p += object->PacketLength();
777 // hexdump(p, object->PacketLength());
779 if ( ASDCP_SUCCESS(result) )
781 if ( object->IsA(m_Dict->ul(MDD_KLVFill)) )
787 DefaultLogSink().Error("Fill item short read: %d.\n", p - end_p);
790 else if ( object->IsA(m_Dict->ul(MDD_Primer)) ) // TODO: only one primer should be found
793 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
797 m_PacketList->AddPacket(object); // takes ownership
799 if ( object->IsA(m_Dict->ul(MDD_Preface)) && m_Preface == 0 )
800 m_Preface = (Preface*)object;
805 DefaultLogSink().Error("Error initializing packet\n");
814 ASDCP::MXF::OP1aHeader::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
816 return m_PacketList->GetMDObjectByID(ObjectID, Object);
821 ASDCP::MXF::OP1aHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
823 InterchangeObject* TmpObject;
828 return m_PacketList->GetMDObjectByType(ObjectID, Object);
833 ASDCP::MXF::OP1aHeader::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
835 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
839 ASDCP::MXF::Identification*
840 ASDCP::MXF::OP1aHeader::GetIdentification()
842 InterchangeObject* Object;
844 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
845 return (Identification*)Object;
851 ASDCP::MXF::SourcePackage*
852 ASDCP::MXF::OP1aHeader::GetSourcePackage()
854 InterchangeObject* Object;
856 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
857 return (SourcePackage*)Object;
864 ASDCP::MXF::OP1aHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize)
867 if ( m_Preface == 0 )
870 if ( HeaderSize < 4096 )
872 DefaultLogSink().Error("HeaderSize %u is too small. Must be >= 4096\n", HeaderSize);
876 ASDCP::FrameBuffer HeaderBuffer;
877 HeaderByteCount = HeaderSize - ArchiveSize();
878 assert (HeaderByteCount <= 0xFFFFFFFFL);
879 Result_t result = HeaderBuffer.Capacity((ui32_t) HeaderByteCount);
880 m_Preface->m_Lookup = &m_Primer;
882 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
883 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
885 InterchangeObject* object = *pl_i;
886 object->m_Lookup = &m_Primer;
888 ASDCP::FrameBuffer WriteWrapper;
889 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
890 HeaderBuffer.Capacity() - HeaderBuffer.Size());
891 result = object->WriteToBuffer(WriteWrapper);
892 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
895 if ( ASDCP_SUCCESS(result) )
897 UL TmpUL(m_Dict->ul(MDD_ClosedCompleteHeader));
898 result = Partition::WriteToFile(Writer, TmpUL);
901 if ( ASDCP_SUCCESS(result) )
902 result = m_Primer.WriteToFile(Writer);
904 if ( ASDCP_SUCCESS(result) )
907 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
908 assert(write_count == HeaderBuffer.Size());
912 if ( ASDCP_SUCCESS(result) )
914 Kumu::fpos_t pos = Writer.Tell();
916 if ( pos > (Kumu::fpos_t)HeaderByteCount )
918 char intbuf[IntBufferLen];
919 DefaultLogSink().Error("Header size %s exceeds specified value %u\n",
925 ASDCP::FrameBuffer NilBuf;
926 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
928 if ( klv_fill_length < kl_length )
930 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
934 klv_fill_length -= kl_length;
935 result = WriteKLToFile(Writer, m_Dict->ul(MDD_KLVFill), klv_fill_length);
937 if ( ASDCP_SUCCESS(result) )
938 result = NilBuf.Capacity(klv_fill_length);
940 if ( ASDCP_SUCCESS(result) )
942 memset(NilBuf.Data(), 0, klv_fill_length);
944 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
945 assert(write_count == klv_fill_length);
954 ASDCP::MXF::OP1aHeader::Dump(FILE* stream)
959 Partition::Dump(stream);
960 m_Primer.Dump(stream);
962 if ( m_Preface == 0 )
963 fputs("No Preface loaded\n", stream);
965 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
966 for ( ; i != m_PacketList->m_List.end(); i++ )
970 //------------------------------------------------------------------------------------------
973 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter(const Dictionary*& d) :
974 Partition(d), m_Dict(d),
975 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
976 m_ECOffset(0), m_Lookup(0)
982 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
986 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
988 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
990 // slurp up the remainder of the footer
991 ui32_t read_count = 0;
993 if ( ASDCP_SUCCESS(result) && IndexByteCount > 0 )
995 assert (IndexByteCount <= 0xFFFFFFFFL);
996 // At this point, m_FooterData may not have been initialized
997 // so it's capacity is zero and data pointer is NULL
998 // However, if IndexByteCount is zero then the capacity
999 // doesn't change and the data pointer is not set.
1000 result = m_FooterData.Capacity((ui32_t) IndexByteCount);
1002 if ( ASDCP_SUCCESS(result) )
1003 result = Reader.Read(m_FooterData.Data(), m_FooterData.Capacity(), &read_count);
1005 if ( ASDCP_SUCCESS(result) && read_count != m_FooterData.Capacity() )
1007 DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
1008 read_count, m_FooterData.Capacity());
1011 else if( ASDCP_SUCCESS(result) && !m_FooterData.Data() )
1013 DefaultLogSink().Error( "Buffer for footer partition not created: IndexByteCount = %u\n",
1018 if ( ASDCP_SUCCESS(result) )
1019 result = InitFromBuffer(m_FooterData.RoData(), m_FooterData.Capacity());
1027 ASDCP::MXF::OPAtomIndexFooter::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
1029 Result_t result = KLVPacket::InitFromBuffer(p, l);
1031 if ( ASDCP_SUCCESS(result) )
1032 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
1034 if ( ASDCP_SUCCESS(result) )
1036 ui32_t pp_len = KLVPacket::PacketLength();
1037 result = InitFromBuffer(p + pp_len, l - pp_len);
1045 ASDCP::MXF::OPAtomIndexFooter::InitFromBuffer(const byte_t* p, ui32_t l)
1047 Result_t result = RESULT_OK;
1048 const byte_t* end_p = p + l;
1050 while ( ASDCP_SUCCESS(result) && p < end_p )
1052 // parse the packets and index them by uid, discard KLVFill items
1053 InterchangeObject* object = CreateObject(m_Dict, p);
1056 object->m_Lookup = m_Lookup;
1057 result = object->InitFromBuffer(p, end_p - p);
1058 p += object->PacketLength();
1060 if ( ASDCP_SUCCESS(result) )
1062 m_PacketList->AddPacket(object); // takes ownership
1066 DefaultLogSink().Error("Error initializing packet\n");
1071 if ( ASDCP_FAILURE(result) )
1072 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
1079 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration)
1082 ASDCP::FrameBuffer FooterBuffer;
1083 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
1084 Result_t result = FooterBuffer.Capacity(footer_size);
1085 ui32_t iseg_count = 0;
1087 if ( m_CurrentSegment != 0 )
1089 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1090 m_CurrentSegment = 0;
1093 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
1094 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
1096 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1099 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
1101 if ( m_BytesPerEditUnit != 0 )
1103 if ( iseg_count != 1 )
1104 return RESULT_STATE;
1106 Segment->IndexDuration = duration;
1110 InterchangeObject* object = *pl_i;
1111 object->m_Lookup = m_Lookup;
1113 ASDCP::FrameBuffer WriteWrapper;
1114 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
1115 FooterBuffer.Capacity() - FooterBuffer.Size());
1116 result = object->WriteToBuffer(WriteWrapper);
1117 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
1120 if ( ASDCP_SUCCESS(result) )
1122 IndexByteCount = FooterBuffer.Size();
1123 UL FooterUL(m_Dict->ul(MDD_CompleteFooter));
1124 result = Partition::WriteToFile(Writer, FooterUL);
1127 if ( ASDCP_SUCCESS(result) )
1129 ui32_t write_count = 0;
1130 result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
1131 assert(write_count == FooterBuffer.Size());
1139 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1144 Partition::Dump(stream);
1146 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1147 for ( ; i != m_PacketList->m_List.end(); i++ )
1152 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
1154 return m_PacketList->GetMDObjectByID(ObjectID, Object);
1159 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
1161 InterchangeObject* TmpObject;
1164 Object = &TmpObject;
1166 return m_PacketList->GetMDObjectByType(ObjectID, Object);
1171 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
1173 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
1178 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const
1180 std::list<InterchangeObject*>::iterator li;
1181 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1183 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1185 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1186 ui64_t start_pos = Segment->IndexStartPosition;
1188 if ( Segment->EditUnitByteCount > 0 )
1190 if ( m_PacketList->m_List.size() > 1 )
1191 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1193 if ( ! Segment->IndexEntryArray.empty() )
1194 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1196 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1199 else if ( (ui64_t)frame_num >= start_pos
1200 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1202 ui64_t tmp = frame_num - start_pos;
1203 assert(tmp <= 0xFFFFFFFFL);
1204 Entry = Segment->IndexEntryArray[(ui32_t) tmp];
1215 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1219 m_BytesPerEditUnit = size;
1222 IndexTableSegment* Index = new IndexTableSegment(m_Dict);
1223 AddChildObject(Index);
1224 Index->EditUnitByteCount = m_BytesPerEditUnit;
1225 Index->IndexEditRate = Rate;
1230 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset)
1234 m_BytesPerEditUnit = 0;
1236 m_ECOffset = offset;
1241 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1243 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1245 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1249 // do we have an available segment?
1250 if ( m_CurrentSegment == 0 )
1251 { // no, set up a new segment
1252 m_CurrentSegment = new IndexTableSegment(m_Dict);
1253 assert(m_CurrentSegment);
1254 AddChildObject(m_CurrentSegment);
1255 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1256 m_CurrentSegment->IndexEditRate = m_EditRate;
1257 m_CurrentSegment->IndexStartPosition = 0;
1259 else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
1260 { // no, this one is full, start another
1261 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1262 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1264 m_CurrentSegment = new IndexTableSegment(m_Dict);
1265 assert(m_CurrentSegment);
1266 AddChildObject(m_CurrentSegment);
1267 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1268 m_CurrentSegment->IndexEditRate = m_EditRate;
1269 m_CurrentSegment->IndexStartPosition = StartPosition;
1272 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1275 //------------------------------------------------------------------------------------------
1280 ASDCP::MXF::InterchangeObject::Copy(const InterchangeObject& rhs)
1283 InstanceUID = rhs.InstanceUID;
1284 GenerationUID = rhs.GenerationUID;
1289 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1291 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1292 if ( ASDCP_SUCCESS(result) )
1293 result = TLVSet.ReadObject(OBJ_READ_ARGS(GenerationInterchangeObject, GenerationUID));
1299 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1301 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1302 if ( ASDCP_SUCCESS(result) )
1303 result = TLVSet.WriteObject(OBJ_WRITE_ARGS(GenerationInterchangeObject, GenerationUID));
1309 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1312 Result_t result = RESULT_FALSE;
1314 if ( m_UL.HasValue() )
1316 result = KLVPacket::InitFromBuffer(p, l, m_UL);
1318 if ( ASDCP_SUCCESS(result) )
1320 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1321 result = InitFromTLVSet(MemRDR);
1326 result = KLVPacket::InitFromBuffer(p, l);
1334 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1336 if ( ! m_UL.HasValue() )
1337 return RESULT_STATE;
1339 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1340 Result_t result = WriteToTLVSet(MemWRT);
1342 if ( ASDCP_SUCCESS(result) )
1344 ui32_t packet_length = MemWRT.Length();
1345 result = WriteKLToBuffer(Buffer, packet_length);
1347 if ( ASDCP_SUCCESS(result) )
1348 Buffer.Size(Buffer.Size() + packet_length);
1356 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1358 char identbuf[IdentBufferLen];
1360 fputc('\n', stream);
1361 KLVPacket::Dump(stream, *m_Dict, false);
1362 fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen));
1363 fprintf(stream, " GenerationUID = %s\n", GenerationUID.EncodeHex(identbuf, IdentBufferLen));
1368 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1370 if ( m_KLLength == 0 )
1373 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
1377 //------------------------------------------------------------------------------------------
1380 typedef std::map<ASDCP::UL, ASDCP::MXF::MXFObjectFactory_t>FactoryMap_t;
1381 typedef FactoryMap_t::iterator FLi_t;
1384 class FactoryList : public FactoryMap_t
1393 Kumu::AutoMutex BlockLock(m_Lock);
1397 FLi_t Find(const byte_t* label) {
1398 Kumu::AutoMutex BlockLock(m_Lock);
1403 Kumu::AutoMutex BlockLock(m_Lock);
1407 void Insert(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) {
1408 Kumu::AutoMutex BlockLock(m_Lock);
1409 insert(FactoryList::value_type(label, factory));
1414 static FactoryList s_FactoryList;
1415 static Kumu::Mutex s_InitLock;
1416 static bool s_TypesInit = false;
1421 ASDCP::MXF::SetObjectFactory(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory)
1423 s_FactoryList.Insert(label, factory);
1427 ASDCP::MXF::InterchangeObject*
1428 ASDCP::MXF::CreateObject(const Dictionary*& Dict, const UL& label)
1430 if ( ! s_TypesInit )
1432 Kumu::AutoMutex BlockLock(s_InitLock);
1434 if ( ! s_TypesInit )
1436 MXF::Metadata_InitTypes(Dict);
1441 FLi_t i = s_FactoryList.find(label.Value());
1443 if ( i == s_FactoryList.end() )
1444 return new InterchangeObject(Dict);
1446 return i->second(Dict);
1450 //------------------------------------------------------------------------------------------
1454 ASDCP::MXF::decode_mca_string(const std::string& s, const mca_label_map_t& labels, const Dictionary& dict, const std::string& language,
1455 InterchangeObject_list_t& descriptor_list, ui32_t& channel_count)
1457 const Dictionary *dictp = &dict;
1458 std::string symbol_buf;
1460 ASDCP::MXF::SoundfieldGroupLabelSubDescriptor *current_soundfield = 0;
1461 std::string::const_iterator i;
1463 for ( i = s.begin(); i != s.end(); ++i )
1467 if ( current_soundfield != 0 )
1469 fprintf(stderr, "Encountered '(', already processing a soundfield group.\n");
1473 if ( symbol_buf.empty() )
1475 fprintf(stderr, "Encountered '(', without leading soundfield group symbol.\n");
1479 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1481 if ( i == labels.end() )
1483 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1487 if ( i->second.Value()[10] != 2 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1489 fprintf(stderr, "Not a soundfield group symbol: '%s'\n", symbol_buf.c_str());
1493 current_soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(dictp);
1495 GenRandomValue(current_soundfield->InstanceUID);
1496 GenRandomValue(current_soundfield->MCALinkID);
1497 current_soundfield->MCATagSymbol = "sg" + i->first;
1498 current_soundfield->MCATagName = i->first;
1499 current_soundfield->RFC5646SpokenLanguage = language;
1500 current_soundfield->MCALabelDictionaryID = i->second;
1501 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(current_soundfield));
1504 else if ( *i == ')' )
1506 if ( current_soundfield == 0 )
1508 fprintf(stderr, "Encountered ')', not currently processing a soundfield group.\n");
1512 if ( symbol_buf.empty() )
1514 fprintf(stderr, "Soundfield group description contains no channels.\n");
1518 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1520 if ( i == labels.end() )
1522 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1526 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1527 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1529 GenRandomValue(channel_descr->InstanceUID);
1530 assert(current_soundfield);
1531 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1532 channel_descr->MCAChannelID = channel_count++;
1533 channel_descr->MCATagSymbol = "ch" + i->first;
1534 channel_descr->MCATagName = i->first;
1535 channel_descr->RFC5646SpokenLanguage = language;
1536 channel_descr->MCALabelDictionaryID = i->second;
1537 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1539 current_soundfield = 0;
1541 else if ( *i == ',' )
1543 if ( ! symbol_buf.empty() )
1545 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1547 if ( i == labels.end() )
1549 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1553 if ( i->second.Value()[10] != 1 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1555 fprintf(stderr, "Not a channel symbol: '%s'\n", symbol_buf.c_str());
1559 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1560 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1562 GenRandomValue(channel_descr->InstanceUID);
1564 if ( current_soundfield != 0 )
1566 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1569 channel_descr->MCAChannelID = channel_count++;
1570 channel_descr->MCATagSymbol = "ch" + i->first;
1571 channel_descr->MCATagName = i->first;
1572 channel_descr->RFC5646SpokenLanguage = language;
1573 channel_descr->MCALabelDictionaryID = i->second;
1574 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1578 else if ( isalnum(*i) )
1582 else if ( ! isspace(*i) )
1584 fprintf(stderr, "Unexpected character '%c'.\n", *i);
1589 if ( ! symbol_buf.empty() )
1591 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1593 if ( i == labels.end() )
1595 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1599 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1600 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1602 GenRandomValue(channel_descr->InstanceUID);
1604 if ( current_soundfield != 0 )
1606 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1609 channel_descr->MCAChannelID = channel_count++;
1610 channel_descr->MCATagSymbol = "ch" + i->first;
1611 channel_descr->MCATagName = i->first;
1612 channel_descr->RFC5646SpokenLanguage = language;
1613 channel_descr->MCALabelDictionaryID = i->second;
1614 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1621 ASDCP::MXF::ASDCP_MCAConfigParser::ASDCP_MCAConfigParser(const Dictionary*& d) : m_Dict(d), m_ChannelCount(0)
1623 m_LabelMap.insert(mca_label_map_t::value_type("L", m_Dict->ul(MDD_DCAudioChannel_L)));
1624 m_LabelMap.insert(mca_label_map_t::value_type("R", m_Dict->ul(MDD_DCAudioChannel_R)));
1625 m_LabelMap.insert(mca_label_map_t::value_type("C", m_Dict->ul(MDD_DCAudioChannel_C)));
1626 m_LabelMap.insert(mca_label_map_t::value_type("LFE", m_Dict->ul(MDD_DCAudioChannel_LFE)));
1627 m_LabelMap.insert(mca_label_map_t::value_type("Ls", m_Dict->ul(MDD_DCAudioChannel_Ls)));
1628 m_LabelMap.insert(mca_label_map_t::value_type("Rs", m_Dict->ul(MDD_DCAudioChannel_Rs)));
1629 m_LabelMap.insert(mca_label_map_t::value_type("Lss", m_Dict->ul(MDD_DCAudioChannel_Lss)));
1630 m_LabelMap.insert(mca_label_map_t::value_type("Rss", m_Dict->ul(MDD_DCAudioChannel_Rss)));
1631 m_LabelMap.insert(mca_label_map_t::value_type("Lrs", m_Dict->ul(MDD_DCAudioChannel_Lrs)));
1632 m_LabelMap.insert(mca_label_map_t::value_type("Rrs", m_Dict->ul(MDD_DCAudioChannel_Rrs)));
1633 m_LabelMap.insert(mca_label_map_t::value_type("Lc", m_Dict->ul(MDD_DCAudioChannel_Lc)));
1634 m_LabelMap.insert(mca_label_map_t::value_type("Rc", m_Dict->ul(MDD_DCAudioChannel_Rc)));
1635 m_LabelMap.insert(mca_label_map_t::value_type("Cs", m_Dict->ul(MDD_DCAudioChannel_Cs)));
1636 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_DCAudioChannel_HI)));
1637 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_DCAudioChannel_VIN)));
1638 m_LabelMap.insert(mca_label_map_t::value_type("51", m_Dict->ul(MDD_DCAudioSoundfield_51)));
1639 m_LabelMap.insert(mca_label_map_t::value_type("71", m_Dict->ul(MDD_DCAudioSoundfield_71)));
1640 m_LabelMap.insert(mca_label_map_t::value_type("SDS", m_Dict->ul(MDD_DCAudioSoundfield_SDS)));
1641 m_LabelMap.insert(mca_label_map_t::value_type("61", m_Dict->ul(MDD_DCAudioSoundfield_61)));
1642 m_LabelMap.insert(mca_label_map_t::value_type("M", m_Dict->ul(MDD_DCAudioSoundfield_M)));
1647 ASDCP::MXF::ASDCP_MCAConfigParser::ChannelCount() const
1649 return m_ChannelCount;
1652 // 51(L,R,C,LFE,Ls,Rs),HI,VIN
1654 ASDCP::MXF::ASDCP_MCAConfigParser::DecodeString(const std::string& s, const std::string& language)
1656 return decode_mca_string(s, m_LabelMap, *m_Dict, language, *this, m_ChannelCount);
1661 ASDCP::MXF::AS02_MCAConfigParser::AS02_MCAConfigParser(const Dictionary*& d) : ASDCP::MXF::ASDCP_MCAConfigParser(d)
1663 m_LabelMap.insert(mca_label_map_t::value_type("M1", m_Dict->ul(MDD_IMFAudioChannel_M1)));
1664 m_LabelMap.insert(mca_label_map_t::value_type("M2", m_Dict->ul(MDD_IMFAudioChannel_M2)));
1665 m_LabelMap.insert(mca_label_map_t::value_type("Lt", m_Dict->ul(MDD_IMFAudioChannel_Lt)));
1666 m_LabelMap.insert(mca_label_map_t::value_type("Rt", m_Dict->ul(MDD_IMFAudioChannel_Rt)));
1667 m_LabelMap.insert(mca_label_map_t::value_type("Lst", m_Dict->ul(MDD_IMFAudioChannel_Lst)));
1668 m_LabelMap.insert(mca_label_map_t::value_type("Rst", m_Dict->ul(MDD_IMFAudioChannel_Rst)));
1669 m_LabelMap.insert(mca_label_map_t::value_type("S", m_Dict->ul(MDD_IMFAudioChannel_S)));
1670 m_LabelMap.insert(mca_label_map_t::value_type("ST", m_Dict->ul(MDD_IMFAudioSoundfield_ST)));
1671 m_LabelMap.insert(mca_label_map_t::value_type("DM", m_Dict->ul(MDD_IMFAudioSoundfield_DM)));
1672 m_LabelMap.insert(mca_label_map_t::value_type("DNS", m_Dict->ul(MDD_IMFAudioSoundfield_DNS)));
1673 m_LabelMap.insert(mca_label_map_t::value_type("30", m_Dict->ul(MDD_IMFAudioSoundfield_30)));
1674 m_LabelMap.insert(mca_label_map_t::value_type("40", m_Dict->ul(MDD_IMFAudioSoundfield_40)));
1675 m_LabelMap.insert(mca_label_map_t::value_type("50", m_Dict->ul(MDD_IMFAudioSoundfield_50)));
1676 m_LabelMap.insert(mca_label_map_t::value_type("60", m_Dict->ul(MDD_IMFAudioSoundfield_60)));
1677 m_LabelMap.insert(mca_label_map_t::value_type("70", m_Dict->ul(MDD_IMFAudioSoundfield_70)));
1678 m_LabelMap.insert(mca_label_map_t::value_type("LtRt", m_Dict->ul(MDD_IMFAudioSoundfield_LtRt)));
1679 m_LabelMap.insert(mca_label_map_t::value_type("51Ex", m_Dict->ul(MDD_IMFAudioSoundfield_51Ex)));
1680 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_IMFAudioSoundfield_HI)));
1681 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_IMFAudioSoundfield_VIN)));