diff options
| author | Carl Hetherington <cth@carlh.net> | 2026-01-01 00:42:05 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2026-01-01 00:42:05 +0100 |
| commit | cf2b75373d6908f97bd9c25ce24ffdd9685545f5 (patch) | |
| tree | ec9015e18ab461ee2ab694c090d3ecbd0b61ac7e /src | |
| parent | 2567be677682e96d5cb7de31dbdcea80111ac8f4 (diff) | |
Allow export of Interop/SMPTE format subtitles (#3025).
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/subtitle_film_encoder.cc | 39 | ||||
| -rw-r--r-- | src/lib/subtitle_film_encoder.h | 11 | ||||
| -rw-r--r-- | src/tools/dcpomatic.cc | 12 | ||||
| -rw-r--r-- | src/wx/export_subtitles_dialog.cc | 64 | ||||
| -rw-r--r-- | src/wx/export_subtitles_dialog.h | 8 |
5 files changed, 107 insertions, 27 deletions
diff --git a/src/lib/subtitle_film_encoder.cc b/src/lib/subtitle_film_encoder.cc index 6130ce194..4a29ebcfa 100644 --- a/src/lib/subtitle_film_encoder.cc +++ b/src/lib/subtitle_film_encoder.cc @@ -49,19 +49,28 @@ using namespace boost::placeholders; * @param initial_name Hint that may be used to create filenames, if @ref output is a directory. * @param include_font true to refer to and export any font file (for Interop; ignored for SMPTE). */ -SubtitleFilmEncoder::SubtitleFilmEncoder(shared_ptr<const Film> film, shared_ptr<Job> job, boost::filesystem::path output, string initial_name, bool split_reels, bool include_font) +SubtitleFilmEncoder::SubtitleFilmEncoder( + shared_ptr<const Film> film, + shared_ptr<Job> job, + boost::filesystem::path output, + string initial_name, + bool split_reels, + bool include_font, + dcp::Standard standard + ) : FilmEncoder(film, job) , _split_reels(split_reels) , _include_font(include_font) , _reel_index(0) , _length(film->length()) + , _standard(standard) { _player.set_play_referenced(); _player.set_ignore_video(); _player.set_ignore_audio(); _player.Text.connect(boost::bind(&SubtitleFilmEncoder::text, this, _1, _2, _3, _4)); - string const extension = film->interop() ? ".xml" : ".mxf"; + string const extension = standard == dcp::Standard::INTEROP ? ".xml" : ".mxf"; int const files = split_reels ? film->reels().size() : 1; for (int i = 0; i < files; ++i) { @@ -105,20 +114,27 @@ SubtitleFilmEncoder::go() for (auto& i: _assets) { if (!i.first) { /* No subtitles arrived for this asset; make an empty one so we write something to the output */ - if (_film->interop()) { + switch (_standard) { + case dcp::Standard::INTEROP: + { auto s = make_shared<dcp::InteropTextAsset>(); s->set_movie_title(_film->name()); s->set_reel_number(fmt::to_string(reel + 1)); i.first = s; - } else { + break; + } + case dcp::Standard::SMPTE: + { auto s = make_shared<dcp::SMPTETextAsset>(); s->set_content_title_text(_film->name()); s->set_reel_number(reel + 1); i.first = s; + break; + } } } - if (!_film->interop() || _include_font) { + if (_standard == dcp::Standard::SMPTE || _include_font) { for (auto j: _player.get_subtitle_fonts()) { i.first->add_font(j->id(), j->data().get_value_or(_default_font)); } @@ -140,7 +156,9 @@ SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional<DCPTextTrack> if (!_assets[_reel_index].first) { shared_ptr<dcp::TextAsset> asset; auto const lang = _film->open_text_languages(); - if (_film->interop()) { + switch (_standard) { + case dcp::Standard::INTEROP: + { auto s = make_shared<dcp::InteropTextAsset>(); s->set_movie_title(_film->name()); if (lang.first) { @@ -148,7 +166,10 @@ SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional<DCPTextTrack> } s->set_reel_number(fmt::to_string(_reel_index + 1)); _assets[_reel_index].first = s; - } else { + break; + } + case dcp::Standard::SMPTE: + { auto s = make_shared<dcp::SMPTETextAsset>(); s->set_content_title_text(_film->name()); if (lang.first) { @@ -164,6 +185,8 @@ SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional<DCPTextTrack> s->set_key(_film->key()); } _assets[_reel_index].first = s; + break; + } } } @@ -171,7 +194,7 @@ SubtitleFilmEncoder::text(PlayerText subs, TextType type, optional<DCPTextTrack> /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ i.set_in (i.in()); i.set_out(i.out()); - if (_film->interop() && !_include_font) { + if (_standard == dcp::Standard::INTEROP && !_include_font) { i.unset_font(); } _assets[_reel_index].first->add(make_shared<dcp::TextString>(i)); diff --git a/src/lib/subtitle_film_encoder.h b/src/lib/subtitle_film_encoder.h index e2b6dd208..0fbb830c3 100644 --- a/src/lib/subtitle_film_encoder.h +++ b/src/lib/subtitle_film_encoder.h @@ -39,7 +39,15 @@ class Film; class SubtitleFilmEncoder : public FilmEncoder { public: - SubtitleFilmEncoder(std::shared_ptr<const Film> film, std::shared_ptr<Job> job, boost::filesystem::path output, std::string initial_name, bool split_reels, bool include_font); + SubtitleFilmEncoder( + std::shared_ptr<const Film> film, + std::shared_ptr<Job> job, + boost::filesystem::path output, + std::string initial_name, + bool split_reels, + bool include_font, + dcp::Standard standard + ); void go() override; @@ -60,5 +68,6 @@ private: int _reel_index; boost::optional<dcpomatic::DCPTime> _last; dcpomatic::DCPTime _length; + dcp::Standard _standard; dcp::ArrayData _default_font; }; diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index aaf1040d4..f41a7edc4 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -1061,8 +1061,16 @@ private: } auto job = make_shared<TranscodeJob>(_film, TranscodeJob::ChangedBehaviour::EXAMINE_THEN_STOP); job->set_encoder( - make_shared<SubtitleFilmEncoder>(_film, job, dialog.path(), _film->isdcf_name(true), dialog.split_reels(), dialog.include_font()) - ); + make_shared<SubtitleFilmEncoder>( + _film, + job, + dialog.path(), + _film->isdcf_name(true), + dialog.split_reels(), + dialog.include_font(), + dialog.standard() + ) + ); JobManager::instance()->add(job); } diff --git a/src/wx/export_subtitles_dialog.cc b/src/wx/export_subtitles_dialog.cc index 73ddd9d6c..92cac77cc 100644 --- a/src/wx/export_subtitles_dialog.cc +++ b/src/wx/export_subtitles_dialog.cc @@ -20,6 +20,7 @@ #include "check_box.h" +#include "dcpomatic_choice.h" #include "export_subtitles_dialog.h" #include "file_picker_ctrl.h" #include "wx_util.h" @@ -36,11 +37,19 @@ using boost::bind; ExportSubtitlesDialog::ExportSubtitlesDialog(wxWindow* parent, int reels, bool interop) : wxDialog(parent, wxID_ANY, _("Export subtitles")) - , _interop(interop) { auto sizer = new wxGridBagSizer(DCPOMATIC_SIZER_GAP, DCPOMATIC_SIZER_GAP); int r = 0; + + add_label_to_sizer(sizer, this, _("Format"), true, wxGBPosition(r, 0)); + _format = new Choice(this); + _format->add_entry(_("XML (Interop)")); + _format->add_entry(_("MXF (SMPTE)")); + _format->set(interop ? 0 : 1); + sizer->Add(_format, wxGBPosition(r, 1)); + ++r; + _split_reels = new CheckBox(this, _("Write reels into separate files")); sizer->Add(_split_reels, wxGBPosition(r, 0), wxGBSpan(1, 2)); ++r; @@ -53,23 +62,16 @@ ExportSubtitlesDialog::ExportSubtitlesDialog(wxWindow* parent, int reels, bool i sizer->Add(_include_font, wxGBPosition(r, 0), wxGBSpan(1, 2)); ++r; - if (!_interop) { - _include_font->Enable(false); - } - - wxString const wildcard = _interop ? _("Subtitle files (.xml)|*.xml") : _("Subtitle files (.mxf)|*.mxf"); - - _file_label = new wxStaticText(this, wxID_ANY, _("Output file")); - sizer->Add(_file_label, wxGBPosition(r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); - _file = new FilePickerCtrl(this, _("Select output file"), wildcard, false, true, "ExportSubtitlesPath"); + _file_label = add_label_to_sizer(sizer, this, _("Output file"), true, wxGBPosition(r, 0)); + _file = new FilePickerCtrl(this, _("Select output file"), wxT(""), false, true, "ExportSubtitlesPath"); sizer->Add(_file, wxGBPosition(r, 1)); ++r; - _dir_label = new wxStaticText(this, wxID_ANY, (_("Output folder"))); - sizer->Add(_dir_label, wxGBPosition(r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + _dir_label = add_label_to_sizer(sizer, this, _("Output folder"), true, wxGBPosition(r, 0)); _dir = new DirPickerCtrl(this); sizer->Add(_dir, wxGBPosition(r, 1)); + _format->bind(&ExportSubtitlesDialog::format_changed, this); _split_reels->bind(&ExportSubtitlesDialog::setup_sensitivity, this); _include_font->bind(&ExportSubtitlesDialog::setup_sensitivity, this); _file->Bind(wxEVT_FILEPICKER_CHANGED, bind(&ExportSubtitlesDialog::setup_sensitivity, this)); @@ -85,13 +87,45 @@ ExportSubtitlesDialog::ExportSubtitlesDialog(wxWindow* parent, int reels, bool i SetSizerAndFit(overall_sizer); setup_sensitivity(); + setup_wildcard(); +} + + +void +ExportSubtitlesDialog::format_changed() +{ + setup_sensitivity(); + setup_wildcard(); +} + + +void +ExportSubtitlesDialog::setup_wildcard() +{ + _file->set_wildcard(standard() == dcp::Standard::INTEROP ? _("Subtitle files (.xml)|*.xml") : _("Subtitle files (.mxf)|*.mxf")); +} + + +dcp::Standard +ExportSubtitlesDialog::standard() const +{ + switch (_format->get().get_value_or(0)) { + case 0: + return dcp::Standard::INTEROP; + case 1: + return dcp::Standard::SMPTE; + } + + DCPOMATIC_ASSERT(false); + return dcp::Standard::SMPTE; } void ExportSubtitlesDialog::setup_sensitivity() { - bool const multi = split_reels() || (_interop && _include_font->GetValue()); + bool const multi = split_reels() || (standard() == dcp::Standard::INTEROP && _include_font->GetValue()); + _include_font->Enable(standard() == dcp::Standard::INTEROP); _file_label->Enable(!multi); _file->Enable(!multi); _dir_label->Enable(multi); @@ -112,7 +146,7 @@ ExportSubtitlesDialog::path() const if (_file->IsEnabled()) { if (auto path = _file->path()) { wxFileName fn(std_to_wx(path->string())); - fn.SetExt(char_to_wx(_interop ? "xml" : "mxf")); + fn.SetExt(char_to_wx(standard() == dcp::Standard::INTEROP ? "xml" : "mxf")); return wx_to_std(fn.GetFullPath()); } } @@ -131,6 +165,6 @@ ExportSubtitlesDialog::split_reels() const bool ExportSubtitlesDialog::include_font() const { - return !_interop || _include_font->GetValue(); + return standard() == dcp::Standard::SMPTE || _include_font->GetValue(); } diff --git a/src/wx/export_subtitles_dialog.h b/src/wx/export_subtitles_dialog.h index 282c8884e..6c18555c0 100644 --- a/src/wx/export_subtitles_dialog.h +++ b/src/wx/export_subtitles_dialog.h @@ -20,6 +20,7 @@ #include "dir_picker_ctrl.h" +#include <dcp/types.h> #include <dcp/warnings.h> LIBDCP_DISABLE_WARNINGS #include <wx/wx.h> @@ -28,22 +29,27 @@ LIBDCP_ENABLE_WARNINGS class CheckBox; +class Choice; class FilePickerCtrl; class ExportSubtitlesDialog : public wxDialog { public: + /** @param interop true to default to XML export, otherwise MXF */ ExportSubtitlesDialog(wxWindow* parent, int reels, bool interop); boost::filesystem::path path() const; bool split_reels() const; bool include_font() const; + dcp::Standard standard() const; private: + void format_changed(); void setup_sensitivity(); + void setup_wildcard(); - bool _interop; + Choice* _format; CheckBox* _split_reels; CheckBox* _include_font = nullptr; wxStaticText* _file_label; |
