From: Carl Hetherington Date: Thu, 26 Mar 2020 22:03:23 +0000 (+0000) Subject: Another solution to binary STL subs that are too big for a single TTI block. X-Git-Tag: v1.4.21 X-Git-Url: https://main.carlh.net/gitweb/?p=libsub.git;a=commitdiff_plain;h=82f9ab96faeef0eb684c357d76d27f3737cf1d55 Another solution to binary STL subs that are too big for a single TTI block. --- diff --git a/src/stl_binary_writer.cc b/src/stl_binary_writer.cc index baed8d8..a96aea9 100644 --- a/src/stl_binary_writer.cc +++ b/src/stl_binary_writer.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ using std::setw; using std::setfill; using std::max; using std::cout; +using std::vector; using boost::locale::conv::utf_to_utf; using boost::optional; using namespace sub; @@ -129,27 +131,165 @@ vertical_position (sub::Line const & line) return vp; } +vector +make_tti_blocks (list const& subtitles, STLBinaryTables const& tables, float frames_per_second) +{ + static int const tti_size = 128; + vector tti; + + /* Buffer to build the TTI blocks in */ + char buffer[tti_size]; + + BOOST_FOREACH (Subtitle const& i, subtitles) { + + /* Find the top vertical position of this subtitle */ + optional top; + BOOST_FOREACH (Line const& j, i.lines) { + int const vp = vertical_position (j); + if (!top || vp < top.get ()) { + top = vp; + } + } + + /* Work out the text */ + string text; + bool italic = false; + bool underline = false; + optional last_vp; + + BOOST_FOREACH (Line const& j, i.lines) { + + /* CR/LF down to this line */ + int const vp = vertical_position (j); + + if (last_vp) { + for (int k = last_vp.get(); k < vp; ++k) { + text += "\x8A"; + } + } + + last_vp = vp; + + BOOST_FOREACH (Block const& k, j.blocks) { + if (k.underline && !underline) { + text += "\x82"; + underline = true; + } else if (underline && !k.underline) { + text += "\x83"; + underline = false; + } + if (k.italic && !italic) { + text += "\x80"; + italic = true; + } else if (italic && !k.italic) { + text += "\x81"; + italic = false; + } + + text += utf16_to_iso6937 (utf_to_utf (k.text)); + } + } + + /* Turn italic/underline off before the end of this subtitle */ + if (underline) { + text += "\x83"; + } + if (italic) { + text += "\x81"; + } + + /* Make sure there's at least one end-of-line */ + text += "\x8F"; + + /* Now write this text in 112 byte chunks (TTI blocks). Only the first TTI + block's cumulative status, timecodes, vertical position, justification code + and comment flag are taken into account by the reader. + */ + + /* Set up the first part of the block */ + + /* XXX: these should increment, surely! */ + /* Subtitle group number */ + put_int_as_int (buffer + 0, 1, 1); + /* Subtitle number */ + put_int_as_int (buffer + 1, 0, 2); + /* Cumulative status */ + put_int_as_int (buffer + 4, tables.cumulative_status_enum_to_file (CUMULATIVE_STATUS_NOT_CUMULATIVE), 1); + /* Time code in */ + put_int_as_int (buffer + 5, i.from.hours(), 1); + put_int_as_int (buffer + 6, i.from.minutes(), 1); + put_int_as_int (buffer + 7, i.from.seconds(), 1); + put_int_as_int (buffer + 8, i.from.frames_at(sub::Rational(frames_per_second * 1000, 1000)), 1); + /* Time code out */ + put_int_as_int (buffer + 9, i.to.hours(), 1); + put_int_as_int (buffer + 10, i.to.minutes(), 1); + put_int_as_int (buffer + 11, i.to.seconds(), 1); + put_int_as_int (buffer + 12, i.to.frames_at(sub::Rational(frames_per_second * 1000, 1000)), 1); + /* Vertical position */ + put_int_as_int (buffer + 13, top.get(), 1); + + /* Justification code */ + /* XXX: this assumes the first line has the right value */ + switch (i.lines.front().horizontal_position.reference) { + case LEFT_OF_SCREEN: + put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_LEFT), 1); + break; + case HORIZONTAL_CENTRE_OF_SCREEN: + put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_CENTRE), 1); + break; + case RIGHT_OF_SCREEN: + put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_RIGHT), 1); + break; + } + + /* Comment flag */ + put_int_as_int (buffer + 15, tables.comment_enum_to_file (COMMENT_NO), 1); + + /* Now make as many blocks as are needed to add all the text */ + size_t const block_size = 112; + size_t offset = 0; + int block_number = 0; + while (offset < text.length()) { + size_t this_time = std::min(block_size, text.length() - offset); + put_string (buffer + 16, text.substr(offset, this_time) + string(block_size - this_time, '\x8f')); + offset += this_time; + + /* Extension block number. Count up from 0 but use 0xff for the last one */ + put_int_as_int (buffer + 3, this_time < block_size ? 0xff : block_number, 1); + ++block_number; + + char* finished = new char[tti_size]; + memcpy (finished, buffer, tti_size); + tti.push_back (finished); + } + } + + return tti; +} + + + /** @param language ISO 3-character country code for the language of the subtitles */ -void + void sub::write_stl_binary ( - list subtitles, - float frames_per_second, - Language language, - string original_programme_title, - string original_episode_title, - string translated_programme_title, - string translated_episode_title, - string translator_name, - string translator_contact_details, - string creation_date, - string revision_date, - int revision_number, - string country_of_origin, - string publisher, - string editor_name, - string editor_contact_details, - boost::filesystem::path file_name - ) + list subtitles, + float frames_per_second, + Language language, + string original_programme_title, + string original_episode_title, + string translated_programme_title, + string translated_episode_title, + string translator_name, + string translator_contact_details, + string creation_date, + string revision_date, + int revision_number, + string country_of_origin, + string publisher, + string editor_name, + string editor_contact_details, + boost::filesystem::path file_name + ) { SUB_ASSERT (original_programme_title.size() <= 32); SUB_ASSERT (original_episode_title.size() <= 32); @@ -165,9 +305,8 @@ sub::write_stl_binary ( SUB_ASSERT (editor_name.size() <= 32); SUB_ASSERT (editor_contact_details.size() <= 32); - char* buffer = new char[1024]; + char buffer[1024]; memset (buffer, 0, 1024); - ofstream output (file_name.string().c_str ()); STLBinaryTables tables; /* Find the longest subtitle in characters */ @@ -184,6 +323,8 @@ sub::write_stl_binary ( } } + vector tti_blocks = make_tti_blocks (subtitles, tables, frames_per_second); + /* Code page: 850 */ put_string (buffer + 0, "850"); /* Disk format code */ @@ -205,7 +346,7 @@ sub::write_stl_binary ( put_string (buffer + 230, revision_date); put_int_as_string (buffer + 236, revision_number, 2); /* TTI blocks */ - put_int_as_string (buffer + 238, subtitles.size(), 5); + put_int_as_string (buffer + 238, tti_blocks.size(), 5); /* Total number of subtitles */ put_int_as_string (buffer + 243, subtitles.size(), 5); /* Total number of subtitle groups */ @@ -229,122 +370,10 @@ sub::write_stl_binary ( put_string (buffer + 309, 32, editor_name); put_string (buffer + 341, 32, editor_contact_details); + ofstream output (file_name.string().c_str()); output.write (buffer, 1024); - - BOOST_FOREACH (Subtitle const& i, subtitles) { - - /* Find the top vertical position of this subtitle */ - optional top; - BOOST_FOREACH (Line const& j, i.lines) { - int const vp = vertical_position (j); - if (!top || vp < top.get ()) { - top = vp; - } - } - - memset (buffer, 0, 128); - - /* XXX: these should increment, surely! */ - /* Subtitle group number */ - put_int_as_int (buffer + 0, 1, 1); - /* Subtitle number */ - put_int_as_int (buffer + 1, 0, 2); - /* Extension block number. Use 0xff here to indicate that it is the last TTI - block in this subtitle "set", as we only ever use one. - */ - put_int_as_int (buffer + 3, 255, 1); - /* Cumulative status */ - put_int_as_int (buffer + 4, tables.cumulative_status_enum_to_file (CUMULATIVE_STATUS_NOT_CUMULATIVE), 1); - /* Time code in */ - put_int_as_int (buffer + 5, i.from.hours(), 1); - put_int_as_int (buffer + 6, i.from.minutes(), 1); - put_int_as_int (buffer + 7, i.from.seconds(), 1); - put_int_as_int (buffer + 8, i.from.frames_at(sub::Rational(frames_per_second * 1000, 1000)), 1); - /* Time code out */ - put_int_as_int (buffer + 9, i.to.hours(), 1); - put_int_as_int (buffer + 10, i.to.minutes(), 1); - put_int_as_int (buffer + 11, i.to.seconds(), 1); - put_int_as_int (buffer + 12, i.to.frames_at(sub::Rational(frames_per_second * 1000, 1000)), 1); - /* Vertical position */ - put_int_as_int (buffer + 13, top.get(), 1); - - /* Justification code */ - /* XXX: this assumes the first line has the right value */ - switch (i.lines.front().horizontal_position.reference) { - case LEFT_OF_SCREEN: - put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_LEFT), 1); - break; - case HORIZONTAL_CENTRE_OF_SCREEN: - put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_CENTRE), 1); - break; - case RIGHT_OF_SCREEN: - put_int_as_int (buffer + 14, tables.justification_enum_to_file (JUSTIFICATION_RIGHT), 1); - break; - } - - /* Comment flag */ - put_int_as_int (buffer + 15, tables.comment_enum_to_file (COMMENT_NO), 1); - - /* Text */ - string text; - bool italic = false; - bool underline = false; - optional last_vp; - - BOOST_FOREACH (Line const& j, i.lines) { - - /* CR/LF down to this line */ - int const vp = vertical_position (j); - - if (last_vp) { - for (int k = last_vp.get(); k < vp; ++k) { - text += "\x8A"; - } - } - - last_vp = vp; - - BOOST_FOREACH (Block const& k, j.blocks) { - if (k.underline && !underline) { - text += "\x82"; - underline = true; - } else if (underline && !k.underline) { - text += "\x83"; - underline = false; - } - if (k.italic && !italic) { - text += "\x80"; - italic = true; - } else if (italic && !k.italic) { - text += "\x81"; - italic = false; - } - - text += utf16_to_iso6937 (utf_to_utf (k.text)); - } - } - - /* Turn italic/underline off before the end of this subtitle */ - - if (underline) { - text += "\x83"; - } - - if (italic) { - text += "\x81"; - } - - if (text.length() > 111) { - text = text.substr (111); - } - - while (text.length() < 112) { - text += "\x8F"; - } - - put_string (buffer + 16, text); - output.write (buffer, 128); + BOOST_FOREACH (char* i, tti_blocks) { + output.write (i, 128); + delete[] i; } - - delete[] buffer; } diff --git a/test/dcp_to_stl_binary_test.cc b/test/dcp_to_stl_binary_test.cc index ade17f8..58e024b 100644 --- a/test/dcp_to_stl_binary_test.cc +++ b/test/dcp_to_stl_binary_test.cc @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE (dcp_to_stl_binary_test8) "GBR", "", "", "", - "build/test/test3.stl" + "build/test/91a30f25-b415-4ffe-9623-bdae43a381d3_sub.stl" ); check_file (