From 2d9213cdfcdac0c08dfb7d15ad86a5e43ec5bb00 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 29 Mar 2012 19:05:45 +0000 Subject: [PATCH] Add support for writing unformatted level 1 teletext to the EBU STL subtitle format Originally committed to SVN as r6638. --- aegisub/src/dialog_export_ebu3264.cpp | 25 +++++++++++---- aegisub/src/dialog_export_ebu3264.h | 10 ++++++ aegisub/src/libresrc/default_config.json | 1 + aegisub/src/subtitle_format_ebu3264.cpp | 40 +++++++++++++++--------- 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/aegisub/src/dialog_export_ebu3264.cpp b/aegisub/src/dialog_export_ebu3264.cpp index d491360d9..ac3a0deb8 100644 --- a/aegisub/src/dialog_export_ebu3264.cpp +++ b/aegisub/src/dialog_export_ebu3264.cpp @@ -124,7 +124,6 @@ EbuExportConfigurationDialog::EbuExportConfigurationDialog(wxWindow *owner, EbuE }; wxRadioBox *tv_standard_box = new wxRadioBox(this, -1, _("TV standard"), wxDefaultPosition, wxDefaultSize, 6, tv_standards, 0, wxRA_SPECIFY_ROWS); - wxStaticBox *timecode_control_box = new wxStaticBox(this, -1, _("Time codes")); wxTextCtrl *timecode_offset_entry = new wxTextCtrl(this, -1, "00:00:00:00"); wxCheckBox *inclusive_end_times_check = new wxCheckBox(this, -1, _("Out-times are inclusive")); @@ -145,13 +144,20 @@ EbuExportConfigurationDialog::EbuExportConfigurationDialog(wxWindow *owner, EbuE _("Skip lines that are too long") }; - wxStaticBox *text_formatting_box = new wxStaticBox(this, -1, _("Text formatting")); wxSpinCtrl *max_line_length_ctrl = new wxSpinCtrl(this, -1, wxString(), wxDefaultPosition, wxSize(65, -1)); wxComboBox *wrap_mode_ctrl = new wxComboBox(this, -1, wrap_modes[0], wxDefaultPosition, wxDefaultSize, 4, wrap_modes, wxCB_DROPDOWN | wxCB_READONLY); wxCheckBox *translate_alignments_check = new wxCheckBox(this, -1, _("Translate alignments")); max_line_length_ctrl->SetRange(10, 99); + wxString display_standards[] = { + _("Open subtitles"), + _("Level-1 teletext"), + _("Level-2 teletext") + }; + + wxComboBox *display_standard_ctrl = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize, 2, display_standards, wxCB_DROPDOWN | wxCB_READONLY); + wxSizer *max_line_length_labelled = new wxBoxSizer(wxHORIZONTAL); max_line_length_labelled->Add(new wxStaticText(this, -1, _("Max. line length:")), 1, wxALIGN_CENTRE|wxRIGHT, 12); max_line_length_labelled->Add(max_line_length_ctrl, 0, 0, 0); @@ -160,18 +166,22 @@ EbuExportConfigurationDialog::EbuExportConfigurationDialog(wxWindow *owner, EbuE timecode_offset_labelled->Add(new wxStaticText(this, -1, _("Time code offset:")), 1, wxALIGN_CENTRE|wxRIGHT, 12); timecode_offset_labelled->Add(timecode_offset_entry, 0, 0, 0); - wxSizer *text_formatting_sizer = new wxStaticBoxSizer(text_formatting_box, wxVERTICAL); + wxSizer *text_formatting_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Text formatting")); text_formatting_sizer->Add(max_line_length_labelled, 0, wxEXPAND | (wxALL & ~wxTOP), 6); text_formatting_sizer->Add(wrap_mode_ctrl, 0, wxEXPAND | (wxALL & ~wxTOP), 6); text_formatting_sizer->Add(translate_alignments_check, 0, wxEXPAND | (wxALL & ~wxTOP), 6); - wxSizer *timecode_control_sizer = new wxStaticBoxSizer(timecode_control_box, wxVERTICAL); + wxSizer *timecode_control_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Time codes")); timecode_control_sizer->Add(timecode_offset_labelled, 0, wxEXPAND | (wxALL & ~wxTOP), 6); timecode_control_sizer->Add(inclusive_end_times_check, 0, wxEXPAND | (wxALL & ~wxTOP), 6); + wxSizer *display_standard_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Display standard")); + display_standard_sizer->Add(display_standard_ctrl, 0, wxEXPAND | (wxALL & ~wxTOP), 6); + wxSizer *left_column = new wxBoxSizer(wxVERTICAL); - left_column->Add(tv_standard_box, 0, wxEXPAND|wxBOTTOM, 6); - left_column->Add(timecode_control_sizer, 0, wxEXPAND, 0); + left_column->Add(tv_standard_box, 0, wxEXPAND | wxBOTTOM, 6); + left_column->Add(timecode_control_sizer, 0, wxEXPAND | wxBOTTOM, 6); + left_column->Add(display_standard_sizer, 0, wxEXPAND, 0); wxSizer *right_column = new wxBoxSizer(wxVERTICAL); right_column->Add(text_encoding_box, 0, wxEXPAND|wxBOTTOM, 6); @@ -203,6 +213,7 @@ EbuExportConfigurationDialog::EbuExportConfigurationDialog(wxWindow *owner, EbuE wrap_mode_ctrl->SetValidator(wxGenericValidator((int*)&s.line_wrapping_mode)); inclusive_end_times_check->SetValidator(wxGenericValidator(&s.inclusive_end_times)); timecode_offset_entry->SetValidator(TimecodeValidator(&s.timecode_offset)); + display_standard_ctrl->SetValidator(wxGenericValidator((int*)&s.display_standard)); } agi::vfr::Framerate EbuExportSettings::GetFramerate() const { @@ -237,6 +248,7 @@ EbuExportSettings::EbuExportSettings(std::string const& prefix) , line_wrapping_mode((LineWrappingMode)OPT_GET(prefix + "/Line Wrapping Mode")->GetInt()) , translate_alignments(OPT_GET(prefix + "/Translate Alignments")->GetBool()) , inclusive_end_times(OPT_GET(prefix + "/Inclusive End Times")->GetBool()) +, display_standard((DisplayStandard)OPT_GET(prefix + "/Display Standard")->GetInt()) { timecode_offset.h = OPT_GET(prefix + "/Timecode Offset/H")->GetInt(); timecode_offset.m = OPT_GET(prefix + "/Timecode Offset/M")->GetInt(); @@ -251,6 +263,7 @@ void EbuExportSettings::Save() const { OPT_SET(prefix + "/Line Wrapping Mode")->SetInt(line_wrapping_mode); OPT_SET(prefix + "/Translate Alignments")->SetBool(translate_alignments); OPT_SET(prefix + "/Inclusive End Times")->SetBool(inclusive_end_times); + OPT_SET(prefix + "/Display Standard")->SetInt(display_standard); OPT_SET(prefix + "/Timecode Offset/H")->SetInt(timecode_offset.h); OPT_SET(prefix + "/Timecode Offset/M")->SetInt(timecode_offset.m); OPT_SET(prefix + "/Timecode Offset/S")->SetInt(timecode_offset.s); diff --git a/aegisub/src/dialog_export_ebu3264.h b/aegisub/src/dialog_export_ebu3264.h index 18ee2bccb..39da9723a 100644 --- a/aegisub/src/dialog_export_ebu3264.h +++ b/aegisub/src/dialog_export_ebu3264.h @@ -67,6 +67,13 @@ public: IgnoreOverLength = 3 ///< Skip overly-long lines }; + /// Types of subtitles/captions that can be stored in STL files + enum DisplayStandard { + DSC_Open = 0, ///< Open subtitles + DSC_Level1 = 1, ///< Level-1 teletext closed captions + DSC_Level2 = 2 ///< Level-2 teletext closed captions + }; + /// Which TV standard (frame rate + timecode encoding) to use TvStandard tv_standard; @@ -88,6 +95,9 @@ public: /// Are end timecodes inclusive or exclusive? bool inclusive_end_times; + /// Save as subtitles, or as closed captions? + DisplayStandard display_standard; + /// Get the frame rate for the current TV Standard agi::vfr::Framerate GetFramerate() const; diff --git a/aegisub/src/libresrc/default_config.json b/aegisub/src/libresrc/default_config.json index 259627e6f..f6e5a0b11 100644 --- a/aegisub/src/libresrc/default_config.json +++ b/aegisub/src/libresrc/default_config.json @@ -387,6 +387,7 @@ "Subtitle Format" : { "EBU STL" : { + "Display Standard" : 0, "Inclusive End Times" : true, "Line Wrapping Mode" : 1, "Max Line Length" : 42, diff --git a/aegisub/src/subtitle_format_ebu3264.cpp b/aegisub/src/subtitle_format_ebu3264.cpp index 1dd8c0312..ee5e3e6be 100644 --- a/aegisub/src/subtitle_format_ebu3264.cpp +++ b/aegisub/src/subtitle_format_ebu3264.cpp @@ -455,7 +455,7 @@ namespace return reinterpret_cast(str.wx_str()); } - std::string convert_subtitle_line(std::vector::const_iterator sub, agi::charset::IconvWrapper *encoder) + std::string convert_subtitle_line(std::vector::const_iterator sub, agi::charset::IconvWrapper *encoder, bool enable_formatting) { std::string fullstring; for (std::vector::const_iterator row = sub->text_rows.begin(); row != sub->text_rows.end(); ++row) @@ -464,14 +464,17 @@ namespace bool underline = false, italic = false; for (std::vector::const_iterator block = row->begin(); block != row->end(); ++block) { - // insert codes for changed formatting - if (underline != block->underline) - fullstring += EBU_FORMAT_UNDERLINE[block->underline]; - if (italic != block->italic) - fullstring += EBU_FORMAT_ITALIC[block->italic]; + if (enable_formatting) + { + // insert codes for changed formatting + if (underline != block->underline) + fullstring += EBU_FORMAT_UNDERLINE[block->underline]; + if (italic != block->italic) + fullstring += EBU_FORMAT_ITALIC[block->italic]; - underline = block->underline; - italic = block->italic; + underline = block->underline; + italic = block->italic; + } // convert text to specified encoding fullstring += encoder->Convert(std::string(wx_str(block->text), buffer_size(block->text))); @@ -500,13 +503,22 @@ namespace agi::scoped_ptr encoder(export_settings.GetTextEncoder()); agi::vfr::Framerate fps = export_settings.GetFramerate(); + // Teletext captions are 1-23; Open subtitles are 0-99 + uint8_t min_row = 0; + uint8_t max_row = 100; + if (export_settings.display_standard != EbuExportSettings::DSC_Open) { + min_row = 1; + max_row = 24; + } + uint16_t subtitle_number = 0; std::vector tti; tti.reserve(subs_list.size()); for (std::vector::const_iterator sub = subs_list.begin(); sub != subs_list.end(); ++sub) { - std::string fullstring = convert_subtitle_line(sub, encoder.get()); + std::string fullstring = convert_subtitle_line(sub, encoder.get(), + export_settings.display_standard == EbuExportSettings::DSC_Open); // construct a base block that can be copied and filled BlockTTI base; @@ -523,17 +535,17 @@ namespace { // vertical position if (sub->vertical_position == EbuSubtitle::PositionTop) - base.vp = 0; + base.vp = min_row; else if (sub->vertical_position == EbuSubtitle::PositionMiddle) - base.vp = std::min(0, 50 - (10 * sub->text_rows.size())); + base.vp = std::min(min_row, max_row / 2 - (max_row / 5 * sub->text_rows.size())); else //if (sub->vertical_position == EbuSubtitle::PositionBottom) - base.vp = 99; + base.vp = max_row - 1; base.jc = sub->justification_code; } else { - base.vp = 99; + base.vp = max_row - 1; base.jc = EbuSubtitle::JustifyCentre; } @@ -591,7 +603,7 @@ namespace memcpy(gsi.dfc, "STL25.01", 8); break; } - gsi.dsc = '0'; // open subtitling + gsi.dsc = '0' + (int)export_settings.display_standard; gsi.cct[0] = '0'; gsi.cct[1] = '0' + (int)export_settings.text_encoding; if (export_settings.text_encoding == EbuExportSettings::utf8)