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_02_internal.h"
38 using Kumu::GenRandomValue;
40 static std::string TIMED_TEXT_PACKAGE_LABEL = "File Package: SMPTE ST 429-5 / ST 2067-5 clip wrapping of IMF 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";
58 //------------------------------------------------------------------------------------------
60 typedef std::map<Kumu::UUID, Kumu::UUID> ResourceMap_t;
62 class AS_02::TimedText::MXFReader::h__Reader : public AS_02::h__AS02Reader
64 ASDCP::MXF::TimedTextDescriptor* m_EssenceDescriptor;
65 ResourceMap_t m_ResourceMap;
67 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
70 TimedTextDescriptor m_TDesc;
72 h__Reader(const Dictionary& d) : AS_02::h__AS02Reader(d), m_EssenceDescriptor(0) {
73 memset(&m_TDesc.AssetID, 0, UUIDlen);
76 virtual ~h__Reader() {}
78 Result_t OpenRead(const std::string&);
79 Result_t MD_to_TimedText_TDesc(TimedTextDescriptor& TDesc);
80 Result_t ReadTimedTextResource(ASDCP::TimedText::FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
81 Result_t ReadAncillaryResource(const Kumu::UUID&, ASDCP::TimedText::FrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC);
86 AS_02::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedTextDescriptor& TDesc)
88 assert(m_EssenceDescriptor);
89 memset(&m_TDesc.AssetID, 0, UUIDlen);
90 ASDCP::MXF::TimedTextDescriptor* TDescObj = (ASDCP::MXF::TimedTextDescriptor*)m_EssenceDescriptor;
92 TDesc.EditRate = TDescObj->SampleRate;
93 assert(TDescObj->ContainerDuration <= 0xFFFFFFFFL);
94 TDesc.ContainerDuration = (ui32_t) TDescObj->ContainerDuration;
95 memcpy(TDesc.AssetID, TDescObj->ResourceID.Value(), UUIDlen);
96 TDesc.NamespaceName = TDescObj->NamespaceURI;
97 TDesc.EncodingName = TDescObj->UCSEncoding;
99 Array<Kumu::UUID>::const_iterator sdi = TDescObj->SubDescriptors.begin();
100 TimedTextResourceSubDescriptor* DescObject = 0;
101 Result_t result = RESULT_OK;
103 for ( ; sdi != TDescObj->SubDescriptors.end() && KM_SUCCESS(result); sdi++ )
105 InterchangeObject* tmp_iobj = 0;
106 result = m_HeaderPart.GetMDObjectByID(*sdi, &tmp_iobj);
107 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
109 if ( KM_SUCCESS(result) )
111 TimedTextResourceDescriptor TmpResource;
112 memcpy(TmpResource.ResourceID, DescObject->AncillaryResourceID.Value(), UUIDlen);
114 if ( DescObject->MIMEMediaType.find("application/x-font-opentype") != std::string::npos
115 || DescObject->MIMEMediaType.find("application/x-opentype") != std::string::npos
116 || DescObject->MIMEMediaType.find("font/opentype") != std::string::npos )
118 TmpResource.Type = ASDCP::TimedText::MT_OPENTYPE;
120 else if ( DescObject->MIMEMediaType.find("image/png") != std::string::npos )
122 TmpResource.Type = ASDCP::TimedText::MT_PNG;
126 TmpResource.Type = ASDCP::TimedText::MT_BIN;
129 TDesc.ResourceList.push_back(TmpResource);
130 m_ResourceMap.insert(ResourceMap_t::value_type(DescObject->AncillaryResourceID, *sdi));
134 DefaultLogSink().Error("Broken sub-descriptor link\n");
135 return RESULT_FORMAT;
144 AS_02::TimedText::MXFReader::h__Reader::OpenRead(const std::string& filename)
146 Result_t result = OpenMXFRead(filename.c_str());
148 if( ASDCP_SUCCESS(result) )
150 if ( m_EssenceDescriptor == 0 )
152 InterchangeObject* tmp_iobj = 0;
153 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(TimedTextDescriptor), &tmp_iobj);
154 m_EssenceDescriptor = static_cast<ASDCP::MXF::TimedTextDescriptor*>(tmp_iobj);
157 if( ASDCP_SUCCESS(result) )
158 result = MD_to_TimedText_TDesc(m_TDesc);
166 AS_02::TimedText::MXFReader::h__Reader::ReadTimedTextResource(ASDCP::TimedText::FrameBuffer& FrameBuf,
167 AESDecContext* Ctx, HMACContext* HMAC)
169 if ( ! m_File.IsOpen() )
175 Result_t result = ReadEKLVFrame(0, FrameBuf, m_Dict->ul(MDD_TimedTextEssence), Ctx, HMAC);
177 if( ASDCP_SUCCESS(result) )
179 FrameBuf.AssetID(m_TDesc.AssetID);
180 FrameBuf.MIMEType("text/xml");
188 AS_02::TimedText::MXFReader::h__Reader::ReadAncillaryResource(const Kumu::UUID& uuid,
189 ASDCP::TimedText::FrameBuffer& FrameBuf,
190 AESDecContext* Ctx, HMACContext* HMAC)
192 ResourceMap_t::const_iterator ri = m_ResourceMap.find(uuid);
193 if ( ri == m_ResourceMap.end() )
196 DefaultLogSink().Error("No such resource: %s\n", uuid.EncodeHex(buf, 64));
200 TimedTextResourceSubDescriptor* DescObject = 0;
201 // get the subdescriptor
202 InterchangeObject* tmp_iobj = 0;
203 Result_t result = m_HeaderPart.GetMDObjectByID((*ri).second, &tmp_iobj);
204 DescObject = static_cast<TimedTextResourceSubDescriptor*>(tmp_iobj);
206 if ( KM_SUCCESS(result) )
208 RIP::const_pair_iterator pi;
209 RIP::PartitionPair TmpPair;
212 // Look up the partition start in the RIP using the SID.
213 // Count the sequence length in because this is the sequence
214 // value needed to complete the HMAC.
215 for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi, ++sequence )
217 if ( (*pi).BodySID == DescObject->EssenceStreamID )
224 if ( TmpPair.ByteOffset == 0 )
226 DefaultLogSink().Error("Body SID not found in RIP set: %d\n", DescObject->EssenceStreamID);
227 return RESULT_FORMAT;
230 if ( KM_SUCCESS(result) )
232 FrameBuf.AssetID(uuid.Value());
233 FrameBuf.MIMEType(DescObject->MIMEMediaType);
235 // seek tp the start of the partition
236 if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
238 m_LastPosition = TmpPair.ByteOffset;
239 result = m_File.Seek(TmpPair.ByteOffset);
242 // read the partition header
243 ASDCP::MXF::Partition GSPart(m_Dict);
244 result = GSPart.InitFromFile(m_File);
246 if( ASDCP_SUCCESS(result) )
249 if ( DescObject->EssenceStreamID != GSPart.BodySID )
252 DefaultLogSink().Error("Generic stream partition body differs: %s\n", uuid.EncodeHex(buf, 64));
253 return RESULT_FORMAT;
256 // read the essence packet
258 if( ASDCP_SUCCESS(result) )
259 result = ReadEKLVPacket(0, sequence, FrameBuf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
268 //------------------------------------------------------------------------------------------
270 AS_02::TimedText::MXFReader::MXFReader()
272 m_Reader = new h__Reader(DefaultSMPTEDict());
276 AS_02::TimedText::MXFReader::~MXFReader()
280 // Warning: direct manipulation of MXF structures can interfere
281 // with the normal operation of the wrapper. Caveat emptor!
283 ASDCP::MXF::OP1aHeader&
284 AS_02::TimedText::MXFReader::OP1aHeader()
286 if ( m_Reader.empty() )
288 assert(g_OP1aHeader);
289 return *g_OP1aHeader;
292 return m_Reader->m_HeaderPart;
295 // Warning: direct manipulation of MXF structures can interfere
296 // with the normal operation of the wrapper. Caveat emptor!
298 AS_02::MXF::AS02IndexReader&
299 AS_02::TimedText::MXFReader::AS02IndexReader()
301 if ( m_Reader.empty() )
303 assert(g_AS02IndexReader);
304 return *g_AS02IndexReader;
307 return m_Reader->m_IndexAccess;
310 // Warning: direct manipulation of MXF structures can interfere
311 // with the normal operation of the wrapper. Caveat emptor!
314 AS_02::TimedText::MXFReader::RIP()
316 if ( m_Reader.empty() )
322 return m_Reader->m_RIP;
325 // Open the file for reading. The file must exist. Returns error if the
326 // operation cannot be completed.
328 AS_02::TimedText::MXFReader::OpenRead(const std::string& filename) const
330 return m_Reader->OpenRead(filename);
333 // Fill the struct with the values from the file's header.
334 // Returns RESULT_INIT if the file is not open.
336 AS_02::TimedText::MXFReader::FillTimedTextDescriptor(TimedText::TimedTextDescriptor& TDesc) const
338 if ( m_Reader && m_Reader->m_File.IsOpen() )
340 TDesc = m_Reader->m_TDesc;
347 // Fill the struct with the values from the file's header.
348 // Returns RESULT_INIT if the file is not open.
350 AS_02::TimedText::MXFReader::FillWriterInfo(WriterInfo& Info) const
352 if ( m_Reader && m_Reader->m_File.IsOpen() )
354 Info = m_Reader->m_Info;
363 AS_02::TimedText::MXFReader::ReadTimedTextResource(std::string& s, AESDecContext* Ctx, HMACContext* HMAC) const
365 ASDCP::TimedText::FrameBuffer FrameBuf(8*Kumu::Megabyte);
367 Result_t result = ReadTimedTextResource(FrameBuf, Ctx, HMAC);
369 if ( ASDCP_SUCCESS(result) )
370 s.assign((char*)FrameBuf.Data(), FrameBuf.Size());
377 AS_02::TimedText::MXFReader::ReadTimedTextResource(ASDCP::TimedText::FrameBuffer& FrameBuf,
378 AESDecContext* Ctx, HMACContext* HMAC) const
380 if ( m_Reader && m_Reader->m_File.IsOpen() )
381 return m_Reader->ReadTimedTextResource(FrameBuf, Ctx, HMAC);
388 AS_02::TimedText::MXFReader::ReadAncillaryResource(const Kumu::UUID& uuid, ASDCP::TimedText::FrameBuffer& FrameBuf,
389 AESDecContext* Ctx, HMACContext* HMAC) const
391 if ( m_Reader && m_Reader->m_File.IsOpen() )
392 return m_Reader->ReadAncillaryResource(uuid, FrameBuf, Ctx, HMAC);
400 AS_02::TimedText::MXFReader::DumpHeaderMetadata(FILE* stream) const
402 if ( m_Reader->m_File.IsOpen() )
403 m_Reader->m_HeaderPart.Dump(stream);
409 AS_02::TimedText::MXFReader::DumpIndex(FILE* stream) const
411 if ( m_Reader->m_File.IsOpen() )
412 m_Reader->m_IndexAccess.Dump(stream);
417 AS_02::TimedText::MXFReader::Close() const
419 if ( m_Reader && m_Reader->m_File.IsOpen() )
429 //------------------------------------------------------------------------------------------
433 class AS_02::TimedText::MXFWriter::h__Writer : public AS_02::h__AS02WriterClip
435 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
439 TimedTextDescriptor m_TDesc;
440 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
441 ui32_t m_EssenceStreamID;
442 ASDCP::Rational m_EditRate;
444 h__Writer(const Dictionary& d) : AS_02::h__AS02WriterClip(d), m_EssenceStreamID(10)
446 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
449 virtual ~h__Writer() {}
451 Result_t OpenWrite(const std::string&, ui32_t HeaderSize);
452 Result_t SetSourceStream(const ASDCP::TimedText::TimedTextDescriptor&);
453 Result_t WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* = 0, HMACContext* = 0);
454 Result_t WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
456 Result_t TimedText_TDesc_to_MD(ASDCP::TimedText::TimedTextDescriptor& TDesc);
461 AS_02::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTextDescriptor& TDesc)
463 assert(m_EssenceDescriptor);
464 ASDCP::MXF::TimedTextDescriptor* TDescObj = (ASDCP::MXF::TimedTextDescriptor*)m_EssenceDescriptor;
466 TDescObj->SampleRate = TDesc.EditRate;
467 TDescObj->ContainerDuration = TDesc.ContainerDuration;
468 TDescObj->ResourceID.Set(TDesc.AssetID);
469 TDescObj->NamespaceURI = TDesc.NamespaceName;
470 TDescObj->UCSEncoding = TDesc.EncodingName;
477 AS_02::TimedText::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize)
479 if ( ! m_State.Test_BEGIN() )
481 KM_RESULT_STATE_HERE();
485 Result_t result = m_File.OpenWrite(filename.c_str());
487 if ( ASDCP_SUCCESS(result) )
489 m_HeaderSize = HeaderSize;
490 m_EssenceDescriptor = new ASDCP::MXF::TimedTextDescriptor(m_Dict);
491 result = m_State.Goto_INIT();
499 AS_02::TimedText::MXFWriter::h__Writer::SetSourceStream(ASDCP::TimedText::TimedTextDescriptor const& TDesc)
501 if ( ! m_State.Test_INIT() )
503 KM_RESULT_STATE_HERE();
510 Result_t result = TimedText_TDesc_to_MD(m_TDesc);
512 if ( KM_SUCCESS(result) )
514 ResourceList_t::const_iterator i;
515 for ( i = m_TDesc.ResourceList.begin() ; i != m_TDesc.ResourceList.end(); ++i )
517 TimedTextResourceSubDescriptor* resourceSubdescriptor = new TimedTextResourceSubDescriptor(m_Dict);
518 GenRandomValue(resourceSubdescriptor->InstanceUID);
519 resourceSubdescriptor->AncillaryResourceID.Set((*i).ResourceID);
520 resourceSubdescriptor->MIMEMediaType = MIME2str((*i).Type);
521 resourceSubdescriptor->EssenceStreamID = m_EssenceStreamID++;
522 m_EssenceSubDescriptorList.push_back((FileDescriptor*)resourceSubdescriptor);
523 m_EssenceDescriptor->SubDescriptors.push_back(resourceSubdescriptor->InstanceUID);
525 // 72 == sizeof K, L, instanceuid, uuid + sizeof int32 + tag/len * 4
526 m_HeaderSize += ( resourceSubdescriptor->MIMEMediaType.ArchiveLength() * 2 /*ArchiveLength is broken*/ ) + 72;
530 //Reset m_EssenceStreamID to 10 for later usage in WriteAncillaryResource
531 m_EssenceStreamID = 10;
534 if ( KM_SUCCESS(result) )
536 memcpy(m_EssenceUL, m_Dict->ul(MDD_TimedTextEssence), SMPTE_UL_LENGTH);
537 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
538 result = m_State.Goto_READY();
541 if ( KM_SUCCESS(result) )
543 m_EditRate = TDesc.EditRate;
544 result = WriteAS02Header(TIMED_TEXT_PACKAGE_LABEL, UL(m_Dict->ul(MDD_TimedTextWrappingClip)),
545 "Data Track", UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
546 TDesc.EditRate, derive_timecode_rate_from_edit_rate(TDesc.EditRate));
554 AS_02::TimedText::MXFWriter::h__Writer::WriteTimedTextResource(const std::string& XMLDoc,
555 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
557 ASDCP::FrameBuffer segment_buffer;
558 IndexTableSegment::IndexEntry index_entry;
559 Result_t result = m_State.Goto_RUNNING();
561 if ( KM_SUCCESS(result) )
563 // TODO: make sure it's XML
565 ui32_t str_size = XMLDoc.size();
566 ASDCP::TimedText::FrameBuffer FrameBuf(str_size);
568 memcpy(FrameBuf.Data(), XMLDoc.c_str(), str_size);
569 FrameBuf.Size(str_size);
570 index_entry.StreamOffset = m_StreamOffset;
572 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
573 m_StreamOffset, FrameBuf, m_EssenceUL, Ctx, HMAC);
576 if ( KM_SUCCESS(result) )
578 // encode the index table
579 IndexTableSegment::DeltaEntry nil_delta_entry;
580 IndexTableSegment segment(m_Dict);
581 segment.m_Lookup = &m_HeaderPart.m_Primer;
582 GenRandomValue(segment.InstanceUID);
584 segment.DeltaEntryArray.push_back(nil_delta_entry);
585 segment.IndexEditRate = m_EditRate;
586 segment.IndexStartPosition = 0;
587 segment.IndexDuration = -1;
588 segment.IndexEntryArray.push_back(index_entry);
590 result = segment_buffer.Capacity(MaxIndexSegmentSize); // segment-count * max-segment-size
592 if ( KM_SUCCESS(result) )
594 result = segment.WriteToBuffer(segment_buffer);
598 if ( KM_SUCCESS(result) )
600 // create an index partition header
601 Kumu::fpos_t here = m_File.Tell();
604 ASDCP::MXF::Partition partition(m_Dict);
605 partition.MajorVersion = m_HeaderPart.MajorVersion;
606 partition.MinorVersion = m_HeaderPart.MinorVersion;
607 partition.ThisPartition = here;
608 partition.BodySID = 0;
609 partition.IndexSID = 129;
610 partition.IndexByteCount = segment_buffer.Size();
611 partition.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
612 partition.OperationalPattern = m_HeaderPart.OperationalPattern;
614 m_RIP.PairArray.push_back(RIP::PartitionPair(0, here));
615 partition.EssenceContainers = m_HeaderPart.EssenceContainers;
616 UL TmpUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
617 result = partition.WriteToFile(m_File, TmpUL);
620 if ( KM_SUCCESS(result) )
622 // write the encoded index table
623 ui32_t write_count = 0;
624 result = m_File.Write(segment_buffer.RoData(), segment_buffer.Size(), &write_count);
625 assert(write_count == segment_buffer.Size());
628 if ( KM_SUCCESS(result) )
639 AS_02::TimedText::MXFWriter::h__Writer::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf,
640 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
642 if ( ! m_State.Test_RUNNING() )
644 KM_RESULT_STATE_HERE();
648 Kumu::fpos_t here = m_File.Tell();
651 // create generic stream partition header
652 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
653 ASDCP::MXF::Partition GSPart(m_Dict);
655 GSPart.MajorVersion = m_HeaderPart.MajorVersion;
656 GSPart.MinorVersion = m_HeaderPart.MinorVersion;
657 GSPart.ThisPartition = here;
658 GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
659 GSPart.BodySID = m_EssenceStreamID;
660 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
662 m_RIP.PairArray.push_back(RIP::PartitionPair(m_EssenceStreamID++, here));
663 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
664 UL TmpUL(m_Dict->ul(MDD_GenericStreamPartition));
665 Result_t result = GSPart.WriteToFile(m_File, TmpUL);
667 if ( KM_SUCCESS(result) )
669 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
670 m_StreamOffset, FrameBuf, GenericStream_DataElement.Value(), Ctx, HMAC);
679 AS_02::TimedText::MXFWriter::h__Writer::Finalize()
681 if ( ! m_State.Test_RUNNING() )
683 DefaultLogSink().Error("Cannot finalize file, the primary essence resource has not been written.\n");
687 m_FramesWritten = m_TDesc.ContainerDuration;
689 Result_t result = m_State.Goto_FINAL();
691 if ( KM_SUCCESS(result) )
693 result = WriteAS02Footer();
700 //------------------------------------------------------------------------------------------
702 AS_02::TimedText::MXFWriter::MXFWriter()
706 AS_02::TimedText::MXFWriter::~MXFWriter()
710 // Warning: direct manipulation of MXF structures can interfere
711 // with the normal operation of the wrapper. Caveat emptor!
713 ASDCP::MXF::OP1aHeader&
714 AS_02::TimedText::MXFWriter::OP1aHeader()
716 if ( m_Writer.empty() )
718 assert(g_OP1aHeader);
719 return *g_OP1aHeader;
722 return m_Writer->m_HeaderPart;
725 // Warning: direct manipulation of MXF structures can interfere
726 // with the normal operation of the wrapper. Caveat emptor!
729 AS_02::TimedText::MXFWriter::RIP()
731 if ( m_Writer.empty() )
737 return m_Writer->m_RIP;
740 // Open the file for writing. The file must not exist. Returns error if
741 // the operation cannot be completed.
743 AS_02::TimedText::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
744 const TimedTextDescriptor& TDesc, ui32_t HeaderSize)
746 if ( Info.LabelSetType != LS_MXF_SMPTE )
748 DefaultLogSink().Error("Timed Text support requires LS_MXF_SMPTE\n");
749 return RESULT_FORMAT;
752 m_Writer = new h__Writer(DefaultSMPTEDict());
753 m_Writer->m_Info = Info;
755 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
757 if ( ASDCP_SUCCESS(result) )
758 result = m_Writer->SetSourceStream(TDesc);
760 if ( ASDCP_FAILURE(result) )
768 AS_02::TimedText::MXFWriter::WriteTimedTextResource(const std::string& XMLDoc, AESEncContext* Ctx, HMACContext* HMAC)
770 if ( m_Writer.empty() )
773 return m_Writer->WriteTimedTextResource(XMLDoc, Ctx, HMAC);
778 AS_02::TimedText::MXFWriter::WriteAncillaryResource(const ASDCP::TimedText::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
780 if ( m_Writer.empty() )
783 return m_Writer->WriteAncillaryResource(FrameBuf, Ctx, HMAC);
786 // Closes the MXF file, writing the index and other closing information.
788 AS_02::TimedText::MXFWriter::Finalize()
790 if ( m_Writer.empty() )
793 return m_Writer->Finalize();
799 // end AS_02_timedText.cpp