Add support for writing unformatted level 1 teletext to the EBU STL subtitle format

Originally committed to SVN as r6638.
This commit is contained in:
Thomas Goyne 2012-03-29 19:05:45 +00:00
parent 7335c520c1
commit 2d9213cdfc
4 changed files with 56 additions and 20 deletions

View File

@ -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);

View File

@ -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;

View File

@ -387,6 +387,7 @@
"Subtitle Format" : {
"EBU STL" : {
"Display Standard" : 0,
"Inclusive End Times" : true,
"Line Wrapping Mode" : 1,
"Max Line Length" : 42,

View File

@ -455,7 +455,7 @@ namespace
return reinterpret_cast<const char *>(str.wx_str());
}
std::string convert_subtitle_line(std::vector<EbuSubtitle>::const_iterator sub, agi::charset::IconvWrapper *encoder)
std::string convert_subtitle_line(std::vector<EbuSubtitle>::const_iterator sub, agi::charset::IconvWrapper *encoder, bool enable_formatting)
{
std::string fullstring;
for (std::vector<EbuTextRow>::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<EbuFormattedText>::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<agi::charset::IconvWrapper> 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<BlockTTI> tti;
tti.reserve(subs_list.size());
for (std::vector<EbuSubtitle>::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<size_t>(0, 50 - (10 * sub->text_rows.size()));
base.vp = std::min<uint8_t>(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)