2 Copyright (C) 2016-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
25 #include "video_content.h"
26 #include "text_content.h"
27 #include "audio_processor.h"
30 #include "audio_analysis.h"
31 #include "compose.hpp"
35 #include <dcp/raw_convert.h>
36 #include <boost/foreach.hpp>
37 #include <boost/algorithm/string.hpp>
48 using boost::shared_ptr;
49 using boost::weak_ptr;
50 using boost::optional;
53 Hints::Hints (weak_ptr<const Film> film)
57 , _overlap_ccap (false)
58 , _too_many_ccap_lines (false)
68 _thread->interrupt ();
89 _overlap_ccap = false;
90 _too_many_ccap_lines = false;
91 _thread = new boost::thread (bind(&Hints::thread, this));
97 shared_ptr<const Film> film = _film.lock ();
102 ContentList content = film->content ();
104 bool big_font_files = false;
105 if (film->interop ()) {
106 BOOST_FOREACH (shared_ptr<Content> i, content) {
107 BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
108 BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
109 for (int l = 0; l < FontFiles::VARIANTS; ++l) {
110 optional<boost::filesystem::path> const p = k->file (static_cast<FontFiles::Variant>(l));
111 if (p && boost::filesystem::file_size (p.get()) >= (640 * 1024)) {
112 big_font_files = true;
120 if (big_font_files) {
121 hint (_("You have specified a font file which is larger than 640kB. This is very likely to cause problems on playback."));
124 if (film->audio_channels() < 6) {
125 hint (_("Your DCP has fewer than 6 audio channels. This may cause problems on some projectors."));
128 AudioProcessor const * ap = film->audio_processor();
129 if (ap && (ap->id() == "stereo-5.1-upmix-a" || ap->id() == "stereo-5.1-upmix-b")) {
130 hint (_("You are using DCP-o-matic's stereo-to-5.1 upmixer. This is experimental and may result in poor-quality audio. If you continue, you should listen to the resulting DCP in a cinema to make sure that it sounds good."));
133 int flat_or_narrower = 0;
135 BOOST_FOREACH (shared_ptr<const Content> i, content) {
137 Ratio const * r = i->video->scale().ratio ();
138 if (r && r->id() == "239") {
140 } else if (r && r->id() != "239" && r->id() != "190") {
146 string const film_container = film->container()->id();
148 if (scope && !flat_or_narrower && film_container == "185") {
149 hint (_("All of your content is in Scope (2.39:1) but your DCP's container is Flat (1.85:1). This will letter-box your content inside a Flat (1.85:1) frame. You may prefer to set your DCP's container to Scope (2.39:1) in the \"DCP\" tab."));
152 if (!scope && flat_or_narrower && film_container == "239") {
153 hint (_("All of your content is at 1.85:1 or narrower but your DCP's container is Scope (2.39:1). This will pillar-box your content inside a Flat (1.85:1) frame. You may prefer to set your DCP's container to Flat (1.85:1) in the \"DCP\" tab."));
156 if (film_container != "185" && film_container != "239" && film_container != "190") {
157 hint (_("Your DCP uses an unusual container ratio. This may cause problems on some projectors. If possible, use Flat or Scope for the DCP container ratio"));
160 if (film->j2k_bandwidth() >= 245000000) {
161 hint (_("A few projectors have problems playing back very high bit-rate DCPs. It is a good idea to drop the JPEG2000 bandwidth down to about 200Mbit/s; this is unlikely to have any visible effect on the image."));
164 if (film->interop() && film->video_frame_rate() != 24 && film->video_frame_rate() != 48) {
165 string base = _("You are set up for an Interop DCP at a frame rate which is not officially supported. You are advised either to change the frame rate of your DCP or to make a SMPTE DCP instead.");
167 pair<double, double> range24 = film->speed_up_range (24);
168 pair<double, double> range48 = film->speed_up_range (48);
169 pair<double, double> range (max (range24.first, range48.first), min (range24.second, range48.second));
171 if (range.second > (29.0/24)) {
173 h += _("However, setting your DCP frame rate to 24 or 48 will cause a significant speed-up of your content, and SMPTE DCPs are not supported by all projectors.");
174 } else if (range.first < (24.0/29)) {
176 h += _("However, setting your DCP frame rate to 24 or 48 will cause a significant slowdown of your content, and SMPTE DCPs are not supported by all projectors.");
178 h = _("You are set up for an Interop DCP at a frame rate which is not officially supported. You are advised either to change the frame rate of your DCP or to make a SMPTE DCP instead (although SMPTE DCPs are not supported by all projectors).");
184 optional<double> lowest_speed_up;
185 optional<double> highest_speed_up;
186 BOOST_FOREACH (shared_ptr<const Content> i, content) {
187 double spu = film->active_frame_rate_change(i->position()).speed_up;
188 if (!lowest_speed_up || spu < *lowest_speed_up) {
189 lowest_speed_up = spu;
191 if (!highest_speed_up || spu > *highest_speed_up) {
192 highest_speed_up = spu;
196 double worst_speed_up = 1;
197 if (highest_speed_up) {
198 worst_speed_up = *highest_speed_up;
200 if (lowest_speed_up) {
201 worst_speed_up = max (worst_speed_up, 1 / *lowest_speed_up);
204 if (worst_speed_up > 25.5/24.0) {
205 hint (_("There is a large difference between the frame rate of your DCP and that of some of your content. This will cause your audio to play back at a much lower or higher pitch than it should. You are advised to set your DCP frame rate to one closer to your content, provided that your target projection systems support your chosen DCP rate."));
209 BOOST_FOREACH (shared_ptr<const Content> i, content) {
210 if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
216 hint (String::compose (_("You have %1 files that look like they are VOB files from DVD. You should join them to ensure smooth joins between the files."), vob));
220 BOOST_FOREACH (shared_ptr<const Content> i, content) {
221 if (i->video && i->video->frame_type() != VIDEO_FRAME_TYPE_2D) {
226 if (three_d > 0 && !film->three_d()) {
227 hint (_("You are using 3D content but your DCP is set to 2D. Set the DCP to 3D if you want to play it back on a 3D system (e.g. Real-D, MasterImage etc.)"));
230 boost::filesystem::path path = film->audio_analysis_path (film->playlist ());
231 if (boost::filesystem::exists (path)) {
233 shared_ptr<AudioAnalysis> an (new AudioAnalysis (path));
237 vector<AudioAnalysis::PeakTime> sample_peak = an->sample_peak ();
238 vector<float> true_peak = an->true_peak ();
240 for (size_t i = 0; i < sample_peak.size(); ++i) {
241 float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
242 float const peak_dB = 20 * log10 (peak) + an->gain_correction (film->playlist ());
244 ch += dcp::raw_convert<string> (short_audio_channel_name (i)) + ", ";
248 ch = ch.substr (0, ch.length() - 2);
251 hint (String::compose (
252 _("Your audio level is very high (on %1). You should reduce the gain of your audio content."),
257 } catch (OldFormatError& e) {
258 /* The audio analysis is too old to load in; just skip this hint as if
259 it had never been run.
264 emit (bind(boost::ref(Progress), _("Examining closed captions")));
266 shared_ptr<Player> player (new Player (film, film->playlist ()));
267 player->set_ignore_video ();
268 player->set_ignore_audio ();
269 player->Text.connect (bind(&Hints::text, this, _1, _2, _3));
270 while (!player->pass ()) {
271 bind (boost::ref(Pulse));
274 emit (bind(boost::ref(Finished)));
278 Hints::hint (string h)
280 emit(bind(boost::ref(Hint), h));
284 Hints::text (PlayerText text, TextType type, DCPTimePeriod period)
286 if (type != TEXT_CLOSED_CAPTION) {
290 int lines = text.string.size();
291 BOOST_FOREACH (StringText i, text.string) {
292 if (i.text().length() > CLOSED_CAPTION_LENGTH) {
296 hint (String::compose(_("Some of your closed captions have lines longer than %1 characters, so they will probably be word-wrapped."), CLOSED_CAPTION_LENGTH));
301 if (!_too_many_ccap_lines && lines > CLOSED_CAPTION_LINES) {
302 hint (String::compose(_("Some of your closed captions span more than %1 lines, so they will be truncated."), CLOSED_CAPTION_LINES));
303 _too_many_ccap_lines = true;
306 if (!_overlap_ccap && _last && _last->overlap(period)) {
307 _overlap_ccap = true;
308 hint (_("You have overlapping closed captions, which are not allowed."));