From f655345eab252ff989c1f9cbdafa894556719aaa Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:06:03 -0800 Subject: [PATCH 1/6] feature: emit timed text language in output --- src/AS_DCP.h | 1 + src/AS_DCP_TimedText.cpp | 6 ++++++ src/TimedText_Parser.cpp | 11 +++++++++++ 3 files changed, 18 insertions(+) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index aab7f77f..f380840c 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1477,6 +1477,7 @@ namespace ASDCP { byte_t AssetID[UUIDlen]; std::string NamespaceName; std::string EncodingName; + std::string Language; ResourceList_t ResourceList; TimedTextDescriptor() : ContainerDuration(0), EncodingName("UTF-8") { memset(AssetID, 0, UUIDlen); } // D-Cinema format is always UTF-8 diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index 9a3e3362..8bc01199 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -68,6 +68,7 @@ ASDCP::TimedText::operator << (std::ostream& strm, const TimedTextDescriptor& TD strm << " AssetID: " << TmpID.EncodeHex(buf, 64) << std::endl; strm << " NamespaceName: " << TDesc.NamespaceName << std::endl; strm << " ResourceCount: " << (unsigned long) TDesc.ResourceList.size() << std::endl; + strm << " Language: " << TDesc.Language << std::endl; TimedText::ResourceList_t::const_iterator ri; for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ ) @@ -94,6 +95,7 @@ ASDCP::TimedText::DescriptorDump(ASDCP::TimedText::TimedTextDescriptor const& TD fprintf(stream, " AssetID: %s\n", TmpID.EncodeHex(buf, 64)); fprintf(stream, " NamespaceName: %s\n", TDesc.NamespaceName.c_str()); fprintf(stream, " ResourceCount: %zu\n", TDesc.ResourceList.size()); + fprintf(stream, " Language: %s\n", TDesc.Language.c_str()); TimedText::ResourceList_t::const_iterator ri; for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end(); ri++ ) @@ -164,6 +166,9 @@ ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTe TDesc.NamespaceName = TDescObj->NamespaceURI; TDesc.EncodingName = TDescObj->UCSEncoding; TDesc.ResourceList.clear(); + if (! TDescObj->RFC5646LanguageTagList.empty() ) { + TDesc.Language = TDescObj->RFC5646LanguageTagList.get(); + } Array::const_iterator sdi = TDescObj->SubDescriptors.begin(); TimedTextResourceSubDescriptor* DescObject = 0; @@ -484,6 +489,7 @@ ASDCP::TimedText::MXFWriter::h__Writer::TimedText_TDesc_to_MD(TimedText::TimedTe TDescObj->ResourceID.Set(TDesc.AssetID); TDescObj->NamespaceURI = TDesc.NamespaceName; TDescObj->UCSEncoding = TDesc.EncodingName; + TDescObj->RFC5646LanguageTagList.set(TDesc.Language); return RESULT_OK; } diff --git a/src/TimedText_Parser.cpp b/src/TimedText_Parser.cpp index d3eca729..e84f26b4 100644 --- a/src/TimedText_Parser.cpp +++ b/src/TimedText_Parser.cpp @@ -271,6 +271,17 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() return RESULT_FORMAT; } + // Language + XMLElement* Language = m_Root.GetChildWithName("Language"); + + if ( Language == 0 ) + { + DefaultLogSink().Error("Language element missing from input document.\n"); + return RESULT_FORMAT; + } + + m_TDesc.Language = Language->GetBody(); + // list of fonts ElementList FontList; m_Root.GetChildrenWithName("LoadFont", FontList); From 4c2c5180b490a101242162b7fa2745c0820c76a2 Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:41:41 -0800 Subject: [PATCH 2/6] feature: allow a faux timed text intrinsic duration --- src/AS_DCP.h | 2 +- src/TimedText_Parser.cpp | 31 +++++++++++++++++++++---------- src/asdcp-wrap.cpp | 5 ++++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index f380840c..52489422 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1549,7 +1549,7 @@ namespace ASDCP { // Opens an XML file for reading, parses data to provide a complete // set of stream metadata for the MXFWriter below. - Result_t OpenRead(const std::string& filename) const; + Result_t OpenRead(const std::string& filename, ui32_t d=0) const; // Parses an XML document to provide a complete set of stream metadata // for the MXFWriter below. The optional filename argument is used to diff --git a/src/TimedText_Parser.cpp b/src/TimedText_Parser.cpp index e84f26b4..3ee1d914 100644 --- a/src/TimedText_Parser.cpp +++ b/src/TimedText_Parser.cpp @@ -112,7 +112,7 @@ class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser { XMLElement m_Root; ResourceTypeMap_t m_ResourceTypes; - Result_t OpenRead(); + Result_t OpenRead(ui32_t d=0); ASDCP_NO_COPY_CONSTRUCT(h__SubtitleParser); @@ -140,8 +140,8 @@ class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser return m_DefaultResolver; } - Result_t OpenRead(const std::string& filename); - Result_t OpenRead(const std::string& xml_doc, const std::string& filename); + Result_t OpenRead(const std::string& filename, ui32_t duration_override=0); + Result_t OpenRead(const std::string& xml_doc, const std::string& filename, ui32_t duration_override=0); Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, const IResourceResolver& Resolver) const; }; namespace { @@ -179,12 +179,12 @@ namespace { // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& filename) +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& filename, ui32_t duration_override) { Result_t result = ReadFileIntoString(filename, m_XMLDoc); if ( KM_SUCCESS(result) ) - result = OpenRead(); + result = OpenRead(duration_override); m_Filename = filename; return result; @@ -192,7 +192,7 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::strin // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const std::string& filename) +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const std::string& filename, ui32_t duration_override) { m_XMLDoc = xml_doc; @@ -205,12 +205,12 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::strin m_Filename = filename; } - return OpenRead(); + return OpenRead(duration_override); } // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(ui32_t duration_override) { if ( ! m_Root.ParseString(m_XMLDoc) ) return RESULT_FORMAT; @@ -369,6 +369,17 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() m_TDesc.ContainerDuration = end_count - beginTC.GetFrames(); + if (duration_override) + { + if (duration_override < m_TDesc.ContainerDuration) + { + DefaultLogSink(). Error("Override Duration (%d) may not be less than the actual intrinsic duration (%d).\n", + duration_override, m_TDesc.ContainerDuration); + return RESULT_FORMAT; + } + m_TDesc.ContainerDuration = duration_override; + } + return RESULT_OK; } @@ -425,11 +436,11 @@ ASDCP::TimedText::DCSubtitleParser::~DCSubtitleParser() // Opens the stream for reading, parses enough data to provide a complete // set of stream metadata for the MXFWriter below. ASDCP::Result_t -ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& filename) const +ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& filename, ui32_t d) const { const_cast(this)->m_Parser = new h__SubtitleParser; - Result_t result = m_Parser->OpenRead(filename); + Result_t result = m_Parser->OpenRead(filename, d); if ( ASDCP_FAILURE(result) ) const_cast(this)->m_Parser = 0; diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp index 7715b772..5e7b2c8d 100755 --- a/src/asdcp-wrap.cpp +++ b/src/asdcp-wrap.cpp @@ -154,6 +154,8 @@ Options:\n\ Defaults to 4,194,304 (4MB)\n\ -C
    - Set ChannelAssignment UL value in a PCM file\n\ -d - Number of frames to process, default all\n\ + Note: For timed-text MXFs, this option forces the\n\ + value for the Asset's intrinsic duration.\n\ -e - Encrypt MPEG or JP2K headers (default)\n\ -E - Do not encrypt MPEG or JP2K headers\n\ -f - Starting frame number, default 0\n\ @@ -1332,7 +1334,8 @@ write_timed_text_file(CommandOptions& Options) byte_t IV_buf[CBC_BLOCK_SIZE]; // set up essence parser - Result_t result = Parser.OpenRead(Options.filenames.front()); + Result_t result = Parser.OpenRead(Options.filenames.front(), + (Options.duration == 0xffffffff ? 0 : Options.duration)); // set up MXF writer if ( ASDCP_SUCCESS(result) ) From 07428823e0d9b04e3fabdb31298aaca7d2119482 Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:06:03 -0800 Subject: [PATCH 3/6] feature: emit timed text language in output --- src/AS_DCP.h | 1 + src/AS_DCP_TimedText.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index a6612264..d0c7f7bb 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1477,6 +1477,7 @@ namespace ASDCP { byte_t AssetID[UUIDlen]; std::string NamespaceName; std::string EncodingName; + std::string Language; ResourceList_t ResourceList; std::string RFC5646LanguageTagList; diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index b30a926d..fe435a8d 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -167,6 +167,9 @@ ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTe TDesc.EncodingName = TDescObj->UCSEncoding; TDesc.RFC5646LanguageTagList = TDescObj->RFC5646LanguageTagList; TDesc.ResourceList.clear(); + if (! TDescObj->RFC5646LanguageTagList.empty() ) { + TDesc.Language = TDescObj->RFC5646LanguageTagList.get(); + } Array::const_iterator sdi = TDescObj->SubDescriptors.begin(); TimedTextResourceSubDescriptor* DescObject = 0; From 827b1e3b7c953a17e89f8dac2fe5786bba74d67c Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Thu, 9 Feb 2023 18:41:41 -0800 Subject: [PATCH 4/6] feature: allow a faux timed text intrinsic duration --- src/AS_DCP.h | 2 +- src/TimedText_Parser.cpp | 31 +++++++++++++++++++++---------- src/asdcp-wrap.cpp | 5 ++++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index d0c7f7bb..b8589166 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1550,7 +1550,7 @@ namespace ASDCP { // Opens an XML file for reading, parses data to provide a complete // set of stream metadata for the MXFWriter below. - Result_t OpenRead(const std::string& filename) const; + Result_t OpenRead(const std::string& filename, ui32_t d=0) const; // Parses an XML document to provide a complete set of stream metadata // for the MXFWriter below. The optional filename argument is used to diff --git a/src/TimedText_Parser.cpp b/src/TimedText_Parser.cpp index 37883594..11a4fc86 100644 --- a/src/TimedText_Parser.cpp +++ b/src/TimedText_Parser.cpp @@ -112,7 +112,7 @@ class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser { XMLElement m_Root; ResourceTypeMap_t m_ResourceTypes; - Result_t OpenRead(); + Result_t OpenRead(ui32_t d=0); ASDCP_NO_COPY_CONSTRUCT(h__SubtitleParser); @@ -140,8 +140,8 @@ class ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser return m_DefaultResolver; } - Result_t OpenRead(const std::string& filename); - Result_t OpenRead(const std::string& xml_doc, const std::string& filename); + Result_t OpenRead(const std::string& filename, ui32_t duration_override=0); + Result_t OpenRead(const std::string& xml_doc, const std::string& filename, ui32_t duration_override=0); Result_t ReadAncillaryResource(const byte_t* uuid, FrameBuffer& FrameBuf, const IResourceResolver& Resolver) const; }; namespace { @@ -179,12 +179,12 @@ namespace { // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& filename) +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& filename, ui32_t duration_override) { Result_t result = ReadFileIntoString(filename, m_XMLDoc); if ( KM_SUCCESS(result) ) - result = OpenRead(); + result = OpenRead(duration_override); m_Filename = filename; return result; @@ -192,7 +192,7 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::strin // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const std::string& filename) +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::string& xml_doc, const std::string& filename, ui32_t duration_override) { m_XMLDoc = xml_doc; @@ -205,12 +205,12 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(const std::strin m_Filename = filename; } - return OpenRead(); + return OpenRead(duration_override); } // Result_t -ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() +ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead(ui32_t duration_override) { if ( ! m_Root.ParseString(m_XMLDoc) ) return RESULT_FORMAT; @@ -370,6 +370,17 @@ ASDCP::TimedText::DCSubtitleParser::h__SubtitleParser::OpenRead() m_TDesc.ContainerDuration = end_count - beginTC.GetFrames(); + if (duration_override) + { + if (duration_override < m_TDesc.ContainerDuration) + { + DefaultLogSink(). Error("Override Duration (%d) may not be less than the actual intrinsic duration (%d).\n", + duration_override, m_TDesc.ContainerDuration); + return RESULT_FORMAT; + } + m_TDesc.ContainerDuration = duration_override; + } + return RESULT_OK; } @@ -426,11 +437,11 @@ ASDCP::TimedText::DCSubtitleParser::~DCSubtitleParser() // Opens the stream for reading, parses enough data to provide a complete // set of stream metadata for the MXFWriter below. ASDCP::Result_t -ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& filename) const +ASDCP::TimedText::DCSubtitleParser::OpenRead(const std::string& filename, ui32_t d) const { const_cast(this)->m_Parser = new h__SubtitleParser; - Result_t result = m_Parser->OpenRead(filename); + Result_t result = m_Parser->OpenRead(filename, d); if ( ASDCP_FAILURE(result) ) const_cast(this)->m_Parser = 0; diff --git a/src/asdcp-wrap.cpp b/src/asdcp-wrap.cpp index fa75edeb..8bbcee29 100755 --- a/src/asdcp-wrap.cpp +++ b/src/asdcp-wrap.cpp @@ -160,6 +160,8 @@ Options:\n\ Defaults to 4,194,304 (4MB)\n\ -C
      - Set ChannelAssignment UL value in a PCM file\n\ -d - Number of frames to process, default all\n\ + Note: For timed-text MXFs, this option forces the\n\ + value for the Asset's intrinsic duration.\n\ -e - Encrypt MPEG or JP2K headers (default)\n\ -E - Do not encrypt MPEG or JP2K headers\n\ -f - Starting frame number, default 0\n\ @@ -1338,7 +1340,8 @@ write_timed_text_file(CommandOptions& Options) byte_t IV_buf[CBC_BLOCK_SIZE]; // set up essence parser - Result_t result = Parser.OpenRead(Options.filenames.front()); + Result_t result = Parser.OpenRead(Options.filenames.front(), + (Options.duration == 0xffffffff ? 0 : Options.duration)); // set up MXF writer if ( ASDCP_SUCCESS(result) ) From dc9e6599e8500586de13f5e4677aae4ec5ef8b10 Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Tue, 12 Dec 2023 20:34:05 -0800 Subject: [PATCH 5/6] update against current master --- src/AS_DCP.h | 1 - src/AS_DCP_TimedText.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index b8589166..7c46a1a2 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1477,7 +1477,6 @@ namespace ASDCP { byte_t AssetID[UUIDlen]; std::string NamespaceName; std::string EncodingName; - std::string Language; ResourceList_t ResourceList; std::string RFC5646LanguageTagList; diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index fe435a8d..b30a926d 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -167,9 +167,6 @@ ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTe TDesc.EncodingName = TDescObj->UCSEncoding; TDesc.RFC5646LanguageTagList = TDescObj->RFC5646LanguageTagList; TDesc.ResourceList.clear(); - if (! TDescObj->RFC5646LanguageTagList.empty() ) { - TDesc.Language = TDescObj->RFC5646LanguageTagList.get(); - } Array::const_iterator sdi = TDescObj->SubDescriptors.begin(); TimedTextResourceSubDescriptor* DescObject = 0; From 0fae90de76b3c62050c7497a051e47c57d4be3cf Mon Sep 17 00:00:00 2001 From: Matthew Sheby <44249925+msheby@users.noreply.github.com> Date: Tue, 12 Dec 2023 20:40:55 -0800 Subject: [PATCH 6/6] update against current master --- src/AS_DCP.h | 1 - src/AS_DCP_TimedText.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/AS_DCP.h b/src/AS_DCP.h index b8589166..7c46a1a2 100755 --- a/src/AS_DCP.h +++ b/src/AS_DCP.h @@ -1477,7 +1477,6 @@ namespace ASDCP { byte_t AssetID[UUIDlen]; std::string NamespaceName; std::string EncodingName; - std::string Language; ResourceList_t ResourceList; std::string RFC5646LanguageTagList; diff --git a/src/AS_DCP_TimedText.cpp b/src/AS_DCP_TimedText.cpp index fe435a8d..b30a926d 100644 --- a/src/AS_DCP_TimedText.cpp +++ b/src/AS_DCP_TimedText.cpp @@ -167,9 +167,6 @@ ASDCP::TimedText::MXFReader::h__Reader::MD_to_TimedText_TDesc(TimedText::TimedTe TDesc.EncodingName = TDescObj->UCSEncoding; TDesc.RFC5646LanguageTagList = TDescObj->RFC5646LanguageTagList; TDesc.ResourceList.clear(); - if (! TDescObj->RFC5646LanguageTagList.empty() ) { - TDesc.Language = TDescObj->RFC5646LanguageTagList.get(); - } Array::const_iterator sdi = TDescObj->SubDescriptors.begin(); TimedTextResourceSubDescriptor* DescObject = 0;