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)
70 boost::mutex::scoped_lock lm (_mutex);
73 _thread->interrupt ();
94 _overlap_ccap = false;
95 _too_many_ccap_lines = false;
97 _thread = new boost::thread (bind(&Hints::thread, this));
103 shared_ptr<const Film> film = _film.lock ();
108 ContentList content = film->content ();
110 bool big_font_files = false;
111 if (film->interop ()) {
112 BOOST_FOREACH (shared_ptr<Content> i, content) {
113 BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
114 BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
115 for (int l = 0; l < FontFiles::VARIANTS; ++l) {
116 optional<boost::filesystem::path> const p = k->file (static_cast<FontFiles::Variant>(l));
117 if (p && boost::filesystem::file_size (p.get()) >= (640 * 1024)) {
118 big_font_files = true;
126 if (big_font_files) {
127 hint (_("You have specified a font file which is larger than 640kB. This is very likely to cause problems on playback."));
130 if (film->audio_channels() < 6) {
131 hint (_("Your DCP has fewer than 6 audio channels. This may cause problems on some projectors."));
134 AudioProcessor const * ap = film->audio_processor();
135 if (ap && (ap->id() == "stereo-5.1-upmix-a" || ap->id() == "stereo-5.1-upmix-b")) {
136 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."));
139 int flat_or_narrower = 0;
141 BOOST_FOREACH (shared_ptr<const Content> i, content) {
143 Ratio const * r = i->video->scale().ratio ();
144 if (r && r->id() == "239") {
146 } else if (r && r->id() != "239" && r->id() != "190") {
152 string const film_container = film->container()->id();
154 if (scope && !flat_or_narrower && film_container == "185") {
155 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."));
158 if (!scope && flat_or_narrower && film_container == "239") {
159 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."));
162 if (film_container != "185" && film_container != "239" && film_container != "190") {
163 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"));
166 if (film->j2k_bandwidth() >= 245000000) {
167 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."));
170 if (film->interop() && film->video_frame_rate() != 24 && film->video_frame_rate() != 48) {
171 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.");
173 pair<double, double> range24 = film->speed_up_range (24);
174 pair<double, double> range48 = film->speed_up_range (48);
175 pair<double, double> range (max (range24.first, range48.first), min (range24.second, range48.second));
177 if (range.second > (29.0/24)) {
179 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.");
180 } else if (range.first < (24.0/29)) {
182 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.");
184 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).");
190 optional<double> lowest_speed_up;
191 optional<double> highest_speed_up;
192 BOOST_FOREACH (shared_ptr<const Content> i, content) {
193 double spu = film->active_frame_rate_change(i->position()).speed_up;
194 if (!lowest_speed_up || spu < *lowest_speed_up) {
195 lowest_speed_up = spu;
197 if (!highest_speed_up || spu > *highest_speed_up) {
198 highest_speed_up = spu;
202 double worst_speed_up = 1;
203 if (highest_speed_up) {
204 worst_speed_up = *highest_speed_up;
206 if (lowest_speed_up) {
207 worst_speed_up = max (worst_speed_up, 1 / *lowest_speed_up);
210 if (worst_speed_up > 25.5/24.0) {
211 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."));
215 BOOST_FOREACH (shared_ptr<const Content> i, content) {
216 if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
222 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));
226 BOOST_FOREACH (shared_ptr<const Content> i, content) {
227 if (i->video && i->video->frame_type() != VIDEO_FRAME_TYPE_2D) {
232 if (three_d > 0 && !film->three_d()) {
233 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.)"));
236 boost::filesystem::path path = film->audio_analysis_path (film->playlist ());
237 if (boost::filesystem::exists (path)) {
239 shared_ptr<AudioAnalysis> an (new AudioAnalysis (path));
243 vector<AudioAnalysis::PeakTime> sample_peak = an->sample_peak ();
244 vector<float> true_peak = an->true_peak ();
246 for (size_t i = 0; i < sample_peak.size(); ++i) {
247 float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
248 float const peak_dB = 20 * log10 (peak) + an->gain_correction (film->playlist ());
250 ch += dcp::raw_convert<string> (short_audio_channel_name (i)) + ", ";
254 ch = ch.substr (0, ch.length() - 2);
257 hint (String::compose (
258 _("Your audio level is very high (on %1). You should reduce the gain of your audio content."),
263 } catch (OldFormatError& e) {
264 /* The audio analysis is too old to load in; just skip this hint as if
265 it had never been run.
270 emit (bind(boost::ref(Progress), _("Examining closed captions")));
272 shared_ptr<Player> player (new Player (film, film->playlist ()));
273 player->set_ignore_video ();
274 player->set_ignore_audio ();
275 player->Text.connect (bind(&Hints::text, this, _1, _2, _4));
277 struct timeval last_pulse;
278 gettimeofday (&last_pulse, 0);
280 while (!player->pass()) {
283 gettimeofday (&now, 0);
284 if ((seconds(now) - seconds(last_pulse)) > 1) {
286 boost::mutex::scoped_lock lm (_mutex);
291 emit (bind (boost::ref(Pulse)));
296 emit (bind(boost::ref(Finished)));
300 Hints::hint (string h)
302 emit(bind(boost::ref(Hint), h));
306 Hints::text (PlayerText text, TextType type, DCPTimePeriod period)
308 if (type != TEXT_CLOSED_CAPTION) {
312 int lines = text.string.size();
313 BOOST_FOREACH (StringText i, text.string) {
314 if (utf8_strlen(i.text()) > CLOSED_CAPTION_LENGTH) {
318 hint (String::compose(_("Some of your closed captions have lines longer than %1 characters, so they will probably be word-wrapped."), CLOSED_CAPTION_LENGTH));
323 if (!_too_many_ccap_lines && lines > CLOSED_CAPTION_LINES) {
324 hint (String::compose(_("Some of your closed captions span more than %1 lines, so they will be truncated."), CLOSED_CAPTION_LINES));
325 _too_many_ccap_lines = true;
328 if (!_overlap_ccap && _last && _last->overlap(period)) {
329 _overlap_ccap = true;
330 hint (_("You have overlapping closed captions, which are not allowed."));