2 Copyright (c) 2008-2012, 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
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 Result_t OpenRead(const char*);
141 Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc);
142 Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
143 Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
148 ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc)
150 assert(m_EssenceDescriptor);
151 memset(&m_TDesc.AssetID, 0, UUIDlen);
152 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
154 TDesc.EditRate = TDescObj->SampleRate;
155 assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
156 TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
157 memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
158 TDesc.NamespaceName = TDescObj->NamespaceURI;
159 TDesc.EncodingName = TDescObj->UCSEncoding;
161 Batch<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
162 TimedTextResourceSubDescriptor* DescObject = 0;
163 Result_t result = RESULT_OK;
165 for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
167 InterchangeObject* tmp_iobj = 0;
168 result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
169 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
171 if ( KM_SUCCESS(result) )
173 TimedTextResourceDescriptor TmpResource;
174 memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
176 if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
177 || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
178 || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
179 TmpResource.Type = MT_OPENTYPE;
181 else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
182 TmpResource.Type = MT_PNG;
185 TmpResource.Type = MT_BIN;
187 TDesc.ResourceList.push_back(TmpResource);
188 m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
192 DefaultLogSink().Error("Broken sub-descriptor link\n");
193 return RESULT_FORMAT;
202 ASDCP::TimedText::MXFReader::h__Reader::OpenRead(char const* filename)
204 Result_t result = OpenMXFRead(filename);
206 if( ASDCP_SUCCESS(result) )
208 if ( m_EssenceDescriptor == 0 )
210 InterchangeObject* tmp_iobj = 0;
211 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
212 m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj);
215 if( ASDCP_SUCCESS(result) )
216 result = MD_to_TimedText_TDesc(m_TDesc);
219 if( ASDCP_SUCCESS(result) )
220 result = InitMXFIndex();
222 if( ASDCP_SUCCESS(result) )
230 ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf,
231 AESDecContext* Ctx, HMACContext* HMAC)
233 if ( ! m_File.IsOpen() )
237 Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
239 if( ASDCP_SUCCESS(result) )
241 FrameBuf.AssetID(m_TDesc.AssetID);
242 FrameBuf.MIMEType("text/xml");
250 ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
251 AESDecContext* Ctx, HMACContext* HMAC)
253 KM_TEST_NULL_L(uuid);
256 ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID);
257 if ( ri == m_ResourceMap.end() )
260 DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64));
264 TimedTextResourceSubDescriptor* DescObject = 0;
265 // get the subdescriptor
266 InterchangeObject* tmp_iobj = 0;
267 Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
268 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
270 if ( KM_SUCCESS(result) )
272 Array<RIP::Pair>::const_iterator pi;
276 // Look up the partition start in the RIP using the SID.
277 // Count the sequence length in because this is the sequence
278 // value needed to complete the HMAC.
279 for ( pi = m_HeaderPart.m_RIP.PairArray.begin(); pi != m_HeaderPart.m_RIP.PairArray.end(); ++pi, ++sequence )
281 if ( (*pi).BodySID == DescObject->EssenceStreamID )
288 if ( TmpPair.ByteOffset == 0 )
290 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
291 return RESULT_FORMAT;
294 if ( KM_SUCCESS(result) )
296 FrameBuf.AssetID(uuid);
297 FrameBuf.MIMEType(DescObject->MIMEMediaType);
299 // seek tp the start of the partition
300 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
302 m_LastPosition = TmpPair.ByteOffset;
303 result = m_File.Seek(TmpPair.ByteOffset);
306 // read the partition header
307 MXF::Partition GSPart(m_Dict);
308 result = GSPart.InitFromFile(m_File);
310 if( ASDCP_SUCCESS(result) )
313 if ( DescObject->EssenceStreamID != GSPart.BodySID )
316 DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
317 return RESULT_FORMAT;
320 // read the essence packet
322 if( ASDCP_SUCCESS(result) )
323 result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
332 //------------------------------------------------------------------------------------------
334 ASDCP::TimedText::MXFReader::MXFReader()
336 m_Reader = new h__Reader(DefaultSMPTEDict());
340 ASDCP::TimedText::MXFReader::~MXFReader()
344 // Warning: direct manipulation of MXF structures can interfere
345 // with the normal operation of the wrapper. Caveat emptor!
347 ASDCP::MXF::OPAtomHeader&
348 ASDCP::TimedText::MXFReader::OPAtomHeader()
350 if ( m_Reader.empty() )
352 assert(g_OPAtomHeader);
353 return *g_OPAtomHeader;
356 return m_Reader->m_HeaderPart;
359 // Warning: direct manipulation of MXF structures can interfere
360 // with the normal operation of the wrapper. Caveat emptor!
362 ASDCP::MXF::OPAtomIndexFooter&
363 ASDCP::TimedText::MXFReader::OPAtomIndexFooter()
365 if ( m_Reader.empty() )
367 assert(g_OPAtomIndexFooter);
368 return *g_OPAtomIndexFooter;
371 return m_Reader->m_FooterPart;
374 // Open the file for reading. The file must exist. Returns error if the
375 // operation cannot be completed.
377 ASDCP::TimedText::MXFReader::OpenRead(const char* filename) const
379 return m_Reader->OpenRead(filename);
382 // Fill the struct with the values from the file's header.
383 // Returns RESULT_INIT if the file is not open.
385 ASDCP::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
387 if ( m_Reader && m_Reader->m_File.IsOpen() )
389 TDesc = m_Reader->m_TDesc;
396 // Fill the struct with the values from the file's header.
397 // Returns RESULT_INIT if the file is not open.
399 ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
401 if ( m_Reader && m_Reader->m_File.IsOpen() )
403 Info = m_Reader->m_Info;
412 ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
414 FrameBuffer FrameBuf(2*Kumu::Megabyte);
416 Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
418 if ( ASDCP_SUCCESS(result) )
419 s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
426 ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf,
427 AESDecContext* Ctx, HMACContext* HMAC) const
429 if ( m_Reader && m_Reader->m_File.IsOpen() )
430 return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
437 ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
438 AESDecContext* Ctx, HMACContext* HMAC) const
440 if ( m_Reader && m_Reader->m_File.IsOpen() )
441 return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
449 ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
451 if ( m_Reader->m_File.IsOpen() )
452 m_Reader->m_HeaderPart.Dump(stream);
458 ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const
460 if ( m_Reader->m_File.IsOpen() )
461 m_Reader->m_FooterPart.Dump(stream);
466 ASDCP::TimedText::MXFReader::Close() const
468 if ( m_Reader && m_Reader->m_File.IsOpen() )
478 //------------------------------------------------------------------------------------------
482 class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__Writer
484 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
488 TimedTextDescriptor m_TDesc;
489 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
490 ui32_t m_EssenceStreamID;
492 h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceStreamID(10) {
493 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
498 Result_t OpenWrite(const char*, ui32_t HeaderSize);
499 Result_t SetSourceStream(const TimedTextDescriptor&);
500 Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
501 Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
503 Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc);
508 ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
510 assert(m_EssenceDescriptor);
511 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
513 TDescObj->SampleRate = TDesc.EditRate;
514 TDescObj->ContainerDuration = TDesc.ContainerDuration;
515 TDescObj->ResourceID.Set(TDesc.AssetID);
516 TDescObj->NamespaceURI = TDesc.NamespaceName;
517 TDescObj->UCSEncoding = TDesc.EncodingName;
524 ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize)
526 if ( ! m_State.Test_BEGIN() )
529 Result_t result = m_File.OpenWrite(filename);
531 if ( ASDCP_SUCCESS(result) )
533 m_HeaderSize = HeaderSize;
534 m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict);
535 result = m_State.Goto_INIT();
543 ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
545 if ( ! m_State.Test_INIT() )
549 ResourceList_t::const_iterator ri;
550 Result_t result = TimedText_TDesc_to_MD(m_TDesc);
552 for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
554 TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
555 GenRandomValue(resourceSubdescriptor->InstanceUID);
556 resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID);
557 resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type);
558 resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
559 m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
560 m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
563 m_EssenceStreamID = 10;
566 if ( ASDCP_SUCCESS(result) )
569 AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
570 UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
572 AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
574 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
576 if ( KM_SUCCESS(result) )
577 result = CreateBodyPart(m_TDesc.EditRate);
580 if ( ASDCP_SUCCESS(result) )
582 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
583 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
584 result = m_State.Goto_READY();
592 ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
593 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
595 Result_t result = m_State.Goto_RUNNING();
597 if ( ASDCP_SUCCESS(result) )
599 // TODO: make sure it's XML
601 ui32_t str_size = XMLDoc.size();
602 FrameBuffer FrameBuf(str_size);
604 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
605 FrameBuf.Size(str_size);
607 IndexTableSegment::IndexEntry Entry;
608 Entry.StreamOffset = m_StreamOffset;
610 if ( ASDCP_SUCCESS(result) )
611 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
613 if ( ASDCP_SUCCESS(result) )
615 m_FooterPart.PushIndexEntry(Entry);
626 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
627 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
629 if ( ! m_State.Test_RUNNING() )
632 Kumu::fpos_t here = m_File.Tell();
635 // create generic stream partition header
636 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
637 MXF::Partition GSPart(m_Dict);
639 GSPart.ThisPartition = here;
640 GSPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
641 GSPart.BodySID = m_EssenceStreamID;
642 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
644 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_EssenceStreamID++, here));
645 GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
646 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
647 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
649 if ( ASDCP_SUCCESS(result) )
650 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
658 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
660 if ( ! m_State.Test_RUNNING() )
663 m_FramesWritten = m_TDesc.ContainerDuration;
664 m_State.Goto_FINAL();
666 return WriteMXFFooter();
670 //------------------------------------------------------------------------------------------
672 ASDCP::TimedText::MXFWriter::MXFWriter()
676 ASDCP::TimedText::MXFWriter::~MXFWriter()
680 // Warning: direct manipulation of MXF structures can interfere
681 // with the normal operation of the wrapper. Caveat emptor!
683 ASDCP::MXF::OPAtomHeader&
684 ASDCP::TimedText::MXFWriter::OPAtomHeader()
686 if ( m_Writer.empty() )
688 assert(g_OPAtomHeader);
689 return *g_OPAtomHeader;
692 return m_Writer->m_HeaderPart;
695 // Warning: direct manipulation of MXF structures can interfere
696 // with the normal operation of the wrapper. Caveat emptor!
698 ASDCP::MXF::OPAtomIndexFooter&
699 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
701 if ( m_Writer.empty() )
703 assert(g_OPAtomIndexFooter);
704 return *g_OPAtomIndexFooter;
707 return m_Writer->m_FooterPart;
710 // Open the file for writing. The file must not exist. Returns error if
711 // the operation cannot be completed.
713 ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
714 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
716 if ( Info.LabelSetType != LS_MXF_SMPTE )
718 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
719 return RESULT_FORMAT;
722 m_Writer = new h__Writer(DefaultSMPTEDict());
723 m_Writer->m_Info = Info;
725 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
727 if ( ASDCP_SUCCESS(result) )
728 result = m_Writer->SetSourceStream(TDesc);
730 if ( ASDCP_FAILURE(result) )
738 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
740 if ( m_Writer.empty() )
743 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
748 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
750 if ( m_Writer.empty() )
753 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
756 // Closes the MXF file, writing the index and other closing information.
758 ASDCP::TimedText::MXFWriter::Finalize()
760 if ( m_Writer.empty() )
763 return m_Writer->Finalize();
769 // end AS_DCP_timedText.cpp