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 const ASDCP::Dictionary *sg_dict = &DefaultSMPTEDict();
41 static MXF::OPAtomHeader sg_OPAtomHeader(sg_dict);
42 static MXF::OPAtomIndexFooter sg_OPAtomIndexFooter(sg_dict);
44 static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE 429-5 clip wrapping of D-Cinema Timed Text data";
45 static std::string TIMED_TEXT_DEF_LABEL = "Timed Text Track";
48 //------------------------------------------------------------------------------------------
51 MIME2str(TimedText::MIMEType_t m)
53 if ( m == TimedText::MT_PNG )
56 else if ( m == TimedText::MT_OPENTYPE )
57 return "application/x-font-opentype";
59 return "application/octet-stream";
64 ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TDesc)
66 UUID TmpID(TDesc.AssetID);
69 strm << " EditRate: " << (unsigned) TDesc.EditRate.Numerator << "/" << (unsigned) TDesc.EditRate.Denominator << std::endl;
70 strm << "ContainerDuration: " << (unsigned) TDesc.ContainerDuration << std::endl;
71 strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl;
72 strm << " NamespaceName: " << TDesc.NamespaceName << std::endl;
73 strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl;
75 TimedText::ResourceList_t::const_iterator ri;
76 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
78 TmpID.Set((*ri).ResourceID);
79 strm << " " << TmpID.EncodeHex(buf, 64) << ": " << MIME2str((*ri).Type) << std::endl;
87 ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TDesc, FILE* stream)
92 UUID TmpID(TDesc.AssetID);
95 fprintf(stream, " EditRate: %u/%u\n", TDesc.EditRate.Numerator, TDesc.EditRate.Denominator);
96 fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration);
97 fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64));
98 fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str());
99 fprintf(stream, " ResourceCount: %d\n", TDesc.ResourceList.size());
101 TimedText::ResourceList_t::const_iterator ri;
102 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
104 TmpID.Set((*ri).ResourceID);
105 fprintf(stream, " %s: %s\n",
106 TmpID.EncodeHex(buf, 64),
107 MIME2str((*ri).Type));
113 ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
118 UUID TmpID(m_AssetID);
120 fprintf(stream, "%s | %s | %u\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str(), Size());
123 Kumu::hexdump(m_Data, dump_len, stream);
126 //------------------------------------------------------------------------------------------
128 typedef std::map<UUID, UUID> ResourceMap_t;
130 class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__Reader
132 MXF::TimedTextDescriptor* m_EssenceDescriptor;
133 ResourceMap_t m_ResourceMap;
135 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
138 TimedTextDescriptor m_TDesc;
140 h__Reader(const Dictionary& d) : ASDCP::h__Reader(d), m_EssenceDescriptor(0) {
141 memset(&m_TDesc.AssetID, 0, UUIDlen);
144 Result_t OpenRead(const char*);
145 Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc);
146 Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
147 Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
152 ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc)
154 assert(m_EssenceDescriptor);
155 memset(&m_TDesc.AssetID, 0, UUIDlen);
156 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
158 TDesc.EditRate = TDescObj->SampleRate;
159 assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
160 TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
161 memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
162 TDesc.NamespaceName = TDescObj->NamespaceURI;
163 TDesc.EncodingName = TDescObj->UCSEncoding;
165 Batch<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
166 TimedTextResourceSubDescriptor* DescObject = 0;
167 Result_t result = RESULT_OK;
169 for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
171 InterchangeObject* tmp_iobj = 0;
172 result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
173 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
175 if ( KM_SUCCESS(result) )
177 TimedTextResourceDescriptor TmpResource;
178 memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
180 if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
181 || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
182 || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
183 TmpResource.Type = MT_OPENTYPE;
185 else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
186 TmpResource.Type = MT_PNG;
189 TmpResource.Type = MT_BIN;
191 TDesc.ResourceList.push_back(TmpResource);
192 m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
196 DefaultLogSink().Error("Broken sub-descriptor link\n");
197 return RESULT_FORMAT;
206 ASDCP::TimedText::MXFReader::h__Reader::OpenRead(char const* filename)
208 Result_t result = OpenMXFRead(filename);
210 if( ASDCP_SUCCESS(result) )
212 if ( m_EssenceDescriptor == 0 )
214 InterchangeObject* tmp_iobj = 0;
215 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
216 m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj);
219 if( ASDCP_SUCCESS(result) )
220 result = MD_to_TimedText_TDesc(m_TDesc);
223 if( ASDCP_SUCCESS(result) )
224 result = InitMXFIndex();
226 if( ASDCP_SUCCESS(result) )
234 ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf,
235 AESDecContext* Ctx, HMACContext* HMAC)
237 if ( ! m_File.IsOpen() )
241 Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
243 if( ASDCP_SUCCESS(result) )
245 FrameBuf.AssetID(m_TDesc.AssetID);
246 FrameBuf.MIMEType("text/xml");
254 ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
255 AESDecContext* Ctx, HMACContext* HMAC)
257 KM_TEST_NULL_L(uuid);
260 ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID);
261 if ( ri == m_ResourceMap.end() )
264 DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64));
268 TimedTextResourceSubDescriptor* DescObject = 0;
269 // get the subdescriptor
270 InterchangeObject* tmp_iobj = 0;
271 Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
272 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
274 if ( KM_SUCCESS(result) )
276 Array<RIP::Pair>::const_iterator pi;
280 // Look up the partition start in the RIP using the SID.
281 // Count the sequence length in because this is the sequence
282 // value needed to complete the HMAC.
283 for ( pi = m_HeaderPart.m_RIP.PairArray.begin(); pi != m_HeaderPart.m_RIP.PairArray.end(); pi++, sequence++ )
285 if ( (*pi).BodySID == DescObject->EssenceStreamID )
292 if ( TmpPair.ByteOffset == 0 )
294 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
295 return RESULT_FORMAT;
298 if ( KM_SUCCESS(result) )
300 FrameBuf.AssetID(uuid);
301 FrameBuf.MIMEType(DescObject->MIMEMediaType);
303 // seek tp the start of the partition
304 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
306 m_LastPosition = TmpPair.ByteOffset;
307 result = m_File.Seek(TmpPair.ByteOffset);
310 // read the partition header
311 MXF::Partition GSPart(m_Dict);
312 result = GSPart.InitFromFile(m_File);
314 if( ASDCP_SUCCESS(result) )
317 if ( DescObject->EssenceStreamID != GSPart.BodySID )
320 DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
321 return RESULT_FORMAT;
324 // read the essence packet
326 if( ASDCP_SUCCESS(result) )
327 result = ReadEKLVPacket(0, 1, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
336 //------------------------------------------------------------------------------------------
338 ASDCP::TimedText::MXFReader::MXFReader()
340 m_Reader = new h__Reader(DefaultSMPTEDict());
344 ASDCP::TimedText::MXFReader::~MXFReader()
348 // Warning: direct manipulation of MXF structures can interfere
349 // with the normal operation of the wrapper. Caveat emptor!
351 ASDCP::MXF::OPAtomHeader&
352 ASDCP::TimedText::MXFReader::OPAtomHeader()
354 if ( m_Reader.empty() )
355 return sg_OPAtomHeader;
357 return m_Reader->m_HeaderPart;
360 // Warning: direct manipulation of MXF structures can interfere
361 // with the normal operation of the wrapper. Caveat emptor!
363 ASDCP::MXF::OPAtomIndexFooter&
364 ASDCP::TimedText::MXFReader::OPAtomIndexFooter()
366 if ( m_Reader.empty() )
367 return sg_OPAtomIndexFooter;
369 return m_Reader->m_FooterPart;
372 // Open the file for reading. The file must exist. Returns error if the
373 // operation cannot be completed.
375 ASDCP::TimedText::MXFReader::OpenRead(const char* filename) const
377 return m_Reader->OpenRead(filename);
380 // Fill the struct with the values from the file's header.
381 // Returns RESULT_INIT if the file is not open.
383 ASDCP::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
385 if ( m_Reader && m_Reader->m_File.IsOpen() )
387 TDesc = m_Reader->m_TDesc;
394 // Fill the struct with the values from the file's header.
395 // Returns RESULT_INIT if the file is not open.
397 ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
399 if ( m_Reader && m_Reader->m_File.IsOpen() )
401 Info = m_Reader->m_Info;
410 ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
412 FrameBuffer FrameBuf(2*Kumu::Megabyte);
414 Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
416 if ( ASDCP_SUCCESS(result) )
417 s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
424 ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf,
425 AESDecContext* Ctx, HMACContext* HMAC) const
427 if ( m_Reader && m_Reader->m_File.IsOpen() )
428 return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
435 ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
436 AESDecContext* Ctx, HMACContext* HMAC) const
438 if ( m_Reader && m_Reader->m_File.IsOpen() )
439 return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
447 ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
449 if ( m_Reader->m_File.IsOpen() )
450 m_Reader->m_HeaderPart.Dump(stream);
456 ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const
458 if ( m_Reader->m_File.IsOpen() )
459 m_Reader->m_FooterPart.Dump(stream);
464 ASDCP::TimedText::MXFReader::Close() const
466 if ( m_Reader && m_Reader->m_File.IsOpen() )
476 //------------------------------------------------------------------------------------------
480 class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__Writer
482 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
486 TimedTextDescriptor m_TDesc;
487 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
488 ui32_t m_EssenceStreamID;
490 h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceStreamID(10) {
491 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
496 Result_t OpenWrite(const char*, ui32_t HeaderSize);
497 Result_t SetSourceStream(const TimedTextDescriptor&);
498 Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
499 Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
501 Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc);
506 ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
508 assert(m_EssenceDescriptor);
509 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
511 TDescObj->SampleRate = TDesc.EditRate;
512 TDescObj->ContainerDuration = TDesc.ContainerDuration;
513 TDescObj->ResourceID.Set(TDesc.AssetID);
514 TDescObj->NamespaceURI = TDesc.NamespaceName;
515 TDescObj->UCSEncoding = TDesc.EncodingName;
522 ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize)
524 if ( ! m_State.Test_BEGIN() )
527 Result_t result = m_File.OpenWrite(filename);
529 if ( ASDCP_SUCCESS(result) )
531 m_HeaderSize = HeaderSize;
532 m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict);
533 result = m_State.Goto_INIT();
541 ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
543 if ( ! m_State.Test_INIT() )
547 ResourceList_t::const_iterator ri;
548 Result_t result = TimedText_TDesc_to_MD(m_TDesc);
550 for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
552 TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
553 GenRandomValue(resourceSubdescriptor->InstanceUID);
554 resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID);
555 resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type);
556 resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
557 m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
558 m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
561 m_EssenceStreamID = 10;
564 if ( ASDCP_SUCCESS(result) )
567 AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
568 UL(m_Dict->ul(MDD_PictureDataDef)), TIMED_TEXT_PACKAGE_LABEL);
570 AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
572 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
574 if ( KM_SUCCESS(result) )
575 result = CreateBodyPart(m_TDesc.EditRate);
578 if ( ASDCP_SUCCESS(result) )
580 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
581 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
582 result = m_State.Goto_READY();
590 ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
591 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
593 Result_t result = m_State.Goto_RUNNING();
595 if ( ASDCP_SUCCESS(result) )
597 // TODO: make sure it's XML
599 ui32_t str_size = XMLDoc.size();
600 FrameBuffer FrameBuf(str_size);
602 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
603 FrameBuf.Size(str_size);
605 IndexTableSegment::IndexEntry Entry;
606 Entry.StreamOffset = m_StreamOffset;
608 if ( ASDCP_SUCCESS(result) )
609 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
611 if ( ASDCP_SUCCESS(result) )
613 m_FooterPart.PushIndexEntry(Entry);
624 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
625 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
627 if ( ! m_State.Test_RUNNING() )
630 Kumu::fpos_t here = m_File.Tell();
633 // create generic stream partition header
634 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
635 MXF::Partition GSPart(m_Dict);
637 GSPart.ThisPartition = here;
638 GSPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
639 GSPart.BodySID = m_EssenceStreamID;
640 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
642 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(m_EssenceStreamID++, here));
643 GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
644 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
645 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
647 if ( ASDCP_SUCCESS(result) )
648 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
656 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
658 if ( ! m_State.Test_RUNNING() )
661 m_FramesWritten = m_TDesc.ContainerDuration;
662 m_State.Goto_FINAL();
664 return WriteMXFFooter();
668 //------------------------------------------------------------------------------------------
670 ASDCP::TimedText::MXFWriter::MXFWriter()
674 ASDCP::TimedText::MXFWriter::~MXFWriter()
678 // Warning: direct manipulation of MXF structures can interfere
679 // with the normal operation of the wrapper. Caveat emptor!
681 ASDCP::MXF::OPAtomHeader&
682 ASDCP::TimedText::MXFWriter::OPAtomHeader()
684 if ( m_Writer.empty() )
685 return sg_OPAtomHeader;
687 return m_Writer->m_HeaderPart;
690 // Warning: direct manipulation of MXF structures can interfere
691 // with the normal operation of the wrapper. Caveat emptor!
693 ASDCP::MXF::OPAtomIndexFooter&
694 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
696 if ( m_Writer.empty() )
697 return sg_OPAtomIndexFooter;
699 return m_Writer->m_FooterPart;
702 // Open the file for writing. The file must not exist. Returns error if
703 // the operation cannot be completed.
705 ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
706 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
708 if ( Info.LabelSetType != LS_MXF_SMPTE )
710 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
711 return RESULT_FORMAT;
714 m_Writer = new h__Writer(DefaultSMPTEDict());
715 m_Writer->m_Info = Info;
717 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
719 if ( ASDCP_SUCCESS(result) )
720 result = m_Writer->SetSourceStream(TDesc);
722 if ( ASDCP_FAILURE(result) )
730 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
732 if ( m_Writer.empty() )
735 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
740 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
742 if ( m_Writer.empty() )
745 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
748 // Closes the MXF file, writing the index and other closing information.
750 ASDCP::TimedText::MXFWriter::Finalize()
752 if ( m_Writer.empty() )
755 return m_Writer->Finalize();
761 // end AS_DCP_timedText.cpp