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 = 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 )
717 DefaultLogSink().Warn("Improbably small HeaderByteCount value: %u\n", HeaderByteCount);
719 assert (HeaderByteCount <= 0xFFFFFFFFL);
720 result = m_HeaderData.Capacity((ui32_t)HeaderByteCount);
722 if ( ASDCP_SUCCESS(result) )
725 result = Reader.Read(m_HeaderData.Data(), m_HeaderData.Capacity(), &read_count);
727 if ( ASDCP_FAILURE(result) )
729 DefaultLogSink().Error("OP1aHeader::InitFromFile, Read failed\n");
733 if ( read_count != m_HeaderData.Capacity() )
735 DefaultLogSink().Error("Short read of OP-Atom header metadata; wanted %u, got %u\n",
736 m_HeaderData.Capacity(), read_count);
737 return RESULT_KLV_CODING;
741 if ( ASDCP_SUCCESS(result) )
742 result = InitFromBuffer(m_HeaderData.RoData(), m_HeaderData.Capacity());
749 ASDCP::MXF::OP1aHeader::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
751 Result_t result = KLVPacket::InitFromBuffer(p, l);
753 if ( ASDCP_SUCCESS(result) )
754 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
756 if ( ASDCP_SUCCESS(result) )
758 ui32_t pp_len = KLVPacket::PacketLength();
759 result = InitFromBuffer(p + pp_len, l - pp_len);
767 ASDCP::MXF::OP1aHeader::InitFromBuffer(const byte_t* p, ui32_t l)
770 Result_t result = RESULT_OK;
771 const byte_t* end_p = p + l;
773 while ( ASDCP_SUCCESS(result) && p < end_p )
775 // parse the packets and index them by uid, discard KLVFill items
776 InterchangeObject* object = CreateObject(m_Dict, p);
779 object->m_Lookup = &m_Primer;
780 result = object->InitFromBuffer(p, end_p - p);
781 const byte_t* redo_p = p;
782 p += object->PacketLength();
783 // hexdump(p, object->PacketLength());
785 if ( ASDCP_SUCCESS(result) )
787 if ( object->IsA(m_Dict->ul(MDD_KLVFill)) )
793 DefaultLogSink().Error("Fill item short read: %d.\n", p - end_p);
796 else if ( object->IsA(m_Dict->ul(MDD_Primer)) ) // TODO: only one primer should be found
799 result = m_Primer.InitFromBuffer(redo_p, end_p - redo_p);
803 m_PacketList->AddPacket(object); // takes ownership
805 if ( object->IsA(m_Dict->ul(MDD_Preface)) && m_Preface == 0 )
806 m_Preface = (Preface*)object;
811 DefaultLogSink().Error("Error initializing packet\n");
820 ASDCP::MXF::OP1aHeader::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
822 return m_PacketList->GetMDObjectByID(ObjectID, Object);
827 ASDCP::MXF::OP1aHeader::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
829 InterchangeObject* TmpObject;
834 return m_PacketList->GetMDObjectByType(ObjectID, Object);
839 ASDCP::MXF::OP1aHeader::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
841 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
845 ASDCP::MXF::Identification*
846 ASDCP::MXF::OP1aHeader::GetIdentification()
848 InterchangeObject* Object;
850 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object)) )
851 return (Identification*)Object;
857 ASDCP::MXF::SourcePackage*
858 ASDCP::MXF::OP1aHeader::GetSourcePackage()
860 InterchangeObject* Object;
862 if ( ASDCP_SUCCESS(GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object)) )
863 return (SourcePackage*)Object;
870 ASDCP::MXF::OP1aHeader::WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderSize)
873 if ( m_Preface == 0 )
876 if ( HeaderSize < 4096 )
878 DefaultLogSink().Error("HeaderSize %u is too small. Must be >= 4096\n", HeaderSize);
882 ASDCP::FrameBuffer HeaderBuffer;
883 HeaderByteCount = HeaderSize - ArchiveSize();
884 assert (HeaderByteCount <= 0xFFFFFFFFL);
885 Result_t result = HeaderBuffer.Capacity((ui32_t) HeaderByteCount);
886 m_Preface->m_Lookup = &m_Primer;
888 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
889 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
891 InterchangeObject* object = *pl_i;
892 object->m_Lookup = &m_Primer;
894 ASDCP::FrameBuffer WriteWrapper;
895 WriteWrapper.SetData(HeaderBuffer.Data() + HeaderBuffer.Size(),
896 HeaderBuffer.Capacity() - HeaderBuffer.Size());
897 result = object->WriteToBuffer(WriteWrapper);
898 HeaderBuffer.Size(HeaderBuffer.Size() + WriteWrapper.Size());
901 if ( ASDCP_SUCCESS(result) )
903 UL TmpUL(m_Dict->ul(MDD_ClosedCompleteHeader));
904 result = Partition::WriteToFile(Writer, TmpUL);
907 if ( ASDCP_SUCCESS(result) )
908 result = m_Primer.WriteToFile(Writer);
910 if ( ASDCP_SUCCESS(result) )
913 Writer.Write(HeaderBuffer.RoData(), HeaderBuffer.Size(), &write_count);
914 assert(write_count == HeaderBuffer.Size());
918 if ( ASDCP_SUCCESS(result) )
920 Kumu::fpos_t pos = Writer.Tell();
922 if ( pos > (Kumu::fpos_t)HeaderByteCount )
924 char intbuf[IntBufferLen];
925 DefaultLogSink().Error("Header size %s exceeds specified value %u\n",
931 ASDCP::FrameBuffer NilBuf;
932 ui32_t klv_fill_length = HeaderSize - (ui32_t)pos;
934 if ( klv_fill_length < kl_length )
936 DefaultLogSink().Error("Remaining region too small for KLV Fill header\n");
940 klv_fill_length -= kl_length;
941 result = WriteKLToFile(Writer, m_Dict->ul(MDD_KLVFill), klv_fill_length);
943 if ( ASDCP_SUCCESS(result) )
944 result = NilBuf.Capacity(klv_fill_length);
946 if ( ASDCP_SUCCESS(result) )
948 memset(NilBuf.Data(), 0, klv_fill_length);
950 Writer.Write(NilBuf.RoData(), klv_fill_length, &write_count);
951 assert(write_count == klv_fill_length);
960 ASDCP::MXF::OP1aHeader::Dump(FILE* stream)
965 Partition::Dump(stream);
966 m_Primer.Dump(stream);
968 if ( m_Preface == 0 )
969 fputs("No Preface loaded\n", stream);
971 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
972 for ( ; i != m_PacketList->m_List.end(); i++ )
976 //------------------------------------------------------------------------------------------
979 ASDCP::MXF::OPAtomIndexFooter::OPAtomIndexFooter(const Dictionary*& d) :
980 Partition(d), m_Dict(d),
981 m_CurrentSegment(0), m_BytesPerEditUnit(0), m_BodySID(0),
982 m_ECOffset(0), m_Lookup(0)
988 ASDCP::MXF::OPAtomIndexFooter::~OPAtomIndexFooter() {}
992 ASDCP::MXF::OPAtomIndexFooter::InitFromFile(const Kumu::FileReader& Reader)
994 Result_t result = Partition::InitFromFile(Reader); // test UL and OP
996 // slurp up the remainder of the footer
997 ui32_t read_count = 0;
999 if ( ASDCP_SUCCESS(result) && IndexByteCount > 0 )
1001 assert (IndexByteCount <= 0xFFFFFFFFL);
1002 // At this point, m_FooterData may not have been initialized
1003 // so it's capacity is zero and data pointer is NULL
1004 // However, if IndexByteCount is zero then the capacity
1005 // doesn't change and the data pointer is not set.
1006 result = m_FooterData.Capacity((ui32_t) IndexByteCount);
1008 if ( ASDCP_SUCCESS(result) )
1009 result = Reader.Read(m_FooterData.Data(), m_FooterData.Capacity(), &read_count);
1011 if ( ASDCP_SUCCESS(result) && read_count != m_FooterData.Capacity() )
1013 DefaultLogSink().Error("Short read of footer partition: got %u, expecting %u\n",
1014 read_count, m_FooterData.Capacity());
1017 else if( ASDCP_SUCCESS(result) && !m_FooterData.Data() )
1019 DefaultLogSink().Error( "Buffer for footer partition not created: IndexByteCount = %u\n",
1024 if ( ASDCP_SUCCESS(result) )
1025 result = InitFromBuffer(m_FooterData.RoData(), m_FooterData.Capacity());
1033 ASDCP::MXF::OPAtomIndexFooter::InitFromPartitionBuffer(const byte_t* p, ui32_t l)
1035 Result_t result = KLVPacket::InitFromBuffer(p, l);
1037 if ( ASDCP_SUCCESS(result) )
1038 result = Partition::InitFromBuffer(m_ValueStart, m_ValueLength); // test UL and OP
1040 if ( ASDCP_SUCCESS(result) )
1042 ui32_t pp_len = KLVPacket::PacketLength();
1043 result = InitFromBuffer(p + pp_len, l - pp_len);
1051 ASDCP::MXF::OPAtomIndexFooter::InitFromBuffer(const byte_t* p, ui32_t l)
1053 Result_t result = RESULT_OK;
1054 const byte_t* end_p = p + l;
1056 while ( ASDCP_SUCCESS(result) && p < end_p )
1058 // parse the packets and index them by uid, discard KLVFill items
1059 InterchangeObject* object = CreateObject(m_Dict, p);
1062 object->m_Lookup = m_Lookup;
1063 result = object->InitFromBuffer(p, end_p - p);
1064 p += object->PacketLength();
1066 if ( ASDCP_SUCCESS(result) )
1068 m_PacketList->AddPacket(object); // takes ownership
1072 DefaultLogSink().Error("Error initializing packet\n");
1077 if ( ASDCP_FAILURE(result) )
1078 DefaultLogSink().Error("Failed to initialize OPAtomIndexFooter\n");
1085 ASDCP::MXF::OPAtomIndexFooter::WriteToFile(Kumu::FileWriter& Writer, ui64_t duration)
1088 ASDCP::FrameBuffer FooterBuffer;
1089 ui32_t footer_size = m_PacketList->m_List.size() * MaxIndexSegmentSize; // segment-count * max-segment-size
1090 Result_t result = FooterBuffer.Capacity(footer_size);
1091 ui32_t iseg_count = 0;
1093 if ( m_CurrentSegment != 0 )
1095 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1096 m_CurrentSegment = 0;
1099 std::list<InterchangeObject*>::iterator pl_i = m_PacketList->m_List.begin();
1100 for ( ; pl_i != m_PacketList->m_List.end() && ASDCP_SUCCESS(result); pl_i++ )
1102 if ( (*pl_i)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1105 IndexTableSegment* Segment = (IndexTableSegment*)(*pl_i);
1107 if ( m_BytesPerEditUnit != 0 )
1109 if ( iseg_count != 1 )
1110 return RESULT_STATE;
1112 Segment->IndexDuration = duration;
1116 InterchangeObject* object = *pl_i;
1117 object->m_Lookup = m_Lookup;
1119 ASDCP::FrameBuffer WriteWrapper;
1120 WriteWrapper.SetData(FooterBuffer.Data() + FooterBuffer.Size(),
1121 FooterBuffer.Capacity() - FooterBuffer.Size());
1122 result = object->WriteToBuffer(WriteWrapper);
1123 FooterBuffer.Size(FooterBuffer.Size() + WriteWrapper.Size());
1126 if ( ASDCP_SUCCESS(result) )
1128 IndexByteCount = FooterBuffer.Size();
1129 UL FooterUL(m_Dict->ul(MDD_CompleteFooter));
1130 result = Partition::WriteToFile(Writer, FooterUL);
1133 if ( ASDCP_SUCCESS(result) )
1135 ui32_t write_count = 0;
1136 result = Writer.Write(FooterBuffer.RoData(), FooterBuffer.Size(), &write_count);
1137 assert(write_count == FooterBuffer.Size());
1145 ASDCP::MXF::OPAtomIndexFooter::Dump(FILE* stream)
1150 Partition::Dump(stream);
1152 std::list<InterchangeObject*>::iterator i = m_PacketList->m_List.begin();
1153 for ( ; i != m_PacketList->m_List.end(); i++ )
1158 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object)
1160 return m_PacketList->GetMDObjectByID(ObjectID, Object);
1165 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object)
1167 InterchangeObject* TmpObject;
1170 Object = &TmpObject;
1172 return m_PacketList->GetMDObjectByType(ObjectID, Object);
1177 ASDCP::MXF::OPAtomIndexFooter::GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList)
1179 return m_PacketList->GetMDObjectsByType(ObjectID, ObjectList);
1184 ASDCP::MXF::OPAtomIndexFooter::Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry& Entry) const
1186 std::list<InterchangeObject*>::iterator li;
1187 for ( li = m_PacketList->m_List.begin(); li != m_PacketList->m_List.end(); li++ )
1189 if ( (*li)->IsA(OBJ_TYPE_ARGS(IndexTableSegment)) )
1191 IndexTableSegment* Segment = (IndexTableSegment*)(*li);
1192 ui64_t start_pos = Segment->IndexStartPosition;
1194 if ( Segment->EditUnitByteCount > 0 )
1196 if ( m_PacketList->m_List.size() > 1 )
1197 DefaultLogSink().Error("Unexpected multiple IndexTableSegment in CBR file\n");
1199 if ( ! Segment->IndexEntryArray.empty() )
1200 DefaultLogSink().Error("Unexpected IndexEntryArray contents in CBR file\n");
1202 Entry.StreamOffset = (ui64_t)frame_num * Segment->EditUnitByteCount;
1205 else if ( (ui64_t)frame_num >= start_pos
1206 && (ui64_t)frame_num < (start_pos + Segment->IndexDuration) )
1208 ui64_t tmp = frame_num - start_pos;
1209 assert(tmp <= 0xFFFFFFFFL);
1210 Entry = Segment->IndexEntryArray[(ui32_t) tmp];
1221 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate)
1225 m_BytesPerEditUnit = size;
1228 IndexTableSegment* Index = new IndexTableSegment(m_Dict);
1229 AddChildObject(Index);
1230 Index->EditUnitByteCount = m_BytesPerEditUnit;
1231 Index->IndexEditRate = Rate;
1236 ASDCP::MXF::OPAtomIndexFooter::SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset)
1240 m_BytesPerEditUnit = 0;
1242 m_ECOffset = offset;
1247 ASDCP::MXF::OPAtomIndexFooter::PushIndexEntry(const IndexTableSegment::IndexEntry& Entry)
1249 if ( m_BytesPerEditUnit != 0 ) // are we CBR? that's bad
1251 DefaultLogSink().Error("Call to PushIndexEntry() failed: index is CBR\n");
1255 // do we have an available segment?
1256 if ( m_CurrentSegment == 0 )
1257 { // no, set up a new segment
1258 m_CurrentSegment = new IndexTableSegment(m_Dict);
1259 assert(m_CurrentSegment);
1260 AddChildObject(m_CurrentSegment);
1261 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1262 m_CurrentSegment->IndexEditRate = m_EditRate;
1263 m_CurrentSegment->IndexStartPosition = 0;
1265 else if ( m_CurrentSegment->IndexEntryArray.size() >= CBRIndexEntriesPerSegment )
1266 { // no, this one is full, start another
1267 m_CurrentSegment->IndexDuration = m_CurrentSegment->IndexEntryArray.size();
1268 ui64_t StartPosition = m_CurrentSegment->IndexStartPosition + m_CurrentSegment->IndexDuration;
1270 m_CurrentSegment = new IndexTableSegment(m_Dict);
1271 assert(m_CurrentSegment);
1272 AddChildObject(m_CurrentSegment);
1273 m_CurrentSegment->DeltaEntryArray.push_back(IndexTableSegment::DeltaEntry());
1274 m_CurrentSegment->IndexEditRate = m_EditRate;
1275 m_CurrentSegment->IndexStartPosition = StartPosition;
1278 m_CurrentSegment->IndexEntryArray.push_back(Entry);
1281 //------------------------------------------------------------------------------------------
1286 ASDCP::MXF::InterchangeObject::Copy(const InterchangeObject& rhs)
1289 InstanceUID = rhs.InstanceUID;
1290 GenerationUID = rhs.GenerationUID;
1295 ASDCP::MXF::InterchangeObject::InitFromTLVSet(TLVReader& TLVSet)
1297 Result_t result = TLVSet.ReadObject(OBJ_READ_ARGS(InterchangeObject, InstanceUID));
1298 if ( ASDCP_SUCCESS(result) )
1299 result = TLVSet.ReadObject(OBJ_READ_ARGS_OPT(GenerationInterchangeObject, GenerationUID));
1305 ASDCP::MXF::InterchangeObject::WriteToTLVSet(TLVWriter& TLVSet)
1307 Result_t result = TLVSet.WriteObject(OBJ_WRITE_ARGS(InterchangeObject, InstanceUID));
1308 if ( ASDCP_SUCCESS(result) )
1309 result = TLVSet.WriteObject(OBJ_WRITE_ARGS_OPT(GenerationInterchangeObject, GenerationUID));
1315 ASDCP::MXF::InterchangeObject::InitFromBuffer(const byte_t* p, ui32_t l)
1318 Result_t result = RESULT_FALSE;
1320 if ( m_UL.HasValue() )
1322 result = KLVPacket::InitFromBuffer(p, l, m_UL);
1324 if ( ASDCP_SUCCESS(result) )
1326 TLVReader MemRDR(m_ValueStart, m_ValueLength, m_Lookup);
1327 result = InitFromTLVSet(MemRDR);
1332 result = KLVPacket::InitFromBuffer(p, l);
1340 ASDCP::MXF::InterchangeObject::WriteToBuffer(ASDCP::FrameBuffer& Buffer)
1342 if ( ! m_UL.HasValue() )
1343 return RESULT_STATE;
1345 TLVWriter MemWRT(Buffer.Data() + kl_length, Buffer.Capacity() - kl_length, m_Lookup);
1346 Result_t result = WriteToTLVSet(MemWRT);
1348 if ( ASDCP_SUCCESS(result) )
1350 ui32_t packet_length = MemWRT.Length();
1351 result = WriteKLToBuffer(Buffer, packet_length);
1353 if ( ASDCP_SUCCESS(result) )
1354 Buffer.Size(Buffer.Size() + packet_length);
1362 ASDCP::MXF::InterchangeObject::Dump(FILE* stream)
1364 char identbuf[IdentBufferLen];
1366 fputc('\n', stream);
1367 KLVPacket::Dump(stream, *m_Dict, false);
1368 fprintf(stream, " InstanceUID = %s\n", InstanceUID.EncodeHex(identbuf, IdentBufferLen));
1370 if ( ! GenerationUID.empty() )
1371 fprintf(stream, " GenerationUID = %s\n", GenerationUID.get().EncodeHex(identbuf, IdentBufferLen));
1376 ASDCP::MXF::InterchangeObject::IsA(const byte_t* label)
1378 if ( m_KLLength == 0 )
1381 return ( memcmp(label, m_KeyStart, SMPTE_UL_LENGTH) == 0 );
1385 //------------------------------------------------------------------------------------------
1388 typedef std::map<ASDCP::UL, ASDCP::MXF::MXFObjectFactory_t>FactoryMap_t;
1389 typedef FactoryMap_t::iterator FLi_t;
1392 class FactoryList : public FactoryMap_t
1401 Kumu::AutoMutex BlockLock(m_Lock);
1405 FLi_t Find(const byte_t* label) {
1406 Kumu::AutoMutex BlockLock(m_Lock);
1411 Kumu::AutoMutex BlockLock(m_Lock);
1415 void Insert(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory) {
1416 Kumu::AutoMutex BlockLock(m_Lock);
1417 insert(FactoryList::value_type(label, factory));
1422 static FactoryList s_FactoryList;
1423 static Kumu::Mutex s_InitLock;
1424 static bool s_TypesInit = false;
1429 ASDCP::MXF::SetObjectFactory(ASDCP::UL label, ASDCP::MXF::MXFObjectFactory_t factory)
1431 s_FactoryList.Insert(label, factory);
1435 ASDCP::MXF::InterchangeObject*
1436 ASDCP::MXF::CreateObject(const Dictionary*& Dict, const UL& label)
1438 if ( ! s_TypesInit )
1440 Kumu::AutoMutex BlockLock(s_InitLock);
1442 if ( ! s_TypesInit )
1444 MXF::Metadata_InitTypes(Dict);
1449 FLi_t i = s_FactoryList.find(label.Value());
1451 if ( i == s_FactoryList.end() )
1452 return new InterchangeObject(Dict);
1454 return i->second(Dict);
1458 //------------------------------------------------------------------------------------------
1462 ASDCP::MXF::decode_mca_string(const std::string& s, const mca_label_map_t& labels, const Dictionary& dict, const std::string& language,
1463 InterchangeObject_list_t& descriptor_list, ui32_t& channel_count)
1465 const Dictionary *dictp = &dict;
1466 std::string symbol_buf;
1468 ASDCP::MXF::SoundfieldGroupLabelSubDescriptor *current_soundfield = 0;
1469 std::string::const_iterator i;
1471 for ( i = s.begin(); i != s.end(); ++i )
1475 if ( current_soundfield != 0 )
1477 fprintf(stderr, "Encountered '(', already processing a soundfield group.\n");
1481 if ( symbol_buf.empty() )
1483 fprintf(stderr, "Encountered '(', without leading soundfield group symbol.\n");
1487 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1489 if ( i == labels.end() )
1491 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1495 if ( i->second.Value()[10] != 2 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1497 fprintf(stderr, "Not a soundfield group symbol: '%s'\n", symbol_buf.c_str());
1501 current_soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(dictp);
1503 GenRandomValue(current_soundfield->InstanceUID);
1504 GenRandomValue(current_soundfield->MCALinkID);
1505 current_soundfield->MCATagSymbol = "sg" + i->first;
1506 current_soundfield->MCATagName = i->first;
1507 current_soundfield->RFC5646SpokenLanguage = language;
1508 current_soundfield->MCALabelDictionaryID = i->second;
1509 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(current_soundfield));
1512 else if ( *i == ')' )
1514 if ( current_soundfield == 0 )
1516 fprintf(stderr, "Encountered ')', not currently processing a soundfield group.\n");
1520 if ( symbol_buf.empty() )
1522 fprintf(stderr, "Soundfield group description contains no channels.\n");
1526 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1528 if ( i == labels.end() )
1530 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1534 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1535 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1537 GenRandomValue(channel_descr->InstanceUID);
1538 assert(current_soundfield);
1539 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1540 channel_descr->MCAChannelID = channel_count++;
1541 channel_descr->MCATagSymbol = "ch" + i->first;
1542 channel_descr->MCATagName = i->first;
1543 channel_descr->RFC5646SpokenLanguage = language;
1544 channel_descr->MCALabelDictionaryID = i->second;
1545 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1547 current_soundfield = 0;
1549 else if ( *i == ',' )
1551 if ( ! symbol_buf.empty() )
1553 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1555 if ( i == labels.end() )
1557 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1561 if ( i->second.Value()[10] != 1 ) // magic depends on UL "Essence Facet" byte (see ST 428-12)
1563 fprintf(stderr, "Not a channel symbol: '%s'\n", symbol_buf.c_str());
1567 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1568 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1570 GenRandomValue(channel_descr->InstanceUID);
1572 if ( current_soundfield != 0 )
1574 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1577 channel_descr->MCAChannelID = channel_count++;
1578 channel_descr->MCATagSymbol = "ch" + i->first;
1579 channel_descr->MCATagName = i->first;
1580 channel_descr->RFC5646SpokenLanguage = language;
1581 channel_descr->MCALabelDictionaryID = i->second;
1582 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1586 else if ( isalnum(*i) )
1590 else if ( ! isspace(*i) )
1592 fprintf(stderr, "Unexpected character '%c'.\n", *i);
1597 if ( ! symbol_buf.empty() )
1599 mca_label_map_t::const_iterator i = labels.find(symbol_buf);
1601 if ( i == labels.end() )
1603 fprintf(stderr, "Unknown symbol: '%s'\n", symbol_buf.c_str());
1607 ASDCP::MXF::AudioChannelLabelSubDescriptor *channel_descr =
1608 new ASDCP::MXF::AudioChannelLabelSubDescriptor(dictp);
1610 GenRandomValue(channel_descr->InstanceUID);
1612 if ( current_soundfield != 0 )
1614 channel_descr->MCALinkID = current_soundfield->MCALinkID;
1617 channel_descr->MCAChannelID = channel_count++;
1618 channel_descr->MCATagSymbol = "ch" + i->first;
1619 channel_descr->MCATagName = i->first;
1620 channel_descr->RFC5646SpokenLanguage = language;
1621 channel_descr->MCALabelDictionaryID = i->second;
1622 descriptor_list.push_back(reinterpret_cast<ASDCP::MXF::InterchangeObject*>(channel_descr));
1629 ASDCP::MXF::ASDCP_MCAConfigParser::ASDCP_MCAConfigParser(const Dictionary*& d) : m_Dict(d), m_ChannelCount(0)
1631 m_LabelMap.insert(mca_label_map_t::value_type("L", m_Dict->ul(MDD_DCAudioChannel_L)));
1632 m_LabelMap.insert(mca_label_map_t::value_type("R", m_Dict->ul(MDD_DCAudioChannel_R)));
1633 m_LabelMap.insert(mca_label_map_t::value_type("C", m_Dict->ul(MDD_DCAudioChannel_C)));
1634 m_LabelMap.insert(mca_label_map_t::value_type("LFE", m_Dict->ul(MDD_DCAudioChannel_LFE)));
1635 m_LabelMap.insert(mca_label_map_t::value_type("Ls", m_Dict->ul(MDD_DCAudioChannel_Ls)));
1636 m_LabelMap.insert(mca_label_map_t::value_type("Rs", m_Dict->ul(MDD_DCAudioChannel_Rs)));
1637 m_LabelMap.insert(mca_label_map_t::value_type("Lss", m_Dict->ul(MDD_DCAudioChannel_Lss)));
1638 m_LabelMap.insert(mca_label_map_t::value_type("Rss", m_Dict->ul(MDD_DCAudioChannel_Rss)));
1639 m_LabelMap.insert(mca_label_map_t::value_type("Lrs", m_Dict->ul(MDD_DCAudioChannel_Lrs)));
1640 m_LabelMap.insert(mca_label_map_t::value_type("Rrs", m_Dict->ul(MDD_DCAudioChannel_Rrs)));
1641 m_LabelMap.insert(mca_label_map_t::value_type("Lc", m_Dict->ul(MDD_DCAudioChannel_Lc)));
1642 m_LabelMap.insert(mca_label_map_t::value_type("Rc", m_Dict->ul(MDD_DCAudioChannel_Rc)));
1643 m_LabelMap.insert(mca_label_map_t::value_type("Cs", m_Dict->ul(MDD_DCAudioChannel_Cs)));
1644 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_DCAudioChannel_HI)));
1645 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_DCAudioChannel_VIN)));
1646 m_LabelMap.insert(mca_label_map_t::value_type("51", m_Dict->ul(MDD_DCAudioSoundfield_51)));
1647 m_LabelMap.insert(mca_label_map_t::value_type("71", m_Dict->ul(MDD_DCAudioSoundfield_71)));
1648 m_LabelMap.insert(mca_label_map_t::value_type("SDS", m_Dict->ul(MDD_DCAudioSoundfield_SDS)));
1649 m_LabelMap.insert(mca_label_map_t::value_type("61", m_Dict->ul(MDD_DCAudioSoundfield_61)));
1650 m_LabelMap.insert(mca_label_map_t::value_type("M", m_Dict->ul(MDD_DCAudioSoundfield_M)));
1655 ASDCP::MXF::ASDCP_MCAConfigParser::ChannelCount() const
1657 return m_ChannelCount;
1660 // 51(L,R,C,LFE,Ls,Rs),HI,VIN
1662 ASDCP::MXF::ASDCP_MCAConfigParser::DecodeString(const std::string& s, const std::string& language)
1664 return decode_mca_string(s, m_LabelMap, *m_Dict, language, *this, m_ChannelCount);
1669 ASDCP::MXF::AS02_MCAConfigParser::AS02_MCAConfigParser(const Dictionary*& d) : ASDCP::MXF::ASDCP_MCAConfigParser(d)
1671 m_LabelMap.insert(mca_label_map_t::value_type("M1", m_Dict->ul(MDD_IMFAudioChannel_M1)));
1672 m_LabelMap.insert(mca_label_map_t::value_type("M2", m_Dict->ul(MDD_IMFAudioChannel_M2)));
1673 m_LabelMap.insert(mca_label_map_t::value_type("Lt", m_Dict->ul(MDD_IMFAudioChannel_Lt)));
1674 m_LabelMap.insert(mca_label_map_t::value_type("Rt", m_Dict->ul(MDD_IMFAudioChannel_Rt)));
1675 m_LabelMap.insert(mca_label_map_t::value_type("Lst", m_Dict->ul(MDD_IMFAudioChannel_Lst)));
1676 m_LabelMap.insert(mca_label_map_t::value_type("Rst", m_Dict->ul(MDD_IMFAudioChannel_Rst)));
1677 m_LabelMap.insert(mca_label_map_t::value_type("S", m_Dict->ul(MDD_IMFAudioChannel_S)));
1678 m_LabelMap.insert(mca_label_map_t::value_type("ST", m_Dict->ul(MDD_IMFAudioSoundfield_ST)));
1679 m_LabelMap.insert(mca_label_map_t::value_type("DM", m_Dict->ul(MDD_IMFAudioSoundfield_DM)));
1680 m_LabelMap.insert(mca_label_map_t::value_type("DNS", m_Dict->ul(MDD_IMFAudioSoundfield_DNS)));
1681 m_LabelMap.insert(mca_label_map_t::value_type("30", m_Dict->ul(MDD_IMFAudioSoundfield_30)));
1682 m_LabelMap.insert(mca_label_map_t::value_type("40", m_Dict->ul(MDD_IMFAudioSoundfield_40)));
1683 m_LabelMap.insert(mca_label_map_t::value_type("50", m_Dict->ul(MDD_IMFAudioSoundfield_50)));
1684 m_LabelMap.insert(mca_label_map_t::value_type("60", m_Dict->ul(MDD_IMFAudioSoundfield_60)));
1685 m_LabelMap.insert(mca_label_map_t::value_type("70", m_Dict->ul(MDD_IMFAudioSoundfield_70)));
1686 m_LabelMap.insert(mca_label_map_t::value_type("LtRt", m_Dict->ul(MDD_IMFAudioSoundfield_LtRt)));
1687 m_LabelMap.insert(mca_label_map_t::value_type("51Ex", m_Dict->ul(MDD_IMFAudioSoundfield_51Ex)));
1688 m_LabelMap.insert(mca_label_map_t::value_type("HI", m_Dict->ul(MDD_IMFAudioSoundfield_HI)));
1689 m_LabelMap.insert(mca_label_map_t::value_type("VIN", m_Dict->ul(MDD_IMFAudioSoundfield_VIN)));