2 Copyright (c) 2008-2016, 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 //------------------------------------------------------------------------------------------
48 MIME2str(TimedText::MIMEType_t m)
50 if ( m == TimedText::MT_PNG )
53 else if( m == TimedText::MT_OPENTYPE )
54 return "application/x-font-opentype";
56 return "application/octet-stream";
61 ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TDesc)
63 UUID TmpID(TDesc.AssetID);
66 strm << " EditRate: " << (unsigned) TDesc.EditRate.Numerator << "/" << (unsigned) TDesc.EditRate.Denominator << std::endl;
67 strm << "ContainerDuration: " << (unsigned) TDesc.ContainerDuration << std::endl;
68 strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl;
69 strm << " NamespaceName: " << TDesc.NamespaceName << std::endl;
70 strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl;
72 TimedText::ResourceList_t::const_iterator ri;
73 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
75 TmpID.Set((*ri).ResourceID);
76 strm << " " << TmpID.EncodeHex(buf, 64) << ": " << MIME2str((*ri).Type) << std::endl;
84 ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TDesc, FILE* stream)
89 UUID TmpID(TDesc.AssetID);
92 fprintf(stream, " EditRate: %u/%u\n", TDesc.EditRate.Numerator, TDesc.EditRate.Denominator);
93 fprintf(stream, "ContainerDuration: %u\n", TDesc.ContainerDuration);
94 fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64));
95 fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str());
96 fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size());
98 TimedText::ResourceList_t::const_iterator ri;
99 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ )
101 TmpID.Set((*ri).ResourceID);
102 fprintf(stream, " %s: %s\n",
103 TmpID.EncodeHex(buf, 64),
104 MIME2str((*ri).Type));
110 ASDCP::TimedText::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
115 UUID TmpID(m_AssetID);
117 fprintf(stream, "%s | %s | %u\n", TmpID.EncodeHex(buf, 64), m_MIMEType.c_str(), Size());
120 Kumu::hexdump(m_Data, dump_len, stream);
123 //------------------------------------------------------------------------------------------
125 typedef std::map<UUID, UUID> ResourceMap_t;
127 class ASDCP::TimedText::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
129 MXF::TimedTextDescriptor* m_EssenceDescriptor;
130 ResourceMap_t m_ResourceMap;
132 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
135 TimedTextDescriptor m_TDesc;
137 h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0) {
138 memset(&m_TDesc.AssetID, 0, UUIDlen);
141 virtual ~h__Reader() {}
143 Result_t OpenRead(const std::string&);
144 Result_t MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc);
145 Result_t ReadTimedTextResource(FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
146 Result_t ReadAncillaryResource(const byte_t*, FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
151 ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTextDescriptor& TDesc)
153 assert(m_EssenceDescriptor);
154 memset(&m_TDesc.AssetID, 0, UUIDlen);
155 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
157 TDesc.EditRate = TDescObj->SampleRate;
158 assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
159 TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
160 memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
161 TDesc.NamespaceName = TDescObj->NamespaceURI;
162 TDesc.EncodingName = TDescObj->UCSEncoding;
164 Array<UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
165 TimedTextResourceSubDescriptor* DescObject = 0;
166 Result_t result = RESULT_OK;
168 for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
170 InterchangeObject* tmp_iobj = 0;
171 result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
172 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
174 if ( KM_SUCCESS(result) )
176 TimedTextResourceDescriptor TmpResource;
177 memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
179 if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
180 || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
181 || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
182 TmpResource.Type = MT_OPENTYPE;
184 else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
185 TmpResource.Type = MT_PNG;
188 TmpResource.Type = MT_BIN;
190 TDesc.ResourceList.push_back(TmpResource);
191 m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
195 DefaultLogSink().Error("Broken sub-descriptor link\n");
196 return RESULT_FORMAT;
205 ASDCP::TimedText::MXFReader::h__Reader::OpenRead(const std::string& filename)
207 Result_t result = OpenMXFRead(filename);
209 if( ASDCP_SUCCESS(result) )
211 if ( m_EssenceDescriptor == 0 )
213 InterchangeObject* tmp_iobj = 0;
214 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
215 m_EssenceDescriptor = static_cast<MXF::TimedTextDescriptor*>(tmp_iobj);
218 if( ASDCP_SUCCESS(result) )
219 result = MD_to_TimedText_TDesc(m_TDesc);
227 ASDCP::TimedText::MXFReader::h__Reader::ReadTimedTextResource(FrameBuffer& FrameBuf,
228 AESDecContext* Ctx, HMACContext* HMAC)
230 if ( ! m_File.IsOpen() )
234 Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
236 if( ASDCP_SUCCESS(result) )
238 FrameBuf.AssetID(m_TDesc.AssetID);
239 FrameBuf.MIMEType("text/xml");
247 ASDCP::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
248 AESDecContext* Ctx, HMACContext* HMAC)
250 KM_TEST_NULL_L(uuid);
253 ResourceMap_t::const_iterator ri = m_ResourceMap.find(RID);
254 if ( ri == m_ResourceMap.end() )
257 DefaultLogSink().Error("No such resource: %s\n", RID.EncodeHex(buf, 64));
261 TimedTextResourceSubDescriptor* DescObject = 0;
262 // get the subdescriptor
263 InterchangeObject* tmp_iobj = 0;
264 Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
265 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
267 if ( KM_SUCCESS(result) )
269 RIP::const_pair_iterator pi;
270 RIP::PartitionPair TmpPair;
273 // Look up the partition start in the RIP using the SID.
274 // Count the sequence length in because this is the sequence
275 // value needed to complete the HMAC.
276 for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
278 if ( (*pi).BodySID == DescObject->EssenceStreamID )
285 if ( TmpPair.ByteOffset == 0 )
287 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
288 return RESULT_FORMAT;
291 if ( KM_SUCCESS(result) )
293 FrameBuf.AssetID(uuid);
294 FrameBuf.MIMEType(DescObject->MIMEMediaType);
296 // seek tp the start of the partition
297 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
299 m_LastPosition = TmpPair.ByteOffset;
300 result = m_File.Seek(TmpPair.ByteOffset);
303 // read the partition header
304 MXF::Partition GSPart(m_Dict);
305 result = GSPart.InitFromFile(m_File);
307 if( ASDCP_SUCCESS(result) )
310 if ( DescObject->EssenceStreamID != GSPart.BodySID )
313 DefaultLogSink().Error("Generic stream partition body differs: %s\n", RID.EncodeHex(buf, 64));
314 return RESULT_FORMAT;
317 // read the essence packet
319 if( ASDCP_SUCCESS(result) )
320 result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
329 //------------------------------------------------------------------------------------------
331 ASDCP::TimedText::MXFReader::MXFReader()
333 m_Reader = new h__Reader(DefaultSMPTEDict());
337 ASDCP::TimedText::MXFReader::~MXFReader()
341 // Warning: direct manipulation of MXF structures can interfere
342 // with the normal operation of the wrapper. Caveat emptor!
344 ASDCP::MXF::OP1aHeader&
345 ASDCP::TimedText::MXFReader::OP1aHeader()
347 if ( m_Reader.empty() )
349 assert(g_OP1aHeader);
350 return *g_OP1aHeader;
353 return m_Reader->m_HeaderPart;
356 // Warning: direct manipulation of MXF structures can interfere
357 // with the normal operation of the wrapper. Caveat emptor!
359 ASDCP::MXF::OPAtomIndexFooter&
360 ASDCP::TimedText::MXFReader::OPAtomIndexFooter()
362 if ( m_Reader.empty() )
364 assert(g_OPAtomIndexFooter);
365 return *g_OPAtomIndexFooter;
368 return m_Reader->m_IndexAccess;
371 // Warning: direct manipulation of MXF structures can interfere
372 // with the normal operation of the wrapper. Caveat emptor!
375 ASDCP::TimedText::MXFReader::RIP()
377 if ( m_Reader.empty() )
383 return m_Reader->m_RIP;
386 // Open the file for reading. The file must exist. Returns error if the
387 // operation cannot be completed.
389 ASDCP::TimedText::MXFReader::OpenRead(const std::string& filename) const
391 return m_Reader->OpenRead(filename);
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::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
399 if ( m_Reader && m_Reader->m_File.IsOpen() )
401 TDesc = m_Reader->m_TDesc;
408 // Fill the struct with the values from the file's header.
409 // Returns RESULT_INIT if the file is not open.
411 ASDCP::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
413 if ( m_Reader && m_Reader->m_File.IsOpen() )
415 Info = m_Reader->m_Info;
424 ASDCP::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
426 FrameBuffer FrameBuf(2*Kumu::Megabyte);
428 Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
430 if ( ASDCP_SUCCESS(result) )
431 s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
438 ASDCP::TimedText::MXFReader::ReadTimedTextResource(FrameBuffer& FrameBuf,
439 AESDecContext* Ctx, HMACContext* HMAC) const
441 if ( m_Reader && m_Reader->m_File.IsOpen() )
442 return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
449 ASDCP::TimedText::MXFReader::ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf,
450 AESDecContext* Ctx, HMACContext* HMAC) const
452 if ( m_Reader && m_Reader->m_File.IsOpen() )
453 return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
461 ASDCP::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
463 if ( m_Reader->m_File.IsOpen() )
464 m_Reader->m_HeaderPart.Dump(stream);
470 ASDCP::TimedText::MXFReader::DumpIndex(FILE* stream) const
472 if ( m_Reader->m_File.IsOpen() )
473 m_Reader->m_IndexAccess.Dump(stream);
478 ASDCP::TimedText::MXFReader::Close() const
480 if ( m_Reader && m_Reader->m_File.IsOpen() )
490 //------------------------------------------------------------------------------------------
494 class ASDCP::TimedText::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
496 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
500 TimedTextDescriptor m_TDesc;
501 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
502 ui32_t m_EssenceStreamID;
504 h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceStreamID(10) {
505 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
508 virtual ~h__Writer() {}
510 Result_t OpenWrite(const std::string&, ui32_t HeaderSize);
511 Result_t SetSourceStream(const TimedTextDescriptor&);
512 Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
513 Result_t WriteAncillaryResource(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
515 Result_t TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc);
520 ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
522 assert(m_EssenceDescriptor);
523 MXF::TimedTextDescriptor* TDescObj = (MXF::TimedTextDescriptor*)m_EssenceDescriptor;
525 TDescObj->SampleRate = TDesc.EditRate;
526 TDescObj->ContainerDuration = TDesc.ContainerDuration;
527 TDescObj->ResourceID.Set(TDesc.AssetID);
528 TDescObj->NamespaceURI = TDesc.NamespaceName;
529 TDescObj->UCSEncoding = TDesc.EncodingName;
536 ASDCP::TimedText::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize)
538 if ( ! m_State.Test_BEGIN() )
541 Result_t result = m_File.OpenWrite(filename);
543 if ( ASDCP_SUCCESS(result) )
545 m_HeaderSize = HeaderSize;
546 m_EssenceDescriptor = new MXF::TimedTextDescriptor(m_Dict);
547 result = m_State.Goto_INIT();
555 ASDCP::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
557 if ( ! m_State.Test_INIT() )
561 ResourceList_t::const_iterator ri;
562 Result_t result = TimedText_TDesc_to_MD(m_TDesc);
564 for ( ri = m_TDesc.ResourceList.begin() ; ri != m_TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
566 TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
567 GenRandomValue(resourceSubdescriptor->InstanceUID);
568 resourceSubdescriptor->AncillaryResourceID.Set((*ri).ResourceID);
569 resourceSubdescriptor->MIMEMediaType = MIME2str((*ri).Type);
570 resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
571 m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
572 m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
574 // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4
575 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72;
578 m_EssenceStreamID = 10;
581 if ( ASDCP_SUCCESS(result) )
583 InitHeader(MXFVersion_2004);
586 if ( m_Info.LabelSetType == LS_MXF_SMPTE ) // ERK
588 m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // 3-part, no essence in header
592 DefaultLogSink().Error("Unable to write Interop timed-text MXF file. Use SMPTE DCP options instead.\n");
593 return RESULT_FORMAT;
596 // timecode rate and essence rate are the same
597 AddSourceClip(m_TDesc.EditRate, m_TDesc.EditRate, derive_timecode_rate_from_edit_rate(m_TDesc.EditRate),
598 TIMED_TEXT_DEF_LABEL, m_EssenceUL, UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
600 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;
636 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
638 if ( ASDCP_SUCCESS(result) )
640 m_FooterPart.PushIndexEntry(Entry);
651 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
652 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
654 if ( ! m_State.Test_RUNNING() )
657 Kumu::fpos_t here = m_File.Tell();
660 // create generic stream partition header
661 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
662 MXF::Partition GSPart(m_Dict);
664 GSPart.ThisPartition = here;
665 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
666 GSPart.BodySID = m_EssenceStreamID;
667 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
669 m_RIP.PairArray.push_back(RIP::PartitionPair(m_EssenceStreamID++, here));
670 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
671 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
672 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
674 if ( ASDCP_SUCCESS(result) )
675 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
683 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
685 if ( ! m_State.Test_RUNNING() )
688 m_FramesWritten = m_TDesc.ContainerDuration;
689 m_State.Goto_FINAL();
691 return WriteASDCPFooter();
695 //------------------------------------------------------------------------------------------
697 ASDCP::TimedText::MXFWriter::MXFWriter()
701 ASDCP::TimedText::MXFWriter::~MXFWriter()
705 // Warning: direct manipulation of MXF structures can interfere
706 // with the normal operation of the wrapper. Caveat emptor!
708 ASDCP::MXF::OP1aHeader&
709 ASDCP::TimedText::MXFWriter::OP1aHeader()
711 if ( m_Writer.empty() )
713 assert(g_OP1aHeader);
714 return *g_OP1aHeader;
717 return m_Writer->m_HeaderPart;
720 // Warning: direct manipulation of MXF structures can interfere
721 // with the normal operation of the wrapper. Caveat emptor!
723 ASDCP::MXF::OPAtomIndexFooter&
724 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
726 if ( m_Writer.empty() )
728 assert(g_OPAtomIndexFooter);
729 return *g_OPAtomIndexFooter;
732 return m_Writer->m_FooterPart;
735 // Warning: direct manipulation of MXF structures can interfere
736 // with the normal operation of the wrapper. Caveat emptor!
739 ASDCP::TimedText::MXFWriter::RIP()
741 if ( m_Writer.empty() )
747 return m_Writer->m_RIP;
750 // Open the file for writing. The file must not exist. Returns error if
751 // the operation cannot be completed.
753 ASDCP::TimedText::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
754 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
756 if ( Info.LabelSetType != LS_MXF_SMPTE )
758 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
759 return RESULT_FORMAT;
762 m_Writer = new h__Writer(DefaultSMPTEDict());
763 m_Writer->m_Info = Info;
765 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
767 if ( ASDCP_SUCCESS(result) )
768 result = m_Writer->SetSourceStream(TDesc);
770 if ( ASDCP_FAILURE(result) )
778 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
780 if ( m_Writer.empty() )
783 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
788 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
790 if ( m_Writer.empty() )
793 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
796 // Closes the MXF file, writing the index and other closing information.
798 ASDCP::TimedText::MXFWriter::Finalize()
800 if ( m_Writer.empty() )
803 return m_Writer->Finalize();
809 // end AS_DCP_timedText.cpp