diff options
| -rw-r--r-- | cscript | 4 | ||||
| -rwxr-xr-x | run/tests | 2 | ||||
| -rw-r--r-- | src/lib/create_cli.cc | 32 | ||||
| -rw-r--r-- | src/lib/create_cli.h | 1 | ||||
| -rw-r--r-- | src/lib/dcp_subtitle_content.cc | 13 | ||||
| -rw-r--r-- | src/lib/dcpomatic_socket.cc | 8 | ||||
| -rw-r--r-- | src/lib/hints.cc | 107 | ||||
| -rw-r--r-- | src/lib/util.cc | 22 | ||||
| -rw-r--r-- | src/lib/util.h | 1 | ||||
| -rw-r--r-- | src/tools/dcpomatic_verifier.cc | 2 | ||||
| -rw-r--r-- | src/wx/controls.cc | 2 | ||||
| -rw-r--r-- | src/wx/standard_controls.cc | 1 | ||||
| -rw-r--r-- | src/wx/supporters.cc | 1 | ||||
| -rw-r--r-- | src/wx/verify_dcp_result_panel.cc | 8 | ||||
| -rw-r--r-- | src/wx/wx_util.cc | 212 | ||||
| -rw-r--r-- | src/wx/wx_util.h | 76 | ||||
| -rw-r--r-- | test/create_cli_test.cc | 16 | ||||
| m--------- | test/data | 0 | ||||
| -rw-r--r-- | test/hints_test.cc | 33 | ||||
| -rw-r--r-- | test/render_subtitles_test.cc | 7 | ||||
| -rw-r--r-- | test/test.cc | 7 | ||||
| -rw-r--r-- | test/test.h | 1 | ||||
| -rw-r--r-- | test/util_test.cc | 18 |
23 files changed, 333 insertions, 241 deletions
@@ -506,7 +506,7 @@ def build_with_cpp17(target): def dependencies(target, options): - deps = [('libdcp', 'v1.10.55', {'c++17': build_with_cpp17(target)})] + deps = [('libdcp', 'b47f0559041040495a08eb0b5cc2d62068d83952', {'c++17': build_with_cpp17(target)})] deps.append(('libsub', 'v1.6.59')) deps.append(('leqm-nrt', 'd75d0af984d9c14bfefca8f1bdbc215c3bf3a388')) if target.platform != 'linux' or target.distro != 'arch': @@ -529,7 +529,7 @@ option_defaults = { "gui": True, "variant": None } def build_tests(target): # Currently we only build tests on macOS, Windows, some Ubuntu versions and Arch return ( - (target.platform == 'linux' and target.distro == 'ubuntu' and target.version in ['18.04', '22.04', '24.04', '25.10']) or + (target.platform == 'linux' and target.distro == 'ubuntu' and target.version in ['18.04', '22.04', '24.04', '26.04']) or (target.platform == 'linux' and target.distro == 'arch') or (target.platform == 'osx') or (target.platform == 'windows') @@ -3,7 +3,7 @@ # e.g. --run_tests=foo set -e -PRIVATE_GIT="805027eb2f6d4b1cbacedd77272cf66b1c06ac98" +PRIVATE_GIT="d64f166137a3f2ee5c950f112e48e52fd982f781" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $DIR/environment diff --git a/src/lib/create_cli.cc b/src/lib/create_cli.cc index 32834be23..3ef61fe11 100644 --- a/src/lib/create_cli.cc +++ b/src/lib/create_cli.cc @@ -85,6 +85,8 @@ help() " --left-eye next piece of content is for the left eye\n" " --right-eye next piece of content is for the right eye\n" " --auto-crop next piece of content should be auto-cropped\n" + " --fill-crop next piece of content should be cropped to fit the container\n" + " (e.g. to crop the letterboxing from a scope-in-flat image)\n" " --colourspace next piece of content is in the given colourspace: " + colour_conversions + "\n" " --colorspace same as --colourspace\n" " --channel <channel> next piece of content should be mapped to audio channel L, R, C, Lfe, Ls, Rs, BsL, BsR, HI, VI\n" @@ -184,6 +186,7 @@ CreateCLI::CreateCLI(int argc, char* argv[]) optional<string> next_colour_conversion; auto next_frame_type = VideoFrameType::TWO_D; auto next_auto_crop = false; + auto next_fill_crop = false; optional<dcp::Channel> channel; optional<float> gain; optional<float> fade_in; @@ -225,6 +228,9 @@ CreateCLI::CreateCLI(int argc, char* argv[]) } else if (a == "--auto-crop") { next_auto_crop = true; claimed = true; + } else if (a == "--fill-crop") { + next_fill_crop = true; + claimed = true; } else if (a == "--twok") { _twok = true; claimed = true; @@ -331,6 +337,7 @@ CreateCLI::CreateCLI(int argc, char* argv[]) c.path = a; c.frame_type = next_frame_type; c.auto_crop = next_auto_crop; + c.fill_crop = next_fill_crop; c.colour_conversion = next_colour_conversion; c.channel = channel; c.gain = gain; @@ -341,6 +348,7 @@ CreateCLI::CreateCLI(int argc, char* argv[]) content.push_back(c); next_frame_type = VideoFrameType::TWO_D; next_auto_crop = false; + next_fill_crop = false; next_colour_conversion = {}; channel = {}; gain = {}; @@ -555,6 +563,30 @@ CreateCLI::make_film(function<void (string)> error) const video->set_crop(crop); } + if (cli_content.fill_crop && video->size()) { + auto const source_ratio = video->size()->ratio(); + Crop crop; + if (source_ratio < film->container().ratio()) { + /* Part to extract is wider than the source */ + auto const height = video->size()->width / film->container().ratio(); + crop.top = crop.bottom = (video->size()->height - height) / 2; + } else { + /* Container is wider than the source */ + auto const width = video->size()->height * film->container().ratio(); + crop.left = crop.right = (video->size()->width - width) / 2; + } + + error(fmt::format( + "Cropped {} to {} left, {} right, {} top and {} bottom", + film_content->path(0).string(), + crop.left, + crop.right, + crop.top, + crop.bottom + )); + + video->set_crop(crop); + } if (cli_content.colour_conversion) { video->set_colour_conversion(PresetColourConversion::from_id(*cli_content.colour_conversion).conversion); } diff --git a/src/lib/create_cli.h b/src/lib/create_cli.h index 00abf85e5..cde8598cd 100644 --- a/src/lib/create_cli.h +++ b/src/lib/create_cli.h @@ -42,6 +42,7 @@ public: boost::filesystem::path path; VideoFrameType frame_type = VideoFrameType::TWO_D; bool auto_crop = false; + bool fill_crop = false; boost::optional<std::string> colour_conversion; boost::optional<dcp::Channel> channel; boost::optional<float> gain; diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc index b285a78fe..ac8c4245b 100644 --- a/src/lib/dcp_subtitle_content.cc +++ b/src/lib/dcp_subtitle_content.cc @@ -38,6 +38,7 @@ using std::list; using std::make_shared; using std::shared_ptr; using std::string; +using std::vector; using boost::optional; using namespace dcpomatic; @@ -45,7 +46,9 @@ using namespace dcpomatic; DCPSubtitleContent::DCPSubtitleContent(boost::filesystem::path path) : Content(path) { - text.push_back(make_shared<TextContent>(this, TextType::OPEN_SUBTITLE, TextType::OPEN_SUBTITLE)); + text = vector<shared_ptr<TextContent>>{make_shared<TextContent>(this, TextType::OPEN_SUBTITLE, TextType::OPEN_SUBTITLE)}; + /* Default to turning these subtitles on */ + only_text()->set_use(true); } DCPSubtitleContent::DCPSubtitleContent(cxml::ConstNodePtr node, boost::optional<boost::filesystem::path> film_directory, int version) @@ -63,20 +66,16 @@ DCPSubtitleContent::examine(shared_ptr<const Film> film, shared_ptr<Job> job, bo auto subtitle_asset = load(path(0)); - auto iop = dynamic_pointer_cast<dcp::InteropTextAsset>(subtitle_asset); - auto smpte = dynamic_pointer_cast<dcp::SMPTETextAsset>(subtitle_asset); - if (smpte) { + if (auto smpte = dynamic_pointer_cast<dcp::SMPTETextAsset>(subtitle_asset)) { set_video_frame_rate(film, smpte->edit_rate().numerator); } boost::mutex::scoped_lock lm(_mutex); - /* Default to turning these subtitles on */ - only_text()->set_use(true); - _length = ContentTime::from_seconds(subtitle_asset->latest_text_out().as_seconds()); subtitle_asset->fix_empty_font_ids(); + only_text()->clear_fonts(); add_fonts(only_text(), subtitle_asset); } diff --git a/src/lib/dcpomatic_socket.cc b/src/lib/dcpomatic_socket.cc index d3bfbc309..876fa47d3 100644 --- a/src/lib/dcpomatic_socket.cc +++ b/src/lib/dcpomatic_socket.cc @@ -50,7 +50,11 @@ Socket::Socket (int timeout) void Socket::check () { +#if BOOST_VERSION >= 108700 if (_deadline.expiry() <= std::chrono::system_clock::now()) { +#else + if (_deadline.expires_at() <= std::chrono::system_clock::now()) { +#endif _socket.close(); _deadline.expires_at(std::chrono::time_point<std::chrono::system_clock>::max()); } @@ -321,7 +325,11 @@ Socket::set_send_buffer_size (int size) void Socket::set_deadline_from_now(int seconds) { +#if BOOST_VERSION >= 108700 _deadline.expires_after(std::chrono::seconds(seconds)); +#else + _deadline.expires_from_now(std::chrono::seconds(seconds)); +#endif } void diff --git a/src/lib/hints.cc b/src/lib/hints.cc index 35eb640d4..879c8a5dd 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -44,16 +44,19 @@ #include <fmt/format.h> #include <boost/algorithm/string.hpp> #include <iostream> +#include <numeric> #include "i18n.h" using std::cout; using std::make_shared; +using std::map; using std::max; using std::shared_ptr; using std::string; using std::weak_ptr; +using std::vector; using boost::optional; using namespace dcpomatic; #if BOOST_VERSION >= 106100 @@ -367,14 +370,6 @@ Hints::check_loudness() } -static -bool -subtitle_mxf_too_big(shared_ptr<dcp::TextAsset> asset) -{ - return asset && asset->file() && dcp::filesystem::file_size(*asset->file()) >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK); -} - - void Hints::check_out_of_range_markers() { @@ -497,10 +492,6 @@ try hint(_("At least one of your subtitle lines has more than 79 characters. You should make each line 79 characters at most in length.")); } - bool ccap_xml_too_big = false; - bool ccap_mxf_too_big = false; - bool subs_mxf_too_big = false; - auto dcp_dir = film->dir("hints") / dcpomatic::get_process_id(); dcp::filesystem::remove_all(dcp_dir); @@ -509,31 +500,39 @@ try dcp::DCP dcp(dcp_dir); dcp.read(); DCPOMATIC_ASSERT(dcp.cpls().size() == 1); + optional<size_t> largest_ccap_xml; + optional<size_t> largest_ccap_mxf; + optional<size_t> largest_sub_mxf; for (auto reel: dcp.cpls()[0]->reels()) { for (auto ccap: reel->closed_captions()) { - if (ccap->asset() && ccap->asset()->xml_as_string().length() > static_cast<size_t>(MAX_CLOSED_CAPTION_XML_SIZE - SIZE_SLACK) && !ccap_xml_too_big) { - hint(_( - "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT - ". You should divide the DCP into shorter reels." - )); - ccap_xml_too_big = true; - } - if (subtitle_mxf_too_big(ccap->asset()) && !ccap_mxf_too_big) { - hint(_( - "At least one of your closed caption files is larger than " MAX_TEXT_MXF_SIZE_TEXT - " in total. You should divide the DCP into shorter reels." - )); - ccap_mxf_too_big = true; + largest_ccap_xml = std::max(ccap->asset()->xml_as_string().length(), largest_ccap_xml.get_value_or(0)); + if (ccap->asset() && ccap->asset()->file()) { + largest_ccap_mxf = std::max(dcp::filesystem::file_size(*ccap->asset()->file()), largest_ccap_mxf.get_value_or(0)); } } - if (reel->main_subtitle() && subtitle_mxf_too_big(reel->main_subtitle()->asset()) && !subs_mxf_too_big) { - hint(_( - "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. " - "You should divide the DCP into shorter reels." - )); - subs_mxf_too_big = true; + if (reel->main_subtitle() && reel->main_subtitle()->asset() && reel->main_subtitle()->asset()->file()) { + largest_sub_mxf = std::max(dcp::filesystem::file_size(*reel->main_subtitle()->asset()->file()), largest_sub_mxf.get_value_or(0)); } } + + if (largest_ccap_xml && *largest_ccap_xml > static_cast<size_t>(MAX_CLOSED_CAPTION_XML_SIZE - SIZE_SLACK)) { + hint(fmt::format(_( + "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT + ". The largest XML part is {}KB. You should divide the DCP into shorter reels." + ), *largest_ccap_xml / 1000)); + } + if (largest_ccap_mxf && *largest_ccap_mxf >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK)) { + hint(fmt::format(_( + "At least one of your closed caption files is larger than " MAX_TEXT_MXF_SIZE_TEXT + " in total. The largest file is {}MB. You should divide the DCP into shorter reels." + ), *largest_ccap_mxf / 1000000)); + } + if (largest_sub_mxf && *largest_sub_mxf >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK)) { + hint(fmt::format(_( + "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. " + "The largest file is {}MB. You should divide the DCP into shorter reels." + ), *largest_sub_mxf / 1000000)); + } dcp::filesystem::remove_all(dcp_dir); emit(boost::bind(boost::ref(Finished))); @@ -584,24 +583,42 @@ Hints::text(PlayerText text, TextType type, optional<DCPTextTrack> track, DCPTim void Hints::closed_caption(PlayerText text, DCPTimePeriod period) { - int lines = text.string.size(); - for (auto i: text.string) { - if (utf8_strlen(i.text()) > MAX_CLOSED_CAPTION_LENGTH) { - ++lines; - if (!_long_ccap) { - _long_ccap = true; - hint( - fmt::format( - "At least one of your closed caption lines has more than {} characters. " - "It is advisable to make each line {} characters at most in length.", - MAX_CLOSED_CAPTION_LENGTH, - MAX_CLOSED_CAPTION_LENGTH) - ); + map<float, vector<StringText>> lines; + for (auto const& line: text.string) { + bool added = false; + for (auto& existing: lines) { + if (std::abs(existing.first - line.v_position()) < dcp::ALIGN_EPSILON) { + existing.second.push_back(line); + added = true; } } + if (!added) { + lines[line.v_position()] = { line }; + } + } + + for (auto const& line: lines) { + int const length = std::accumulate( + line.second.begin(), + line.second.end(), + 0, + [](int acc, StringText const& text) { + return acc + dcp::utf8_strlen(text.text()); + }); + + if (length > MAX_CLOSED_CAPTION_LENGTH && !_long_ccap) { + _long_ccap = true; + hint( + fmt::format( + "At least one of your closed caption lines has more than {} characters. " + "It is advisable to make each line {} characters at most in length.", + MAX_CLOSED_CAPTION_LENGTH, + MAX_CLOSED_CAPTION_LENGTH) + ); + } } - if (!_too_many_ccap_lines && lines > MAX_CLOSED_CAPTION_LINES) { + if (!_too_many_ccap_lines && lines.size() > MAX_CLOSED_CAPTION_LINES) { hint(fmt::format(_("Some of your closed captions span more than {} lines, so they will be truncated."), MAX_CLOSED_CAPTION_LINES)); _too_many_ccap_lines = true; } diff --git a/src/lib/util.cc b/src/lib/util.cc index adc347ab1..60b93a0c4 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -171,7 +171,7 @@ time_to_hmsf(DCPTime time, Frame rate) m -= h * 60; char buffer[64]; - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%02d", h, m, s, static_cast<int>(f)); + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d:%02d", h, m, s, static_cast<int>(f)); return buffer; } @@ -842,26 +842,6 @@ remap(shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping ma } -size_t -utf8_strlen(string s) -{ - size_t const len = s.length(); - int N = 0; - for (size_t i = 0; i < len; ++i) { - unsigned char c = s[i]; - if ((c & 0xe0) == 0xc0) { - ++i; - } else if ((c & 0xf0) == 0xe0) { - i += 2; - } else if ((c & 0xf8) == 0xf0) { - i += 3; - } - ++N; - } - return N; -} - - /** @param size Size of picture that the subtitle will be overlaid onto */ void emit_subtitle_image(ContentTimePeriod period, dcp::TextImage sub, dcp::Size size, shared_ptr<TextDecoder> decoder) diff --git a/src/lib/util.h b/src/lib/util.h index aa003ff00..9863e5d94 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -84,7 +84,6 @@ extern std::string atmos_asset_filename(std::shared_ptr<dcp::AtmosAsset> asset, extern std::string careful_string_filter(std::string s, std::wstring allowed = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.+"); extern std::pair<int, int> audio_channel_types(std::list<int> mapped, int channels); extern std::shared_ptr<AudioBuffers> remap(std::shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping map); -extern size_t utf8_strlen(std::string s); extern void emit_subtitle_image(dcpomatic::ContentTimePeriod period, dcp::TextImage sub, dcp::Size size, std::shared_ptr<TextDecoder> decoder); extern void copy_in_bits(boost::filesystem::path from, boost::filesystem::path to, std::function<void (float)>); extern dcp::Size scale_for_display(dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta); diff --git a/src/tools/dcpomatic_verifier.cc b/src/tools/dcpomatic_verifier.cc index c2d6cd22c..c881019d8 100644 --- a/src/tools/dcpomatic_verifier.cc +++ b/src/tools/dcpomatic_verifier.cc @@ -160,7 +160,7 @@ public: return dcp_paths; }; - auto add = [this, &load_dcps](wxWindow* parent) { + auto add = [&load_dcps](wxWindow* parent) { #if wxCHECK_VERSION(3, 1, 4) DirDialog dialog(parent, _("Select DCP(s)"), wxDD_MULTIPLE, "AddVerifierInputPath"); #else diff --git a/src/wx/controls.cc b/src/wx/controls.cc index fce3fd7eb..708cc9a5d 100644 --- a/src/wx/controls.cc +++ b/src/wx/controls.cc @@ -279,7 +279,7 @@ Controls::update_position_label() { if (!_film) { checked_set(_frame_number, char_to_wx("0")); - checked_set(_timecode, char_to_wx("0:0:0.0")); + checked_set(_timecode, char_to_wx("0:0:0:0")); return; } diff --git a/src/wx/standard_controls.cc b/src/wx/standard_controls.cc index 942c49fc4..d9b8c998b 100644 --- a/src/wx/standard_controls.cc +++ b/src/wx/standard_controls.cc @@ -38,6 +38,7 @@ StandardControls::StandardControls(wxWindow* parent, FilmViewer& viewer, bool ed { _button_sizer->Add (_play_button, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); _play_button->Bind (wxEVT_TOGGLEBUTTON, boost::bind(&StandardControls::play_clicked, this)); + setup_sensitivity(); } diff --git a/src/wx/supporters.cc b/src/wx/supporters.cc index 18951fa4f..dff4f9a7c 100644 --- a/src/wx/supporters.cc +++ b/src/wx/supporters.cc @@ -1491,6 +1491,7 @@ supported_by.Add (wxT ("Tilman Vatteroth")); supported_by.Add (wxT ("Jos Vecht")); supported_by.Add (wxT ("Christian Vennefrohne")); supported_by.Add (wxT ("Jaap Verseput")); +supported_by.Add (wxT ("Dan Viafore")); supported_by.Add (wxT ("Videoworld")); supported_by.Add (wxT ("Robert Vidić")); supported_by.Add (wxT ("Burg Kino Vienna")); diff --git a/src/wx/verify_dcp_result_panel.cc b/src/wx/verify_dcp_result_panel.cc index 425a3eb00..aa5da95c6 100644 --- a/src/wx/verify_dcp_result_panel.cc +++ b/src/wx/verify_dcp_result_panel.cc @@ -230,6 +230,12 @@ VerifyDCPResultPanel::add(shared_ptr<const VerifyDCPJob> job, bool many) if (auto const error = note.error()) { message.Replace(char_to_wx("%error"), std_to_wx(*error)); } + if (auto const bit_depth = note.bit_depth()) { + message.Replace(char_to_wx("%bit_depth"), std_to_wx(fmt::to_string(*bit_depth))); + } + if (auto const issue_date = note.issue_date()) { + message.Replace(char_to_wx("%issue_date"), std_to_wx(*issue_date)); + } if (auto const size_in_pixels = note.size_in_pixels()) { message.Replace(char_to_wx("%size_in_pixels"), wxString::Format(char_to_wx("%dx%d"), size_in_pixels->width, size_in_pixels->height)); } @@ -339,7 +345,7 @@ VerifyDCPResultPanel::add(shared_ptr<const VerifyDCPJob> job, bool many) ); break; case dcp::VerificationNote::Code::EXTERNAL_ASSET: - add(i.second, _("This DCP refers to at the asset %asset_id in another DCP (and perhaps others), so it is a \"version file\" (VF)")); + add(i.second, _("This DCP refers to the asset %asset_id in another DCP (and perhaps others), so it is a \"version file\" (VF)")); break; case dcp::VerificationNote::Code::THREED_ASSET_MARKED_AS_TWOD: add(i.second, _("The asset %f is 3D but its MXF is marked as 2D.")); diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 8d21a3e63..8e86a5408 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -65,9 +65,9 @@ using namespace dcpomatic; wxStaticText * #ifdef __WXOSX__ -create_label (wxWindow* p, wxString t, bool left) +create_label(wxWindow* p, wxString t, bool left) #else -create_label (wxWindow* p, wxString t, bool) +create_label(wxWindow* p, wxString t, bool) #endif { #ifdef __WXOSX__ @@ -75,14 +75,14 @@ create_label (wxWindow* p, wxString t, bool) t += char_to_wx(":"); } #endif - return new StaticText (p, t); + return new StaticText(p, t); } #ifdef __WXOSX__ static void -setup_osx_flags (wxSizer* s, bool left, int& flags) +setup_osx_flags(wxSizer* s, bool left, int& flags) { if (left) { auto box = dynamic_cast<wxBoxSizer*>(s); @@ -103,28 +103,28 @@ setup_osx_flags (wxSizer* s, bool left, int& flags) * @param prop Proportion to pass when calling Add() on the wxSizer. */ wxStaticText * -add_label_to_sizer (wxSizer* s, wxWindow* p, wxString t, bool left, int prop, int flags) +add_label_to_sizer(wxSizer* s, wxWindow* p, wxString t, bool left, int prop, int flags) { #ifdef __WXOSX__ - setup_osx_flags (s, left, flags); + setup_osx_flags(s, left, flags); #endif - auto m = create_label (p, t, left); - s->Add (m, prop, flags, DCPOMATIC_SIZER_GAP); + auto m = create_label(p, t, left); + s->Add(m, prop, flags, DCPOMATIC_SIZER_GAP); return m; } wxStaticText * #ifdef __WXOSX__ -add_label_to_sizer (wxSizer* s, wxStaticText* t, bool left, int prop, int flags) +add_label_to_sizer(wxSizer* s, wxStaticText* t, bool left, int prop, int flags) #else -add_label_to_sizer (wxSizer* s, wxStaticText* t, bool, int prop, int flags) +add_label_to_sizer(wxSizer* s, wxStaticText* t, bool, int prop, int flags) #endif { #ifdef __WXOSX__ - setup_osx_flags (s, left, flags); + setup_osx_flags(s, left, flags); #endif - s->Add (t, prop, flags, DCPOMATIC_SIZER_GAP); + s->Add(t, prop, flags, DCPOMATIC_SIZER_GAP); return t; } @@ -134,9 +134,9 @@ add_label_to_sizer(wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPo { int flags = wxALIGN_CENTER_VERTICAL | wxLEFT; #ifdef __WXOSX__ - setup_osx_flags (s, left, flags); + setup_osx_flags(s, left, flags); #endif - auto m = create_label (p, t, left); + auto m = create_label(p, t, left); s->Add(m, pos, span, flags, indent ? DCPOMATIC_SIZER_X_GAP : 0); return m; } @@ -144,16 +144,16 @@ add_label_to_sizer(wxGridBagSizer* s, wxWindow* p, wxString t, bool left, wxGBPo wxStaticText * #ifdef __WXOSX__ -add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span) +add_label_to_sizer(wxGridBagSizer* s, wxStaticText* t, bool left, wxGBPosition pos, wxGBSpan span) #else -add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, wxGBSpan span) +add_label_to_sizer(wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, wxGBSpan span) #endif { int flags = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT; #ifdef __WXOSX__ - setup_osx_flags (s, left, flags); + setup_osx_flags(s, left, flags); #endif - s->Add (t, pos, span, flags); + s->Add(t, pos, span, flags); return t; } @@ -164,12 +164,12 @@ add_label_to_sizer (wxGridBagSizer* s, wxStaticText* t, bool, wxGBPosition pos, * @param e Extended message. */ void -error_dialog (wxWindow* parent, wxString m, optional<wxString> e) +error_dialog(wxWindow* parent, wxString m, optional<wxString> e) { wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxOK | wxICON_ERROR); if (e) { wxString em = *e; - em[0] = wxToupper (em[0]); + em[0] = wxToupper(em[0]); dialog.SetExtendedMessage(em); } dialog.ShowModal(); @@ -181,7 +181,7 @@ error_dialog (wxWindow* parent, wxString m, optional<wxString> e) * @param m Message. */ void -message_dialog (wxWindow* parent, wxString m) +message_dialog(wxWindow* parent, wxString m) { wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxOK | wxICON_INFORMATION); dialog.ShowModal(); @@ -190,7 +190,7 @@ message_dialog (wxWindow* parent, wxString m) /** @return true if the user answered "yes" */ bool -confirm_dialog (wxWindow* parent, wxString m) +confirm_dialog(wxWindow* parent, wxString m) { wxMessageDialog dialog(parent, m, variant::wx::dcpomatic(), wxYES_NO | wxICON_QUESTION); return dialog.ShowModal() == wxID_YES; @@ -201,9 +201,9 @@ confirm_dialog (wxWindow* parent, wxString m) * @return Corresponding STL string. */ string -wx_to_std (wxString s) +wx_to_std(wxString s) { - return string (s.ToUTF8()); + return string(s.ToUTF8()); } @@ -211,9 +211,9 @@ wx_to_std (wxString s) * @return Corresponding wxWidgets string. */ wxString -std_to_wx (string s) +std_to_wx(string s) { - return wxString (s.c_str(), wxConvUTF8); + return wxString(s.c_str(), wxConvUTF8); } @@ -225,14 +225,14 @@ char_to_wx(char const* s) string -string_client_data (wxClientData* o) +string_client_data(wxClientData* o) { - return wx_to_std (dynamic_cast<wxStringClientData*>(o)->GetData()); + return wx_to_std(dynamic_cast<wxStringClientData*>(o)->GetData()); } void -checked_set (FilePickerCtrl* widget, boost::filesystem::path value) +checked_set(FilePickerCtrl* widget, boost::filesystem::path value) { if (widget->path() != value) { if (value.empty()) { @@ -247,60 +247,60 @@ checked_set (FilePickerCtrl* widget, boost::filesystem::path value) void -checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value) +checked_set(wxDirPickerCtrl* widget, boost::filesystem::path value) { - if (widget->GetPath() != std_to_wx (value.string())) { + if (widget->GetPath() != std_to_wx(value.string())) { if (value.empty()) { /* Hack to make wxWidgets clear the control when we are passed an empty value. */ value = " "; } - widget->SetPath (std_to_wx (value.string())); + widget->SetPath(std_to_wx(value.string())); } } void -checked_set (wxSpinCtrl* widget, int value) +checked_set(wxSpinCtrl* widget, int value) { if (widget->GetValue() != value) { - widget->SetValue (value); + widget->SetValue(value); } } void -checked_set (wxSpinCtrlDouble* widget, double value) +checked_set(wxSpinCtrlDouble* widget, double value) { /* XXX: completely arbitrary epsilon */ - if (fabs (widget->GetValue() - value) > 1e-16) { - widget->SetValue (value); + if (fabs(widget->GetValue() - value) > 1e-16) { + widget->SetValue(value); } } void -checked_set (wxChoice* widget, int value) +checked_set(wxChoice* widget, int value) { if (widget->GetSelection() != value) { - widget->SetSelection (value); + widget->SetSelection(value); } } void -checked_set (wxChoice* widget, string value) +checked_set(wxChoice* widget, string value) { wxClientData* o = nullptr; if (widget->GetSelection() != -1) { - o = widget->GetClientObject (widget->GetSelection ()); + o = widget->GetClientObject(widget->GetSelection()); } if (!o || string_client_data(o) != value) { for (unsigned int i = 0; i < widget->GetCount(); ++i) { - if (string_client_data (widget->GetClientObject (i)) == value) { - widget->SetSelection (i); + if (string_client_data(widget->GetClientObject(i)) == value) { + widget->SetSelection(i); } } } @@ -308,11 +308,11 @@ checked_set (wxChoice* widget, string value) void -checked_set (wxChoice* widget, vector<pair<string, string>> items) +checked_set(wxChoice* widget, vector<pair<string, string>> items) { vector<pair<string, string>> current; for (unsigned int i = 0; i < widget->GetCount(); ++i) { - current.push_back ( + current.push_back( make_pair( wx_to_std(widget->GetString(i)), widget->GetClientData() ? string_client_data(widget->GetClientObject(i)) : "" @@ -324,24 +324,24 @@ checked_set (wxChoice* widget, vector<pair<string, string>> items) return; } - widget->Clear (); + widget->Clear(); for (auto i: items) { - widget->Append (std_to_wx(i.first), new wxStringClientData(std_to_wx(i.second))); + widget->Append(std_to_wx(i.first), new wxStringClientData(std_to_wx(i.second))); } } void -checked_set (wxTextCtrl* widget, string value) +checked_set(wxTextCtrl* widget, string value) { - if (widget->GetValue() != std_to_wx (value)) { - widget->ChangeValue (std_to_wx (value)); + if (widget->GetValue() != std_to_wx(value)) { + widget->ChangeValue(std_to_wx(value)); } } void -checked_set (PasswordEntry* entry, string value) +checked_set(PasswordEntry* entry, string value) { if (entry->get() != value) { entry->set(value); @@ -350,46 +350,46 @@ checked_set (PasswordEntry* entry, string value) void -checked_set (wxTextCtrl* widget, wxString value) +checked_set(wxTextCtrl* widget, wxString value) { if (widget->GetValue() != value) { - widget->ChangeValue (value); + widget->ChangeValue(value); } } void -checked_set (wxStaticText* widget, string value) +checked_set(wxStaticText* widget, string value) { - if (widget->GetLabel() != std_to_wx (value)) { - widget->SetLabel (std_to_wx (value)); + if (widget->GetLabel() != std_to_wx(value)) { + widget->SetLabel(std_to_wx(value)); } } void -checked_set (wxStaticText* widget, wxString value) +checked_set(wxStaticText* widget, wxString value) { if (widget->GetLabel() != value) { - widget->SetLabel (value); + widget->SetLabel(value); } } void -checked_set (wxCheckBox* widget, bool value) +checked_set(wxCheckBox* widget, bool value) { if (widget->GetValue() != value) { - widget->SetValue (value); + widget->SetValue(value); } } void -checked_set (wxRadioButton* widget, bool value) +checked_set(wxRadioButton* widget, bool value) { if (widget->GetValue() != value) { - widget->SetValue (value); + widget->SetValue(value); } } @@ -422,23 +422,23 @@ checked_set(RegionSubtagWidget* widget, optional<dcp::LanguageTag::RegionSubtag> int -wx_get (wxSpinCtrl* w) +wx_get(wxSpinCtrl* w) { - return w->GetValue (); + return w->GetValue(); } int -wx_get (wxChoice* w) +wx_get(wxChoice* w) { - return w->GetSelection (); + return w->GetSelection(); } double -wx_get (wxSpinCtrlDouble* w) +wx_get(wxSpinCtrlDouble* w) { - return w->GetValue (); + return w->GetValue(); } @@ -454,7 +454,7 @@ context_translation(char const* s) /* No translation; strip the context */ int c = t.Find(char_to_wx("|")); if (c != wxNOT_FOUND) { - t = t.Mid (c + 1); + t = t.Mid(c + 1); } } @@ -463,46 +463,46 @@ context_translation(char const* s) wxString -time_to_timecode (DCPTime t, double fps) +time_to_timecode(DCPTime t, double fps) { - auto w = t.seconds (); + auto w = t.seconds(); int const h = (w / 3600); w -= h * 3600; int const m = (w / 60); w -= m * 60; - int const s = floor (w); + int const s = floor(w); w -= s; - int const f = lrint (w * fps); - return wxString::Format(char_to_wx("%02d:%02d:%02d.%02d"), h, m, s, f); + int const f = lrint(w * fps); + return wxString::Format(char_to_wx("%02d:%02d:%02d:%02d"), h, m, s, f); } void -setup_audio_channels_choice (wxChoice* choice, int minimum) +setup_audio_channels_choice(wxChoice* choice, int minimum) { vector<pair<string, string>> items; for (int i = minimum; i <= 16; i += 2) { if (i == 2) { - items.push_back (make_pair(wx_to_std(_("2 - stereo")), locale_convert<string>(i))); + items.push_back(make_pair(wx_to_std(_("2 - stereo")), locale_convert<string>(i))); } else if (i == 4) { - items.push_back (make_pair(wx_to_std(_("4 - L/C/R/Lfe")), locale_convert<string>(i))); + items.push_back(make_pair(wx_to_std(_("4 - L/C/R/Lfe")), locale_convert<string>(i))); } else if (i == 6) { - items.push_back (make_pair(wx_to_std(_("6 - 5.1")), locale_convert<string>(i))); + items.push_back(make_pair(wx_to_std(_("6 - 5.1")), locale_convert<string>(i))); } else if (i == 8) { - items.push_back (make_pair(wx_to_std(_("8 - 5.1/HI/VI")), locale_convert<string>(i))); + items.push_back(make_pair(wx_to_std(_("8 - 5.1/HI/VI")), locale_convert<string>(i))); } else if (i == 12) { - items.push_back (make_pair(wx_to_std(_("12 - 7.1/HI/VI")), locale_convert<string>(i))); + items.push_back(make_pair(wx_to_std(_("12 - 7.1/HI/VI")), locale_convert<string>(i))); } else { - items.push_back (make_pair(locale_convert<string> (i), locale_convert<string>(i))); + items.push_back(make_pair(locale_convert<string>(i), locale_convert<string>(i))); } } - checked_set (choice, items); + checked_set(choice, items); } wxSplashScreen* -maybe_show_splash () +maybe_show_splash() { wxSplashScreen* splash = nullptr; @@ -523,7 +523,7 @@ maybe_show_splash () #else splash = new wxSplashScreen(bitmap, wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT, 0, nullptr, -1); #endif - wxYield (); + wxYield(); } } catch (boost::filesystem::filesystem_error& e) { /* Maybe we couldn't find the splash image; never mind */ @@ -534,19 +534,19 @@ maybe_show_splash () double -calculate_mark_interval (double mark_interval) +calculate_mark_interval(double mark_interval) { if (mark_interval > 5) { - mark_interval -= lrint (mark_interval) % 5; + mark_interval -= lrint(mark_interval) % 5; } if (mark_interval > 10) { - mark_interval -= lrint (mark_interval) % 10; + mark_interval -= lrint(mark_interval) % 10; } if (mark_interval > 60) { - mark_interval -= lrint (mark_interval) % 60; + mark_interval -= lrint(mark_interval) % 60; } if (mark_interval > 3600) { - mark_interval -= lrint (mark_interval) % 3600; + mark_interval -= lrint(mark_interval) % 3600; } if (mark_interval < 1) { @@ -559,16 +559,16 @@ calculate_mark_interval (double mark_interval) /** @return false if the task was cancelled */ bool -display_progress (wxString title, wxString task) +display_progress(wxString title, wxString task) { - auto jm = JobManager::instance (); + auto jm = JobManager::instance(); - wxProgressDialog progress (title, task, 100, 0, wxPD_CAN_ABORT); + wxProgressDialog progress(title, task, 100, 0, wxPD_CAN_ABORT); bool ok = true; while (jm->work_to_do()) { - dcpomatic_sleep_seconds (1); + dcpomatic_sleep_seconds(1); if (!progress.Pulse()) { /* user pressed cancel */ for (auto i: jm->get()) { @@ -584,7 +584,7 @@ display_progress (wxString title, wxString task) int -get_offsets (vector<Offset>& offsets) +get_offsets(vector<Offset>& offsets) { offsets.push_back({_("UTC-11"), dcp::UTCOffset(-11, 0)}); offsets.push_back({_("UTC-10"), dcp::UTCOffset(-10, 0)}); @@ -623,13 +623,13 @@ get_offsets (vector<Offset>& offsets) wxString -bitmap_path (string name) +bitmap_path(string name) { boost::filesystem::path base; #ifdef DCPOMATIC_DEBUG /* Hack to allow Linux and OS X to find icons when running from the source tree */ - char* path = getenv ("DCPOMATIC_GRAPHICS"); + char* path = getenv("DCPOMATIC_GRAPHICS"); if (path) { base = path; } else { @@ -644,7 +644,7 @@ bitmap_path (string name) #endif auto p = base / name; - return std_to_wx (p.string()); + return std_to_wx(p.string()); } @@ -656,18 +656,18 @@ icon_path(string name) wxSize -small_button_size (wxWindow* parent, wxString text) +small_button_size(wxWindow* parent, wxString text) { - wxClientDC dc (parent); - auto size = dc.GetTextExtent (text); - size.SetHeight (-1); - size.IncBy (32, 0); + wxClientDC dc(parent); + auto size = dc.GetTextExtent(text); + size.SetHeight(-1); + size.IncBy(32, 0); return size; } bool -gui_is_dark () +gui_is_dark() { #ifdef DCPOMATIC_WINDOWS /* Dark mode doesn't really work at all on Windows at the moment, so just don't use it */ @@ -684,13 +684,13 @@ gui_is_dark () #if wxCHECK_VERSION(3,1,0) double -dpi_scale_factor (wxWindow* window) +dpi_scale_factor(wxWindow* window) { return window->GetDPIScaleFactor(); } #else double -dpi_scale_factor (wxWindow*) +dpi_scale_factor(wxWindow*) { return 1; } @@ -699,7 +699,7 @@ dpi_scale_factor (wxWindow*) int -search_ctrl_height () +search_ctrl_height() { #ifdef __WXGTK3__ return 30; diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index 6f84705fb..957957589 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -94,34 +94,34 @@ class PasswordEntry; #define S_(x) context_translation(x) -extern void error_dialog (wxWindow *, wxString, boost::optional<wxString> e = boost::optional<wxString>()); -extern void message_dialog (wxWindow *, wxString); -extern bool confirm_dialog (wxWindow *, wxString); -extern wxStaticText* create_label (wxWindow* p, wxString t, bool left); -extern wxStaticText* add_label_to_sizer (wxSizer *, wxWindow *, wxString, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT); -extern wxStaticText* add_label_to_sizer (wxSizer *, wxStaticText *, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT); +extern void error_dialog(wxWindow *, wxString, boost::optional<wxString> e = boost::optional<wxString>()); +extern void message_dialog(wxWindow *, wxString); +extern bool confirm_dialog(wxWindow *, wxString); +extern wxStaticText* create_label(wxWindow* p, wxString t, bool left); +extern wxStaticText* add_label_to_sizer(wxSizer *, wxWindow *, wxString, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT); +extern wxStaticText* add_label_to_sizer(wxSizer *, wxStaticText *, bool left, int prop = 0, int flags = wxLEFT | wxRIGHT); extern wxStaticText* add_label_to_sizer(wxGridBagSizer *, wxWindow *, wxString, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan, bool indent = false); -extern wxStaticText* add_label_to_sizer (wxGridBagSizer *, wxStaticText *, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan); -extern std::string wx_to_std (wxString); -extern wxString std_to_wx (std::string); +extern wxStaticText* add_label_to_sizer(wxGridBagSizer *, wxStaticText *, bool, wxGBPosition, wxGBSpan span = wxDefaultSpan); +extern std::string wx_to_std(wxString); +extern wxString std_to_wx(std::string); /** Convert UTF8-encoded char array to wxString */ extern wxString char_to_wx(char const* s); extern wxString context_translation(char const* s); -extern std::string string_client_data (wxClientData* o); -extern wxString time_to_timecode (dcpomatic::DCPTime t, double fps); -extern void setup_audio_channels_choice (wxChoice* choice, int minimum); +extern std::string string_client_data(wxClientData* o); +extern wxString time_to_timecode(dcpomatic::DCPTime t, double fps); +extern void setup_audio_channels_choice(wxChoice* choice, int minimum); extern wxSplashScreen* maybe_show_splash(); -extern double calculate_mark_interval (double start); -extern bool display_progress (wxString title, wxString task); -extern bool report_errors_from_last_job (wxWindow* parent); -extern wxString bitmap_path (std::string name); +extern double calculate_mark_interval(double start); +extern bool display_progress(wxString title, wxString task); +extern bool report_errors_from_last_job(wxWindow* parent); +extern wxString bitmap_path(std::string name); extern wxString icon_path(std::string name); -extern wxSize small_button_size (wxWindow* parent, wxString text); -extern bool gui_is_dark (); -extern double dpi_scale_factor (wxWindow* window); -extern int search_ctrl_height (); +extern wxSize small_button_size(wxWindow* parent, wxString text); +extern bool gui_is_dark(); +extern double dpi_scale_factor(wxWindow* window); +extern int search_ctrl_height(); extern void report_config_load_failure(wxWindow* parent, Config::LoadFailure what); extern bool layout_for_short_screen(wxWindow* reference); @@ -137,7 +137,7 @@ struct Offset dcp::UTCOffset offset; }; -extern int get_offsets (std::vector<Offset>& offsets); +extern int get_offsets(std::vector<Offset>& offsets); namespace dcpomatic { namespace wx { @@ -149,27 +149,27 @@ namespace wx { } -extern void checked_set (FilePickerCtrl* widget, boost::filesystem::path value); -extern void checked_set (wxDirPickerCtrl* widget, boost::filesystem::path value); -extern void checked_set (wxSpinCtrl* widget, int value); -extern void checked_set (wxSpinCtrlDouble* widget, double value); -extern void checked_set (wxChoice* widget, int value); -extern void checked_set (wxChoice* widget, std::string value); -extern void checked_set (wxChoice* widget, std::vector<std::pair<std::string, std::string> > items); -extern void checked_set (wxTextCtrl* widget, std::string value); -extern void checked_set (wxTextCtrl* widget, wxString value); -extern void checked_set (PasswordEntry* widget, std::string value); -extern void checked_set (wxCheckBox* widget, bool value); -extern void checked_set (wxRadioButton* widget, bool value); -extern void checked_set (wxStaticText* widget, std::string value); -extern void checked_set (wxStaticText* widget, wxString value); +extern void checked_set(FilePickerCtrl* widget, boost::filesystem::path value); +extern void checked_set(wxDirPickerCtrl* widget, boost::filesystem::path value); +extern void checked_set(wxSpinCtrl* widget, int value); +extern void checked_set(wxSpinCtrlDouble* widget, double value); +extern void checked_set(wxChoice* widget, int value); +extern void checked_set(wxChoice* widget, std::string value); +extern void checked_set(wxChoice* widget, std::vector<std::pair<std::string, std::string> > items); +extern void checked_set(wxTextCtrl* widget, std::string value); +extern void checked_set(wxTextCtrl* widget, wxString value); +extern void checked_set(PasswordEntry* widget, std::string value); +extern void checked_set(wxCheckBox* widget, bool value); +extern void checked_set(wxRadioButton* widget, bool value); +extern void checked_set(wxStaticText* widget, std::string value); +extern void checked_set(wxStaticText* widget, wxString value); extern void checked_set(LanguageTagWidget* widget, dcp::LanguageTag value); extern void checked_set(LanguageTagWidget* widget, boost::optional<dcp::LanguageTag> value); extern void checked_set(RegionSubtagWidget* widget, boost::optional<dcp::LanguageTag::RegionSubtag> value); -extern int wx_get (wxChoice* widget); -extern int wx_get (wxSpinCtrl* widget); -extern double wx_get (wxSpinCtrlDouble* widget); +extern int wx_get(wxChoice* widget); +extern int wx_get(wxSpinCtrl* widget); +extern double wx_get(wxSpinCtrlDouble* widget); #ifdef DCPOMATIC_WINDOWS #define DCPOMATIC_USE_OWN_PICKER diff --git a/test/create_cli_test.cc b/test/create_cli_test.cc index c71031fbc..0f127c018 100644 --- a/test/create_cli_test.cc +++ b/test/create_cli_test.cc @@ -322,6 +322,22 @@ BOOST_AUTO_TEST_CASE (create_cli_test) BOOST_CHECK(film->content()[0]->video->fade_in() == 24); BOOST_CHECK(film->content()[0]->video->fade_out() == 0); BOOST_CHECK(collected_error.empty()); + + /* Extract a 1.85 frame from a 320x240 source */ + cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/red_24.mp4"); + BOOST_CHECK(!cc.error); + film = cc.make_film(error); + BOOST_REQUIRE_EQUAL(film->content().size(), 1U); + BOOST_REQUIRE(film->content()[0]->video); + BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(0, 0, 33, 33)); + + /* Extract a 1.85 frame from a 2048x858 source */ + cc = run("dcpomatic2_create --container-ratio 185 --fill-crop test/data/scope_dcp"); + BOOST_CHECK(!cc.error); + film = cc.make_film(error); + BOOST_REQUIRE_EQUAL(film->content().size(), 1U); + BOOST_REQUIRE(film->content()[0]->video); + BOOST_CHECK(film->content()[0]->video->requested_crop() == Crop(230, 230, 0, 0)); } diff --git a/test/data b/test/data -Subproject fe6973d73602cff710f5ea2396a47074b21686d +Subproject cec02cb60028b76800357604f8331b903388d77 diff --git a/test/hints_test.cc b/test/hints_test.cc index 073415018..7cb9d676b 100644 --- a/test/hints_test.cc +++ b/test/hints_test.cc @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE (hint_subtitle_mxf_too_big) BOOST_CHECK_EQUAL ( hints[0], "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total. " - "You should divide the DCP into shorter reels." + "The largest file is 134MB. You should divide the DCP into shorter reels." ); } @@ -245,7 +245,7 @@ BOOST_AUTO_TEST_CASE (hint_closed_caption_xml_too_big) BOOST_CHECK_EQUAL ( hints[0], "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT ". " - "You should divide the DCP into shorter reels." + "The largest XML part is 482KB. You should divide the DCP into shorter reels." ); } @@ -326,3 +326,32 @@ BOOST_AUTO_TEST_CASE(hints_120fps) BOOST_CHECK(hint.find("There is a large difference between the frame rate of your DCP and that of some of your content.") == std::string::npos); } } + + +BOOST_AUTO_TEST_CASE(hints_ccap_not_too_many_lines_xml) +{ + auto content = content_factory(TestPaths::private_data() / "ccap_not_too_many_lines.xml")[0]; + auto film = new_test_film("hints_ccap_not_too_many_lines", { content }); + content->text[0]->set_type(TextType::CLOSED_CAPTION); + auto hints = get_hints(film); + + BOOST_CHECK( + std::none_of(hints.begin(), hints.end(), [](string const& hint) { + return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos; + }) + ); +} + + +BOOST_AUTO_TEST_CASE(hints_ccap_too_many_lines_xml) +{ + auto content = content_factory(TestPaths::private_data() / "ccap_too_many_lines.xml")[0]; + auto film = new_test_film("hints_ccap_too_many_lines", { content }); + content->text[0]->set_type(TextType::CLOSED_CAPTION); + auto hints = get_hints(film); + BOOST_CHECK( + std::any_of(hints.begin(), hints.end(), [](string const& hint) { + return hint.find("Some of your closed captions span more than 3 lines") != std::string::npos; + }) + ); +} diff --git a/test/render_subtitles_test.cc b/test/render_subtitles_test.cc index 4e87abde0..4fc98cb56 100644 --- a/test/render_subtitles_test.cc +++ b/test/render_subtitles_test.cc @@ -176,8 +176,11 @@ BOOST_AUTO_TEST_CASE(render_text_with_newline_test) #elif defined(DCPOMATIC_WINDOWS) check_image("test/data/windows/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); #elif PANGO_VERSION_CHECK(1, 57, 0) - /* This pango version is the one on Arch, which renders slightly differently */ - check_image("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); + /* This pango version is the one on Arch and Ubuntu 26.04, both of which render slightly differently */ + BOOST_REQUIRE( + check_image_and_report("test/data/arch/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png") + || check_image_and_report("test/data/ubuntu-26.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png") + ); #elif PANGO_VERSION_CHECK(1, 52, 1) /* This pango version is the one on Ubuntu 24.04, which renders slightly differently */ check_image("test/data/ubuntu-24.04/render_text_with_newline_test.png", "build/test/render_text_with_newline_test.png"); diff --git a/test/test.cc b/test/test.cc index 641ee4085..27b00b9d3 100644 --- a/test/test.cc +++ b/test/test.cc @@ -473,6 +473,13 @@ check_image (boost::filesystem::path ref, boost::filesystem::path check, double } +bool +check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold) +{ + return rms_error(ref, check) < threshold; +} + + void check_file (boost::filesystem::path ref, boost::filesystem::path check) { diff --git a/test/test.h b/test/test.h index 172edcf71..cd40c7872 100644 --- a/test/test.h +++ b/test/test.h @@ -69,6 +69,7 @@ extern bool mxf_atmos_files_same (boost::filesystem::path ref, boost::filesystem extern void check_xml(boost::filesystem::path, boost::filesystem::path, std::list<Glib::ustring>); extern void check_ffmpeg(boost::filesystem::path, boost::filesystem::path, float audio_tolerance); extern void check_image(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4); +extern bool check_image_and_report(boost::filesystem::path ref, boost::filesystem::path check, double threshold = 4); extern boost::filesystem::path test_film_dir (std::string); extern void write_image (std::shared_ptr<const Image> image, boost::filesystem::path file); boost::filesystem::path dcp_file (std::shared_ptr<const Film> film, std::string prefix); diff --git a/test/util_test.cc b/test/util_test.cc index defc7f907..ee26cc18c 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -93,11 +93,11 @@ BOOST_AUTO_TEST_CASE(seconds_to_approximate_hms_test) BOOST_AUTO_TEST_CASE(time_to_hmsf_test) { - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00.12"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01.00"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01.08"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32.00"); - BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32.00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(12, 24), 24), "00:00:00:12"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(24, 24), 24), "00:00:01:00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_frames(32, 24), 24), "00:00:01:08"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(92), 24), "00:01:32:00"); + BOOST_CHECK_EQUAL(time_to_hmsf(DCPTime::from_seconds(2 * 60 * 60 + 92), 24), "02:01:32:00"); } @@ -110,14 +110,6 @@ BOOST_AUTO_TEST_CASE(tidy_for_filename_test) } -BOOST_AUTO_TEST_CASE(utf8_strlen_test) -{ - BOOST_CHECK_EQUAL(utf8_strlen("hello world"), 11U); - BOOST_CHECK_EQUAL(utf8_strlen("hëllo world"), 11U); - BOOST_CHECK_EQUAL(utf8_strlen("hëłlo wørld"), 11U); -} - - BOOST_AUTO_TEST_CASE(careful_string_filter_test) { BOOST_CHECK_EQUAL("hello_world", careful_string_filter("hello_world")); |
