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) )
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 AddDMSegment(m_TDesc.EditRate, m_TDesc.EditRate, derive_timecode_rate_from_edit_rate(m_TDesc.EditRate), TIMED_TEXT_DEF_LABEL,
598 UL(m_Dict->ul(MDD_DataDataDef)), TIMED_TEXT_PACKAGE_LABEL);
600 AddEssenceDescriptor(UL(m_Dict->ul(MDD_TimedTextWrappingClip)));
602 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
604 if ( KM_SUCCESS(result) )
605 result = CreateBodyPart(m_TDesc.EditRate);
608 if ( ASDCP_SUCCESS(result) )
610 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
611 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
612 result = m_State.Goto_READY();
620 ASDCP::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
621 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
623 Result_t result = m_State.Goto_RUNNING();
625 if ( ASDCP_SUCCESS(result) )
627 // TODO: make sure it's XML
629 ui32_t str_size = XMLDoc.size();
630 FrameBuffer FrameBuf(str_size);
632 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
633 FrameBuf.Size(str_size);
635 IndexTableSegment::IndexEntry Entry;
636 Entry.StreamOffset = m_StreamOffset;
638 if ( ASDCP_SUCCESS(result) )
639 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
641 if ( ASDCP_SUCCESS(result) )
643 m_FooterPart.PushIndexEntry(Entry);
654 ASDCP::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
655 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
657 if ( ! m_State.Test_RUNNING() )
660 Kumu::fpos_t here = m_File.Tell();
663 // create generic stream partition header
664 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
665 MXF::Partition GSPart(m_Dict);
667 GSPart.ThisPartition = here;
668 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
669 GSPart.BodySID = m_EssenceStreamID;
670 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
672 m_RIP.PairArray.push_back(RIP::PartitionPair(m_EssenceStreamID++, here));
673 GSPart.EssenceContainers.push_back(UL(m_Dict->ul(MDD_TimedTextEssence)));
674 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
675 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
677 if ( ASDCP_SUCCESS(result) )
678 result = WriteEKLVPacket(FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
686 ASDCP::TimedText::MXFWriter::h__Writer::Finalize()
688 if ( ! m_State.Test_RUNNING() )
691 m_FramesWritten = m_TDesc.ContainerDuration;
692 m_State.Goto_FINAL();
694 return WriteASDCPFooter();
698 //------------------------------------------------------------------------------------------
700 ASDCP::TimedText::MXFWriter::MXFWriter()
704 ASDCP::TimedText::MXFWriter::~MXFWriter()
708 // Warning: direct manipulation of MXF structures can interfere
709 // with the normal operation of the wrapper. Caveat emptor!
711 ASDCP::MXF::OP1aHeader&
712 ASDCP::TimedText::MXFWriter::OP1aHeader()
714 if ( m_Writer.empty() )
716 assert(g_OP1aHeader);
717 return *g_OP1aHeader;
720 return m_Writer->m_HeaderPart;
723 // Warning: direct manipulation of MXF structures can interfere
724 // with the normal operation of the wrapper. Caveat emptor!
726 ASDCP::MXF::OPAtomIndexFooter&
727 ASDCP::TimedText::MXFWriter::OPAtomIndexFooter()
729 if ( m_Writer.empty() )
731 assert(g_OPAtomIndexFooter);
732 return *g_OPAtomIndexFooter;
735 return m_Writer->m_FooterPart;
738 // Warning: direct manipulation of MXF structures can interfere
739 // with the normal operation of the wrapper. Caveat emptor!
742 ASDCP::TimedText::MXFWriter::RIP()
744 if ( m_Writer.empty() )
750 return m_Writer->m_RIP;
753 // Open the file for writing. The file must not exist. Returns error if
754 // the operation cannot be completed.
756 ASDCP::TimedText::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
757 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
759 if ( Info.LabelSetType != LS_MXF_SMPTE )
761 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
762 return RESULT_FORMAT;
765 m_Writer = new h__Writer(DefaultSMPTEDict());
766 m_Writer->m_Info = Info;
768 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
770 if ( ASDCP_SUCCESS(result) )
771 result = m_Writer->SetSourceStream(TDesc);
773 if ( ASDCP_FAILURE(result) )
781 ASDCP::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
783 if ( m_Writer.empty() )
786 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
791 ASDCP::TimedText::MXFWriter::WriteAncillaryResource(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
793 if ( m_Writer.empty() )
796 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
799 // Closes the MXF file, writing the index and other closing information.
801 ASDCP::TimedText::MXFWriter::Finalize()
803 if ( m_Writer.empty() )
806 return m_Writer->Finalize();
812 // end AS_DCP_timedText.cpp