2 Copyright (c) 2008-2015, 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.
27 /*! \file AS_DCP_TimedText.cpp
28 \version $Id: AS_DCP_TimedText.cpp,v 1.38 2015/10/09 23:41:11 jhurst Exp $
29 \brief AS-DCP library, PCM essence reader and writer implementation
33 #include "AS_DCP_internal.h"
38 using Kumu::GenRandomValue;
40 static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE 429-5 clip wrapping of D-Cinema Timed Text data";
41 static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track";
44 //------------------------------------------------------------------------------------------
47 MIME2str(TimedText::MIMEType_t m)
49 if ( m == TimedText::MT_PNG )
52 else if ( m == TimedText::MT_OPENTYPE )
53 return "application/x-font-opentype";
55 return "application/octet-stream";
60 ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TDesc)
62 UUID TmpID(TDesc.AssetID);
65 strm << " EditRate: " << (unsigned) TDesc.EditRate.Numerator << "/" << (unsigned) TDesc.EditRate.Denominator << std::endl;
66 strm << "ContainerDuration: " << (unsigned) TDesc.ContainerDuration << std::endl;
67 strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl;
68 strm << " NamespaceName: " << TDesc.NamespaceName << std::endl;
69 strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl;
71 TimedText::ResourceList_t::const_iterator ri;
72 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
74 TmpID.Set((*ri).ResourceID);
75 strm << " " << TmpID.EncodeHex(buf, 64) << ": " << MIME2str((*ri).Type) << std::endl;
83 ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TDesc, FILE* stream)
88 UUID TmpID(TDesc.AssetID);
91 fprintf(stream, " EditRate: %u/%u\n", TDesc.EditRate.Numerator, TDesc.EditRate.Denominator);
92 fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration);
93 fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64));
94 fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str());
95 fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size());
97 TimedText::ResourceList_t::const_iterator ri;
98 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
100 TmpID.Set((*ri).ResourceID);
101 fprintf(stream, " %s: %s\n",
102 TmpID.EncodeHex(buf, 64),
103 MIME2str((*ri).Type));
109 ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
114 UUID TmpID(m_AssetID);
116 fprintf(stream, "%s | %s | %u\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str(), Size());
119 Kumu::hexdump(m_Data, dump_len, stream);
122 //------------------------------------------------------------------------------------------
124 typedef std::map<UUID, UUID> ResourceMap_t;
126 class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
128 MXF::TimedTextDescriptor* m_EssenceDescriptor;
129 ResourceMap_t m_ResourceMap;
131 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
134 TimedTextDescriptor m_TDesc;
136 h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0) {
137 memset(&m_TDesc.AssetID, 0, UUIDlen);
140 virtual ~h__Reader() {}
142 Result_t OpenRead(const std::string&);
143 Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc);
144 Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
145 Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
150 ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc)
152 assert(m_EssenceDescriptor);
153 memset(&m_TDesc.AssetID, 0, UUIDlen);
154 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
156 TDesc.EditRate = TDescObj->SampleRate;
157 assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
158 TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
159 memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
160 TDesc.NamespaceName = TDescObj->NamespaceURI;
161 TDesc.EncodingName = TDescObj->UCSEncoding;
163 Array<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
164 TimedTextResourceSubDescriptor* DescObject = 0;
165 Result_t result = RESULT_OK;
167 for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
169 InterchangeObject* tmp_iobj = 0;
170 result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
171 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
173 if ( KM_SUCCESS(result) )
175 TimedTextResourceDescriptor TmpResource;
176 memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
178 if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
179 || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
180 || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
181 TmpResource.Type = MT_OPENTYPE;
183 else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
184 TmpResource.Type = MT_PNG;
187 TmpResource.Type = MT_BIN;
189 TDesc.ResourceList.push_back(TmpResource);
190 m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
194 DefaultLogSink().Error("Broken sub-descriptor link\n");
195 return RESULT_FORMAT;
204 ASDCP::TimedText::MXFReader::h__Reader::OpenRead(const std::string& filename)
206 Result_t result = OpenMXFRead(filename);
208 if( ASDCP_SUCCESS(result) )
210 if ( m_EssenceDescriptor == 0 )
212 InterchangeObject* tmp_iobj = 0;
213 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
214 m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj);
217 if( ASDCP_SUCCESS(result) )
218 result = MD_to_TimedText_TDesc(m_TDesc);
226 ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf,
227 AESDecContext* Ctx, HMACContext* HMAC)
229 if ( ! m_File.IsOpen() )
233 Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
235 if( ASDCP_SUCCESS(result) )
237 FrameBuf.AssetID(m_TDesc.AssetID);
238 FrameBuf.MIMEType("text/xml");
246 ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
247 AESDecContext* Ctx, HMACContext* HMAC)
249 KM_TEST_NULL_L(uuid);
252 ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID);
253 if ( ri == m_ResourceMap.end() )
256 DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64));
260 TimedTextResourceSubDescriptor* DescObject = 0;
261 // get the subdescriptor
262 InterchangeObject* tmp_iobj = 0;
263 Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
264 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
266 if ( KM_SUCCESS(result) )
268 RIP::const_pair_iterator pi;
269 RIP::PartitionPair TmpPair;
272 // Look up the partition start in the RIP using the SID.
273 // Count the sequence length in because this is the sequence
274 // value needed to complete the HMAC.
275 for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
277 if ( (*pi).BodySID == DescObject->EssenceStreamID )
284 if ( TmpPair.ByteOffset == 0 )
286 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
287 return RESULT_FORMAT;
290 if ( KM_SUCCESS(result) )
292 FrameBuf.AssetID(uuid);
293 FrameBuf.MIMEType(DescObject->MIMEMediaType);
295 // seek tp the start of the partition
296 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
298 m_LastPosition = TmpPair.ByteOffset;
299 result = m_File.Seek(TmpPair.ByteOffset);
302 // read the partition header
303 MXF::Partition GSPart(m_Dict);
304 result = GSPart.InitFromFile(m_File);
306 if( ASDCP_SUCCESS(result) )
309 if ( DescObject->EssenceStreamID != GSPart.BodySID )
312 DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
313 return RESULT_FORMAT;
316 // read the essence packet
318 if( ASDCP_SUCCESS(result) )
319 result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
328 //------------------------------------------------------------------------------------------
330 ASDCP::TimedText::MXFReader::MXFReader()
332 m_Reader = new h__Reader(DefaultSMPTEDict());
336 ASDCP::TimedText::MXFReader::~MXFReader()
340 // Warning: direct manipulation of MXF structures can interfere
341 // with the normal operation of the wrapper. Caveat emptor!
343 ASDCP::MXF::OP1aHeader&
344 ASDCP::TimedText::MXFReader::OP1aHeader()
346 if ( m_Reader.empty() )
348 assert(g_OP1aHeader);
349 return *g_OP1aHeader;
352 return m_Reader->m_HeaderPart;
355 // Warning: direct manipulation of MXF structures can interfere
356 // with the normal operation of the wrapper. Caveat emptor!
358 ASDCP::MXF::OPAtomIndexFooter&
359 ASDCP::TimedText::MXFReader::OPAtomIndexFooter()
361 if ( m_Reader.empty() )
363 assert(g_OPAtomIndexFooter);
364 return *g_OPAtomIndexFooter;
367 return m_Reader->m_IndexAccess;
370 // Warning: direct manipulation of MXF structures can interfere
371 // with the normal operation of the wrapper. Caveat emptor!
374 ASDCP::TimedText::MXFReader::RIP()
376 if ( m_Reader.empty() )
382 return m_Reader->m_RIP;
385 // Open the file for reading. The file must exist. Returns error if the
386 // operation cannot be completed.
388 ASDCP::TimedText::MXFReader::OpenRead(const std::string& filename) const
390 return m_Reader->OpenRead(filename);
393 // Fill the struct with the values from the file's header.
394 // Returns RESULT_INIT if the file is not open.
396 ASDCP::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
398 if ( m_Reader && m_Reader->m_File.IsOpen() )
400 TDesc = m_Reader->m_TDesc;
407 // Fill the struct with the values from the file's header.
408 // Returns RESULT_INIT if the file is not open.
410 ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
412 if ( m_Reader && m_Reader->m_File.IsOpen() )
414 Info = m_Reader->m_Info;
423 ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
425 FrameBuffer FrameBuf(2*Kumu::Megabyte);
427 Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
429 if ( ASDCP_SUCCESS(result) )
430 s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
437 ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf,
438 AESDecContext* Ctx, HMACContext* HMAC) const
440 if ( m_Reader && m_Reader->m_File.IsOpen() )
441 return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
448 ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
449 AESDecContext* Ctx, HMACContext* HMAC) const
451 if ( m_Reader && m_Reader->m_File.IsOpen() )
452 return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
460 ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
462 if ( m_Reader->m_File.IsOpen() )
463 m_Reader->m_HeaderPart.Dump(stream);
469 ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const
471 if ( m_Reader->m_File.IsOpen() )
472 m_Reader->m_IndexAccess.Dump(stream);
477 ASDCP::TimedText::MXFReader::Close() const
479 if ( m_Reader && m_Reader->m_File.IsOpen() )
489 //------------------------------------------------------------------------------------------
493 class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
495 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
499 TimedTextDescriptor m_TDesc;
500 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
501 ui32_t m_EssenceStreamID;
503 h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceStreamID(10) {
504 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
507 virtual ~h__Writer() {}
509 Result_t OpenWrite(const std::string&, ui32_t HeaderSize);
510 Result_t SetSourceStream(const TimedTextDescriptor&);
511 Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
512 Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
514 Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc);
519 ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
521 assert(m_EssenceDescriptor);
522 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
524 TDescObj->SampleRate = TDesc.EditRate;
525 TDescObj->ContainerDuration = TDesc.ContainerDuration;
526 TDescObj->ResourceID.Set(TDesc.AssetID);
527 TDescObj->NamespaceURI = TDesc.NamespaceName;
528 TDescObj->UCSEncoding = TDesc.EncodingName;
535 ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize)
537 if ( ! m_State.Test_BEGIN() )
540 Result_t result = m_File.OpenWrite(filename);
542 if ( ASDCP_SUCCESS(result) )
544 m_HeaderSize = HeaderSize;
545 m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict);
546 result = m_State.Goto_INIT();
554 ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
556 if ( ! m_State.Test_INIT() )
560 ResourceList_t::const_iterator ri;
561 Result_t result = TimedText_TDesc_to_MD(m_TDesc);
563 for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
565 TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
566 GenRandomValue(resourceSubdescriptor->InstanceUID);
567 resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID);
568 resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type);
569 resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
570 m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
571 m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
573 // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4
574 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72;
577 m_EssenceStreamID = 10;
580 if ( ASDCP_SUCCESS(result) )
585 if ( m_Info.LabelSetType == LS_MXF_SMPTE ) // ERK
587 m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // 3-part, no essence in header
591 DefaultLogSink().Error("Unable to write Interop timed-text MXF file. Use SMPTE DCP options instead.\n");
592 return RESULT_FORMAT;
595 // timecode rate and essence rate are the same
596 AddDMSegment(m_TDesc.EditRate, m_TDesc.EditRate, derive_timecode_rate_from_edit_rate(m_TDesc.EditRate), TIMED_TEXT_DEF_LABEL,
597 UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
599 AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrappingClip)));
601 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
603 if ( KM_SUCCESS(result) )
604 result = CreateBodyPart(m_TDesc.EditRate);
607 if ( ASDCP_SUCCESS(result) )
609 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
610 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
611 result = m_State.Goto_READY();
619 ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
620 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
622 Result_t result = m_State.Goto_RUNNING();
624 if ( ASDCP_SUCCESS(result) )
626 // TODO: make sure it's XML
628 ui32_t str_size = XMLDoc.size();
629 FrameBuffer FrameBuf(str_size);
631 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
632 FrameBuf.Size(str_size);
634 IndexTableSegment::IndexEntry Entry;
635 Entry.StreamOffset = m_StreamOffset;
637 if ( ASDCP_SUCCESS(result) )
638 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
640 if ( ASDCP_SUCCESS(result) )
642 m_FooterPart.PushIndexEntry(Entry);
653 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
654 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
656 if ( ! m_State.Test_RUNNING() )
659 Kumu::fpos_t here = m_File.Tell();
662 // create generic stream partition header
663 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
664 MXF::Partition GSPart(m_Dict);
666 GSPart.ThisPartition = here;
667 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
668 GSPart.BodySID = m_EssenceStreamID;
669 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
671 m_RIP.PairArray.push_back(RIP::PartitionPair(m_EssenceStreamID++, here));
672 GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
673 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
674 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
676 if ( ASDCP_SUCCESS(result) )
677 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
685 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
687 if ( ! m_State.Test_RUNNING() )
690 m_FramesWritten = m_TDesc.ContainerDuration;
691 m_State.Goto_FINAL();
693 return WriteASDCPFooter();
697 //------------------------------------------------------------------------------------------
699 ASDCP::TimedText::MXFWriter::MXFWriter()
703 ASDCP::TimedText::MXFWriter::~MXFWriter()
707 // Warning: direct manipulation of MXF structures can interfere
708 // with the normal operation of the wrapper. Caveat emptor!
710 ASDCP::MXF::OP1aHeader&
711 ASDCP::TimedText::MXFWriter::OP1aHeader()
713 if ( m_Writer.empty() )
715 assert(g_OP1aHeader);
716 return *g_OP1aHeader;
719 return m_Writer->m_HeaderPart;
722 // Warning: direct manipulation of MXF structures can interfere
723 // with the normal operation of the wrapper. Caveat emptor!
725 ASDCP::MXF::OPAtomIndexFooter&
726 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
728 if ( m_Writer.empty() )
730 assert(g_OPAtomIndexFooter);
731 return *g_OPAtomIndexFooter;
734 return m_Writer->m_FooterPart;
737 // Warning: direct manipulation of MXF structures can interfere
738 // with the normal operation of the wrapper. Caveat emptor!
741 ASDCP::TimedText::MXFWriter::RIP()
743 if ( m_Writer.empty() )
749 return m_Writer->m_RIP;
752 // Open the file for writing. The file must not exist. Returns error if
753 // the operation cannot be completed.
755 ASDCP::TimedText::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
756 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
758 if ( Info.LabelSetType != LS_MXF_SMPTE )
760 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
761 return RESULT_FORMAT;
764 m_Writer = new h__Writer(DefaultSMPTEDict());
765 m_Writer->m_Info = Info;
767 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
769 if ( ASDCP_SUCCESS(result) )
770 result = m_Writer->SetSourceStream(TDesc);
772 if ( ASDCP_FAILURE(result) )
780 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
782 if ( m_Writer.empty() )
785 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
790 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
792 if ( m_Writer.empty() )
795 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
798 // Closes the MXF file, writing the index and other closing information.
800 ASDCP::TimedText::MXFWriter::Finalize()
802 if ( m_Writer.empty() )
805 return m_Writer->Finalize();
811 // end AS_DCP_timedText.cpp