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)
592 m_UL = m_Dict->Type(MDD_Preface).ul;
593 ObjectModelVersion = 0;
598 ASDCP::MXF::Preface::Copy(const Preface& rhs)
600 InterchangeObject::Copy(rhs);
602 LastModifiedDate = rhs.LastModifiedDate;
603 Version = rhs.Version;
604 ObjectModelVersion = rhs.ObjectModelVersion;
605 PrimaryPackage = rhs.PrimaryPackage;
606 Identifications = rhs.Identifications;
607 ContentStorage = rhs.ContentStorage;
608 OperationalPattern = rhs.OperationalPattern;
609 EssenceContainers = rhs.EssenceContainers;
610 DMSchemes = rhs.DMSchemes;
615 ASDCP::MXF::Preface::InitFromTLVSet(TLVReader& TLVSet)
617 Result_t result = InterchangeObject::InitFromTLVSet(TLVSet);
618 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, LastModifiedDate));
619 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi16(OBJ_READ_ARGS(Preface, Version));
620 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadUi32(OBJ_READ_ARGS_OPT(Preface, ObjectModelVersion));
621 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(Preface, PrimaryPackage));
622 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, Identifications));
623 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, ContentStorage));
624 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, OperationalPattern));
625 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, EssenceContainers));
626 if ( ASDCP_SUCCESS(result) ) result = TLVSet.ReadObject(OBJ_READ_ARGS(Preface, DMSchemes));
632 ASDCP::MXF::Preface::WriteToTLVSet(TLVWriter& TLVSet)
634 Result_t result = InterchangeObject::WriteToTLVSet(TLVSet);
635 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, LastModifiedDate));
636 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi16(OBJ_WRITE_ARGS(Preface, Version));
637 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteUi32(OBJ_WRITE_ARGS_OPT(Preface, ObjectModelVersion));
638 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(Preface, PrimaryPackage));
639 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, Identifications));
640 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, ContentStorage));
641 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, OperationalPattern));
642 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, EssenceContainers));
643 if ( ASDCP_SUCCESS(result) ) result = TLVSet.WriteObject(OBJ_WRITE_ARGS(Preface, DMSchemes));
649 ASDCP::MXF::Preface::InitFromBuffer(const byte_t* p, ui32_t l)
651 return InterchangeObject::InitFromBuffer(p, l);
656 ASDCP::MXF::Preface::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
658 return InterchangeObject::WriteToBuffer(Buffer);
663 ASDCP::MXF::Preface::Dump(FILE* stream)
665 char identbuf[IdentBufferLen];
670 InterchangeObject::Dump(stream);
671 fprintf(stream, " %22s = %s\n", "LastModifiedDate", LastModifiedDate.EncodeString(identbuf, IdentBufferLen));
672 fprintf(stream, " %22s = %hu\n", "Version", Version);
674 if ( ! ObjectModelVersion.empty() )
675 fprintf(stream, " %22s = %u\n", "ObjectModelVersion", ObjectModelVersion.get());
677 if ( ! PrimaryPackage.empty() )
678 fprintf(stream, " %22s = %s\n", "PrimaryPackage", PrimaryPackage.get().EncodeHex(identbuf, IdentBufferLen));
680 fprintf(stream, " %22s:\n", "Identifications"); Identifications.Dump(stream);
681 fprintf(stream, " %22s = %s\n", "ContentStorage", ContentStorage.EncodeHex(identbuf, IdentBufferLen));
682 fprintf(stream, " %22s = %s\n", "OperationalPattern", OperationalPattern.EncodeString(identbuf, IdentBufferLen));
683 fprintf(stream, " %22s:\n", "EssenceContainers"); EssenceContainers.Dump(stream);
684 fprintf(stream, " %22s:\n", "DMSchemes"); DMSchemes.Dump(stream);
687 //------------------------------------------------------------------------------------------
690 ASDCP::MXF::OP1aHeader::OP1aHeader(const Dictionary*& d) : Partition(d), m_Dict(d), m_Primer(d), m_Preface(0) {}
691 ASDCP::MXF::OP1aHeader::~OP1aHeader() {}
695 ASDCP::MXF::OP1aHeader::InitFromFile(const Kumu::FileReader& Reader)
697 Result_t result = Partition::InitFromFile(Reader);
699 if ( ASDCP_FAILURE(result) )
702 if ( m_Dict == &DefaultCompositeDict() )
704 // select more explicit dictionary if one is available
705 if ( OperationalPattern.ExactMatch(MXFInterop_OPAtom_Entry().ul) )
707 m_Dict = &DefaultInteropDict();
709 else if ( OperationalPattern.ExactMatch(SMPTE_390_OPAtom_Entry().ul) )
711 m_Dict = &DefaultSMPTEDict();
715 // slurp up the remainder of the header
716 if ( HeaderByteCount < 1024 )
718 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %qu\n", HeaderByteCount);
720 else if (HeaderByteCount > ( 4 * Kumu::Megabyte ) )
722 DefaultLogSink().Warn("Improbably huge HeaderByteCount value: %qu\n", HeaderByteCount);
725 result = m_HeaderData.Capacity(Kumu::xmin(4*Kumu::Megabyte, static_cast<ui32_t>(HeaderByteCount)));
727 if ( ASDCP_SUCCESS(result) )
730 result = Reader.Read(m_HeaderData.Data(), m_HeaderData.Capacity(), &read_count);
732 if ( ASDCP_FAILURE(result) )
734 DefaultLogSink().Error("OP1aHeader::InitFromFile, Read failed\n");
738 if ( read_count != m_HeaderData.Capacity() )
740 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %u, got %u\n",
741 m_HeaderData.Capacity(), read_count);
742 return RESULT_KLV_CODING;
746 if ( ASDCP_SUCCESS(result) )
747 result = InitFromBuffer(m_HeaderData.RoData(), m_HeaderData.Capacity());
754 ASDCP::MXF::OP1aHeader::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
756 Result_t result = KLVPacket::InitFromBuffer(p, l);
758 if ( ASDCP_SUCCESS(result) )
759 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
761 if ( ASDCP_SUCCESS(result) )
763 ui32_t pp_len = KLVPacket::PacketLength();
764 result = InitFromBuffer(p + pp_len, l - pp_len);
772 ASDCP::MXF::OP1aHeader::InitFromBuffer(const byte_t* p, ui32_t l)
775 Result_t result = RESULT_OK;
776 const byte_t* end_p = p + l;
778 while ( ASDCP_SUCCESS(result) && p < end_p )
780 // parse the packets and index them by uid, discard KLVFill items
781 InterchangeObject* object = CreateObject(m_Dict, p);
784 object->m_Lookup = &m_Primer;
785 result = object->InitFromBuffer(p, end_p - p);
786 const byte_t* redo_p = p;
787 p += object->PacketLength();
788 // hexdump(p, object->PacketLength());
790 if ( ASDCP_SUCCESS(result) )
792 if ( object->IsA(m_Dict->ul(MDD_KLVFill)) )
798 DefaultLogSink().Error("Fill item short read: %d.\n", p - end_p);
801 else if ( object->IsA(m_Dict->ul(MDD_Primer)) ) // TODO: only one primer should be found
804 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
808 m_PacketList->AddPacket(object); // takes ownership
810 if ( object->IsA(m_Dict->ul(MDD_Preface)) && m_Preface == 0 )
811 m_Preface = (Preface*)object;
816 DefaultLogSink().Error("Error initializing packet\n");
825 ASDCP::MXF::OP1aHeader::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
827 return m_PacketList->GetMDObjectByID(ObjectID, Object);
832 ASDCP::MXF::OP1aHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
834 InterchangeObject* TmpObject;
839 return m_PacketList->GetMDObjectByType(ObjectID, Object);
844 ASDCP::MXF::OP1aHeader::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
846 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
850 ASDCP::MXF::Identification*
851 ASDCP::MXF::OP1aHeader::GetIdentification()
853 InterchangeObject* Object;
855 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
856 return (Identification*)Object;
862 ASDCP::MXF::SourcePackage*
863 ASDCP::MXF::OP1aHeader::GetSourcePackage()
865 InterchangeObject* Object;
867 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
868 return (SourcePackage*)Object;
875 ASDCP::MXF::OP1aHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize)
878 if ( m_Preface == 0 )
881 if ( HeaderSize < 4096 )
883 DefaultLogSink().Error("HeaderSize %u is too small. Must be >= 4096\n", HeaderSize);
887 ASDCP::FrameBuffer HeaderBuffer;
888 HeaderByteCount = HeaderSize - ArchiveSize();
889 assert (HeaderByteCount <= 0xFFFFFFFFL);
890 Result_t result = HeaderBuffer.Capacity((ui32_t) HeaderByteCount);
891 m_Preface->m_Lookup = &m_Primer;
893 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
894 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
896 InterchangeObject* object = *pl_i;
897 object->m_Lookup = &m_Primer;
899 ASDCP::FrameBuffer WriteWrapper;
900 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
901 HeaderBuffer.Capacity() - HeaderBuffer.Size());
902 result = object->WriteToBuffer(WriteWrapper);
903 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
906 if ( ASDCP_SUCCESS(result) )
908 UL TmpUL(m_Dict->ul(MDD_ClosedCompleteHeader));
909 result = Partition::WriteToFile(Writer, TmpUL);
912 if ( ASDCP_SUCCESS(result) )
913 result = m_Primer.WriteToFile(Writer);
915 if ( ASDCP_SUCCESS(result) )
918 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
919 assert(write_count == HeaderBuffer.Size());
923 if ( ASDCP_SUCCESS(result) )
925 Kumu::fpos_t pos = Writer.Tell();
927 if ( pos > (Kumu::fpos_t)HeaderByteCount )
929 char intbuf[IntBufferLen];
930 DefaultLogSink().Error("Header size %s exceeds specified value %u\n",
936 ASDCP::FrameBuffer NilBuf;
937 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
939 if ( klv_fill_length < kl_length )
941 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
945 klv_fill_length -= kl_length;
946 result = WriteKLToFile(Writer, m_Dict->ul(MDD_KLVFill), klv_fill_length);
948 if ( ASDCP_SUCCESS(result) )
949 result = NilBuf.Capacity(klv_fill_length);
951 if ( ASDCP_SUCCESS(result) )
953 memset(NilBuf.Data(), 0, klv_fill_length);
955 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
956 assert(write_count == klv_fill_length);
965 ASDCP::MXF::OP1aHeader::Dump(FILE* stream)
970 Partition::Dump(stream);
971 m_Primer.Dump(stream);
973 if ( m_Preface == 0 )
974 fputs("No Preface loaded\n", stream);
976 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
977 for ( ; i != m_PacketList->m_List.end(); i++ )
981 //------------------------------------------------------------------------------------------
984 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter(const Dictionary*& d) :
985 Partition(d), m_Dict(d),
986 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
987 m_ECOffset(0), m_Lookup(0)
993 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
997 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
999 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
1001 // slurp up the remainder of the footer
1002 ui32_t read_count = 0;
1004 if ( ASDCP_SUCCESS(result) && IndexByteCount > 0 )
1006 assert (IndexByteCount <= 0xFFFFFFFFL);
1007 // At this point, m_FooterData may not have been initialized
1008 // so it's capacity is zero and data pointer is NULL
1009 // However, if IndexByteCount is zero then the capacity
1010 // doesn't change and the data pointer is not set.
1011 result = m_FooterData.Capacity((ui32_t) IndexByteCount);
1013 if ( ASDCP_SUCCESS(result) )
1014 result = Reader.Read(m_FooterData.Data(), m_FooterData.Capacity(), &read_count);
1016 if ( ASDCP_SUCCESS(result) && read_count != m_FooterData.Capacity() )
1018 DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
1019 read_count, m_FooterData.Capacity());
1022 else if( ASDCP_SUCCESS(result) && !m_FooterData.Data() )
1024 DefaultLogSink().Error( "Buffer for footer partition not created: IndexByteCount = %u\n",
1029 if ( ASDCP_SUCCESS(result) )
1030 result = InitFromBuffer(m_FooterData.RoData(), m_FooterData.Capacity());
1038 ASDCP::MXF::OPAtomIndexFooter::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
1040 Result_t result = KLVPacket::InitFromBuffer(p, l);
1042 if ( ASDCP_SUCCESS(result) )
1043 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
1045 if ( ASDCP_SUCCESS(result) )
1047 ui32_t pp_len = KLVPacket::PacketLength();
1048 result = InitFromBuffer(p + pp_len, l - pp_len);
1056 ASDCP::MXF::OPAtomIndexFooter::InitFromBuffer(const byte_t* p, ui32_t l)
1058 Result_t result = RESULT_OK;
1059 const byte_t* end_p = p + l;
1061 while ( ASDCP_SUCCESS(result) && p < end_p )
1063 // parse the packets and index them by uid, discard KLVFill items
1064 InterchangeObject* object = CreateObject(m_Dict, p);
1067 object->m_Lookup = m_Lookup;
1068 result = object->InitFromBuffer(p, end_p - p);
1069 p += object->PacketLength();
1071 if ( ASDCP_SUCCESS(result) )
1073 m_PacketList->AddPacket(object); // takes ownership
1077 DefaultLogSink().Error("Error initializing packet\n");
1082 if ( ASDCP_FAILURE(result) )
1083 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
1090 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration)
1093 ASDCP::FrameBuffer FooterBuffer;
1094 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
1095 Result_t result = FooterBuffer.Capacity(footer_size);
1096 ui32_t iseg_count = 0;
1098 if ( m_CurrentSegment != 0 )
1100 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1101 m_CurrentSegment = 0;
1104 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
1105 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
1107 IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*pl_i);
1112 if ( m_BytesPerEditUnit != 0 )
1114 if ( iseg_count != 1 )
1115 return RESULT_STATE;
1117 segment->IndexDuration = duration;
1121 InterchangeObject* object = *pl_i;
1122 object->m_Lookup = m_Lookup;
1124 ASDCP::FrameBuffer WriteWrapper;
1125 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
1126 FooterBuffer.Capacity() - FooterBuffer.Size());
1127 result = object->WriteToBuffer(WriteWrapper);
1128 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
1131 if ( ASDCP_SUCCESS(result) )
1133 IndexByteCount = FooterBuffer.Size();
1134 UL FooterUL(m_Dict->ul(MDD_CompleteFooter));
1135 result = Partition::WriteToFile(Writer, FooterUL);
1138 if ( ASDCP_SUCCESS(result) )
1140 ui32_t write_count = 0;
1141 result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
1142 assert(write_count == FooterBuffer.Size());
1150 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1155 Partition::Dump(stream);
1157 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1158 for ( ; i != m_PacketList->m_List.end(); i++ )
1163 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
1165 return m_PacketList->GetMDObjectByID(ObjectID, Object);
1170 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
1172 InterchangeObject* TmpObject;
1175 Object = &TmpObject;
1177 return m_PacketList->GetMDObjectByType(ObjectID, Object);
1182 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
1184 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
1189 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const
1191 std::list<InterchangeObject*>::iterator li;
1192 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1194 IndexTableSegment *segment = dynamic_cast<IndexTableSegment*>(*li);
1198 ui64_t start_pos = segment->IndexStartPosition;
1200 if ( segment->EditUnitByteCount > 0 )
1202 if ( m_PacketList->m_List.size() > 1 )
1203 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1205 if ( ! segment->IndexEntryArray.empty() )
1206 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1208 Entry.StreamOffset = (ui64_t)frame_num * segment->EditUnitByteCount;
1211 else if ( (ui64_t)frame_num >= start_pos
1212 && (ui64_t)frame_num < (start_pos + segment->IndexDuration) )
1214 ui64_t tmp = frame_num - start_pos;
1215 assert(tmp <= 0xFFFFFFFFL);
1216 Entry = segment->IndexEntryArray[(ui32_t) tmp];
1227 ASDCP::MXF::OPAtomIndexFooter::SetDeltaParams(const IndexTableSegment::DeltaEntry& delta)
1229 m_DefaultDeltaEntry = delta;
1234 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1238 m_BytesPerEditUnit = size;
1241 IndexTableSegment* Index = new IndexTableSegment(m_Dict);
1242 AddChildObject(Index);
1243 Index->EditUnitByteCount = m_BytesPerEditUnit;
1244 Index->IndexEditRate = Rate;
1249 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset)
1253 m_BytesPerEditUnit = 0;
1255 m_ECOffset = offset;
1260 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1262 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1264 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1268 // do we have an available segment?
1269 if ( m_CurrentSegment == 0 )
1270 { // no, set up a new segment
1271 m_CurrentSegment = new IndexTableSegment(m_Dict);
1272 assert(m_CurrentSegment);
1273 AddChildObject(m_CurrentSegment);
1274 m_CurrentSegment->DeltaEntryArray.push_back(m_DefaultDeltaEntry);
1275 m_CurrentSegment->IndexEditRate = m_EditRate;
1276 m_CurrentSegment->IndexStartPosition = 0;
1278 else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
1279 { // no, this one is full, start another
1280 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1281 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1283 m_CurrentSegment = new IndexTableSegment(m_Dict);
1284 assert(m_CurrentSegment);
1285 AddChildObject(m_CurrentSegment);
1286 m_CurrentSegment->DeltaEntryArray.push_back(m_DefaultDeltaEntry);
1287 m_CurrentSegment->IndexEditRate = m_EditRate;
1288 m_CurrentSegment->IndexStartPosition = StartPosition;
1291 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1294 //------------------------------------------------------------------------------------------
1299 ASDCP::MXF::InterchangeObject::Copy(const InterchangeObject& rhs)
1302 InstanceUID = rhs.InstanceUID;
1303 GenerationUID = rhs.GenerationUID;
1308 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1310 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1311 if ( ASDCP_SUCCESS(result) )
1312 result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(GenerationInterchangeObject, GenerationUID));
1318 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1320 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1321 if ( ASDCP_SUCCESS(result) )
1322 result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(GenerationInterchangeObject, GenerationUID));
1328 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1331 Result_t result = RESULT_FALSE;
1333 if ( m_UL.HasValue() )
1335 result = KLVPacket::InitFromBuffer(p, l, m_UL);
1337 if ( ASDCP_SUCCESS(result) )
1339 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1340 result = InitFromTLVSet(MemRDR);
1345 result = KLVPacket::InitFromBuffer(p, l);
1353 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1355 if ( ! m_UL.HasValue() )
1356 return RESULT_STATE;
1358 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1359 Result_t result = WriteToTLVSet(MemWRT);
1361 if ( ASDCP_SUCCESS(result) )
1363 ui32_t packet_length = MemWRT.Length();
1364 result = WriteKLToBuffer(Buffer, packet_length);
1366 if ( ASDCP_SUCCESS(result) )
1367 Buffer.Size(Buffer.Size() + packet_length);
1375 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1377 char identbuf[IdentBufferLen];
1379 fputc('\n', stream);
1380 KLVPacket::Dump(stream, *m_Dict, false);
1381 fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen));
1383 if ( ! GenerationUID.empty() )
1384 fprintf(stream, " GenerationUID = %s\n", GenerationUID.get().EncodeHex(identbuf, IdentBufferLen));
1389 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1391 if ( m_KLLength == 0 || m_KeyStart == 0 )
1394 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
1398 //------------------------------------------------------------------------------------------
1401 typedef std::map<ASDCP::UL, ASDCP::MXF::MXFObjectFactory_t>FactoryMap_t;
1402 typedef FactoryMap_t::iterator FLi_t;
1405 class FactoryList : public FactoryMap_t
1414 Kumu::AutoMutex BlockLock(m_Lock);
1418 FLi_t Find(const byte_t* label) {
1419 Kumu::AutoMutex BlockLock(m_Lock);
1424 Kumu::AutoMutex BlockLock(m_Lock);
1428 void Insert(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) {
1429 Kumu::AutoMutex BlockLock(m_Lock);
1430 insert(FactoryList::value_type(label, factory));
1435 static FactoryList s_FactoryList;
1436 static Kumu::Mutex s_InitLock;
1437 static bool s_TypesInit = false;
1442 ASDCP::MXF::SetObjectFactory(const ASDCP::UL& label, ASDCP::MXF::MXFObjectFactory_t factory)
1444 s_FactoryList.Insert(label, factory);
1448 ASDCP::MXF::InterchangeObject*
1449 ASDCP::MXF::CreateObject(const Dictionary*& Dict, const UL& label)
1451 if ( ! s_TypesInit )
1453 Kumu::AutoMutex BlockLock(s_InitLock);
1455 if ( ! s_TypesInit )
1457 MXF::Metadata_InitTypes(Dict);
1462 FLi_t i = s_FactoryList.find(label.Value());
1464 if ( i == s_FactoryList.end() )
1465 return new InterchangeObject(Dict);
1467 return i->second(Dict);
1471 //------------------------------------------------------------------------------------------
1475 ASDCP::MXF::decode_mca_string(const std::string& s, const mca_label_map_t& labels, const Dictionary*& dict, const std::string& language,
1476 InterchangeObject_list_t& descriptor_list, ui32_t& channel_count)
1478 std::string symbol_buf;
1480 ASDCP::MXF::SoundfieldGroupLabelSubDescriptor *current_soundfield = 0;
1481 std::string::const_iterator i;
1483 for ( i = s.begin(); i != s.end(); ++i )
1487 if ( current_soundfield != 0 )
1489 DefaultLogSink().Error("Encountered '(', already processing a soundfield group.\n");
1493 if ( symbol_buf.empty() )
1495 DefaultLogSink().Error("Encountered '(', without leading soundfield group symbol.\n");
1499 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1501 if ( i == labels.end() )
1503 DefaultLogSink().Error("Unknown symbol: '%s'\n", symbol_buf.c_str());
1507 if ( i->second.Value()[10] != 2 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1509 DefaultLogSink().Error("Not a soundfield group symbol: '%s'\n", symbol_buf.c_str());
1513 current_soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(dict);
1515 GenRandomValue(current_soundfield->InstanceUID);
1516 GenRandomValue(current_soundfield->MCALinkID);
1517 current_soundfield->MCATagSymbol = "sg" + i->first;
1518 current_soundfield->MCATagName = i->first;
1519 current_soundfield->RFC5646SpokenLanguage = language;
1520 current_soundfield->MCALabelDictionaryID = i->second;
1521 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(current_soundfield));
1524 else if ( *i == ')' )
1526 if ( current_soundfield == 0 )
1528 DefaultLogSink().Error("Encountered ')', not currently processing a soundfield group.\n");
1532 if ( symbol_buf.empty() )
1534 DefaultLogSink().Error("Soundfield group description contains no channels.\n");
1538 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1540 if ( i == labels.end() )
1542 DefaultLogSink().Error("Unknown symbol: '%s'\n", symbol_buf.c_str());
1546 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1547 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dict);
1549 GenRandomValue(channel_descr->InstanceUID);
1550 assert(current_soundfield);
1551 channel_descr->SoundfieldGroupLinkID = current_soundfield->MCALinkID;
1552 channel_descr->MCAChannelID = channel_count++;
1553 channel_descr->MCATagSymbol = "ch" + i->first;
1554 channel_descr->MCATagName = i->first;
1555 channel_descr->RFC5646SpokenLanguage = language;
1556 channel_descr->MCALabelDictionaryID = i->second;
1557 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1559 current_soundfield = 0;
1561 else if ( *i == ',' )
1563 if ( ! symbol_buf.empty() )
1565 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1567 if ( i == labels.end() )
1569 DefaultLogSink().Error("Unknown symbol: '%s'\n", symbol_buf.c_str());
1573 if ( i->second.Value()[10] != 1 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1575 DefaultLogSink().Error("Not a channel symbol: '%s'\n", symbol_buf.c_str());
1579 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1580 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dict);
1582 GenRandomValue(channel_descr->InstanceUID);
1584 if ( current_soundfield != 0 )
1586 channel_descr->SoundfieldGroupLinkID = current_soundfield->MCALinkID;
1589 channel_descr->MCAChannelID = channel_count++;
1590 channel_descr->MCATagSymbol = "ch" + i->first;
1591 channel_descr->MCATagName = i->first;
1592 channel_descr->RFC5646SpokenLanguage = language;
1593 channel_descr->MCALabelDictionaryID = i->second;
1594 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1598 else if ( isalnum(*i) )
1602 else if ( ! isspace(*i) )
1604 DefaultLogSink().Error("Unexpected character '%c'.\n", *i);
1609 if ( ! symbol_buf.empty() )
1611 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1613 if ( i == labels.end() )
1615 DefaultLogSink().Error("Unknown symbol: '%s'\n", symbol_buf.c_str());
1619 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1620 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dict);
1622 GenRandomValue(channel_descr->InstanceUID);
1624 if ( current_soundfield != 0 )
1626 channel_descr->SoundfieldGroupLinkID = current_soundfield->MCALinkID;
1629 channel_descr->MCAChannelID = channel_count++;
1630 channel_descr->MCATagSymbol = "ch" + i->first;
1631 channel_descr->MCATagName = i->first;
1632 channel_descr->RFC5646SpokenLanguage = language;
1633 channel_descr->MCALabelDictionaryID = i->second;
1634 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1641 ASDCP::MXF::ASDCP_MCAConfigParser::ASDCP_MCAConfigParser(const Dictionary*& d) : m_Dict(d), m_ChannelCount(0)
1643 m_LabelMap.insert(mca_label_map_t::value_type("L", m_Dict->ul(MDD_DCAudioChannel_L)));
1644 m_LabelMap.insert(mca_label_map_t::value_type("R", m_Dict->ul(MDD_DCAudioChannel_R)));
1645 m_LabelMap.insert(mca_label_map_t::value_type("C", m_Dict->ul(MDD_DCAudioChannel_C)));
1646 m_LabelMap.insert(mca_label_map_t::value_type("LFE", m_Dict->ul(MDD_DCAudioChannel_LFE)));
1647 m_LabelMap.insert(mca_label_map_t::value_type("Ls", m_Dict->ul(MDD_DCAudioChannel_Ls)));
1648 m_LabelMap.insert(mca_label_map_t::value_type("Rs", m_Dict->ul(MDD_DCAudioChannel_Rs)));
1649 m_LabelMap.insert(mca_label_map_t::value_type("Lss", m_Dict->ul(MDD_DCAudioChannel_Lss)));
1650 m_LabelMap.insert(mca_label_map_t::value_type("Rss", m_Dict->ul(MDD_DCAudioChannel_Rss)));
1651 m_LabelMap.insert(mca_label_map_t::value_type("Lrs", m_Dict->ul(MDD_DCAudioChannel_Lrs)));
1652 m_LabelMap.insert(mca_label_map_t::value_type("Rrs", m_Dict->ul(MDD_DCAudioChannel_Rrs)));
1653 m_LabelMap.insert(mca_label_map_t::value_type("Lc", m_Dict->ul(MDD_DCAudioChannel_Lc)));
1654 m_LabelMap.insert(mca_label_map_t::value_type("Rc", m_Dict->ul(MDD_DCAudioChannel_Rc)));
1655 m_LabelMap.insert(mca_label_map_t::value_type("Cs", m_Dict->ul(MDD_DCAudioChannel_Cs)));
1656 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_DCAudioChannel_HI)));
1657 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_DCAudioChannel_VIN)));
1658 m_LabelMap.insert(mca_label_map_t::value_type("51", m_Dict->ul(MDD_DCAudioSoundfield_51)));
1659 m_LabelMap.insert(mca_label_map_t::value_type("71", m_Dict->ul(MDD_DCAudioSoundfield_71)));
1660 m_LabelMap.insert(mca_label_map_t::value_type("SDS", m_Dict->ul(MDD_DCAudioSoundfield_SDS)));
1661 m_LabelMap.insert(mca_label_map_t::value_type("61", m_Dict->ul(MDD_DCAudioSoundfield_61)));
1662 m_LabelMap.insert(mca_label_map_t::value_type("M", m_Dict->ul(MDD_DCAudioSoundfield_M)));
1667 ASDCP::MXF::ASDCP_MCAConfigParser::ChannelCount() const
1669 return m_ChannelCount;
1672 // 51(L,R,C,LFE,Ls,Rs),HI,VIN
1674 ASDCP::MXF::ASDCP_MCAConfigParser::DecodeString(const std::string& s, const std::string& language)
1676 return decode_mca_string(s, m_LabelMap, m_Dict, language, *this, m_ChannelCount);
1681 ASDCP::MXF::AS02_MCAConfigParser::AS02_MCAConfigParser(const Dictionary*& d) : ASDCP::MXF::ASDCP_MCAConfigParser(d)
1683 m_LabelMap.insert(mca_label_map_t::value_type("M1", m_Dict->ul(MDD_IMFAudioChannel_M1)));
1684 m_LabelMap.insert(mca_label_map_t::value_type("M2", m_Dict->ul(MDD_IMFAudioChannel_M2)));
1685 m_LabelMap.insert(mca_label_map_t::value_type("Lt", m_Dict->ul(MDD_IMFAudioChannel_Lt)));
1686 m_LabelMap.insert(mca_label_map_t::value_type("Rt", m_Dict->ul(MDD_IMFAudioChannel_Rt)));
1687 m_LabelMap.insert(mca_label_map_t::value_type("Lst", m_Dict->ul(MDD_IMFAudioChannel_Lst)));
1688 m_LabelMap.insert(mca_label_map_t::value_type("Rst", m_Dict->ul(MDD_IMFAudioChannel_Rst)));
1689 m_LabelMap.insert(mca_label_map_t::value_type("S", m_Dict->ul(MDD_IMFAudioChannel_S)));
1690 m_LabelMap.insert(mca_label_map_t::value_type("ST", m_Dict->ul(MDD_IMFAudioSoundfield_ST)));
1691 m_LabelMap.insert(mca_label_map_t::value_type("DM", m_Dict->ul(MDD_IMFAudioSoundfield_DM)));
1692 m_LabelMap.insert(mca_label_map_t::value_type("DNS", m_Dict->ul(MDD_IMFAudioSoundfield_DNS)));
1693 m_LabelMap.insert(mca_label_map_t::value_type("30", m_Dict->ul(MDD_IMFAudioSoundfield_30)));
1694 m_LabelMap.insert(mca_label_map_t::value_type("40", m_Dict->ul(MDD_IMFAudioSoundfield_40)));
1695 m_LabelMap.insert(mca_label_map_t::value_type("50", m_Dict->ul(MDD_IMFAudioSoundfield_50)));
1696 m_LabelMap.insert(mca_label_map_t::value_type("60", m_Dict->ul(MDD_IMFAudioSoundfield_60)));
1697 m_LabelMap.insert(mca_label_map_t::value_type("70", m_Dict->ul(MDD_IMFAudioSoundfield_70)));
1698 m_LabelMap.insert(mca_label_map_t::value_type("LtRt", m_Dict->ul(MDD_IMFAudioSoundfield_LtRt)));
1699 m_LabelMap.insert(mca_label_map_t::value_type("51Ex", m_Dict->ul(MDD_IMFAudioSoundfield_51Ex)));
1700 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_IMFAudioSoundfield_HI)));
1701 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_IMFAudioSoundfield_VIN)));