2 Copyright (c) 2008-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.
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 virtual ~h__Reader() {}
142 Result_t OpenRead(const char*);
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 Batch<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(char const* 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 Array<RIP::Pair>::const_iterator pi;
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 char* 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 char*, 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(char const* 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);
574 m_EssenceStreamID = 10;
577 if ( ASDCP_SUCCESS(result) )
580 AddDMSegment(m_TDesc.EditRate, 24, TIMED_TEXT_DEF_LABEL,
581 UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
583 AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrapping)));
585 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
587 if ( KM_SUCCESS(result) )
588 result = CreateBodyPart(m_TDesc.EditRate);
591 if ( ASDCP_SUCCESS(result) )
593 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
594 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
595 result = m_State.Goto_READY();
603 ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
604 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
606 Result_t result = m_State.Goto_RUNNING();
608 if ( ASDCP_SUCCESS(result) )
610 // TODO: make sure it's XML
612 ui32_t str_size = XMLDoc.size();
613 FrameBuffer FrameBuf(str_size);
615 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
616 FrameBuf.Size(str_size);
618 IndexTableSegment::IndexEntry Entry;
619 Entry.StreamOffset = m_StreamOffset;
621 if ( ASDCP_SUCCESS(result) )
622 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
624 if ( ASDCP_SUCCESS(result) )
626 m_FooterPart.PushIndexEntry(Entry);
637 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
638 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
640 if ( ! m_State.Test_RUNNING() )
643 Kumu::fpos_t here = m_File.Tell();
646 // create generic stream partition header
647 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
648 MXF::Partition GSPart(m_Dict);
650 GSPart.ThisPartition = here;
651 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
652 GSPart.BodySID = m_EssenceStreamID;
653 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
655 m_RIP.PairArray.push_back(RIP::Pair(m_EssenceStreamID++, here));
656 GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
657 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
658 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
660 if ( ASDCP_SUCCESS(result) )
661 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
669 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
671 if ( ! m_State.Test_RUNNING() )
674 m_FramesWritten = m_TDesc.ContainerDuration;
675 m_State.Goto_FINAL();
677 return WriteASDCPFooter();
681 //------------------------------------------------------------------------------------------
683 ASDCP::TimedText::MXFWriter::MXFWriter()
687 ASDCP::TimedText::MXFWriter::~MXFWriter()
691 // Warning: direct manipulation of MXF structures can interfere
692 // with the normal operation of the wrapper. Caveat emptor!
694 ASDCP::MXF::OP1aHeader&
695 ASDCP::TimedText::MXFWriter::OP1aHeader()
697 if ( m_Writer.empty() )
699 assert(g_OP1aHeader);
700 return *g_OP1aHeader;
703 return m_Writer->m_HeaderPart;
706 // Warning: direct manipulation of MXF structures can interfere
707 // with the normal operation of the wrapper. Caveat emptor!
709 ASDCP::MXF::OPAtomIndexFooter&
710 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
712 if ( m_Writer.empty() )
714 assert(g_OPAtomIndexFooter);
715 return *g_OPAtomIndexFooter;
718 return m_Writer->m_FooterPart;
721 // Warning: direct manipulation of MXF structures can interfere
722 // with the normal operation of the wrapper. Caveat emptor!
725 ASDCP::TimedText::MXFWriter::RIP()
727 if ( m_Writer.empty() )
733 return m_Writer->m_RIP;
736 // Open the file for writing. The file must not exist. Returns error if
737 // the operation cannot be completed.
739 ASDCP::TimedText::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
740 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
742 if ( Info.LabelSetType != LS_MXF_SMPTE )
744 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
745 return RESULT_FORMAT;
748 m_Writer = new h__Writer(DefaultSMPTEDict());
749 m_Writer->m_Info = Info;
751 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
753 if ( ASDCP_SUCCESS(result) )
754 result = m_Writer->SetSourceStream(TDesc);
756 if ( ASDCP_FAILURE(result) )
764 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
766 if ( m_Writer.empty() )
769 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
774 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
776 if ( m_Writer.empty() )
779 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
782 // Closes the MXF file, writing the index and other closing information.
784 ASDCP::TimedText::MXFWriter::Finalize()
786 if ( m_Writer.empty() )
789 return m_Writer->Finalize();
795 // end AS_DCP_timedText.cpp