2 Copyright (C) 2016-2019 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;
52 using namespace dcpomatic;
53 #if BOOST_VERSION >= 106100
54 using namespace boost::placeholders;
57 Hints::Hints (weak_ptr<const Film> film)
60 , _overlap_ccap (false)
61 , _too_many_ccap_lines (false)
70 _thread = boost::thread (bind(&Hints::thread, this));
75 boost::this_thread::disable_interruption dis;
86 Hints::check_few_audio_channels ()
88 if (film()->audio_channels() < 6) {
89 hint (_("Your DCP has fewer than 6 audio channels. This may cause problems on some projectors. You may want to set the DCP to have 6 channels. It does not matter if your content has fewer channels, as DCP-o-matic will fill the extras with silence."));
95 Hints::check_upmixers ()
97 AudioProcessor const * ap = film()->audio_processor();
98 if (ap && (ap->id() == "stereo-5.1-upmix-a" || ap->id() == "stereo-5.1-upmix-b")) {
99 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."));
105 Hints::check_incorrect_container ()
107 int narrower_than_scope = 0;
109 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
111 Ratio const * r = Ratio::nearest_from_ratio(i->video->scaled_size(film()->frame_size()).ratio());
112 if (r && r->id() == "239") {
114 } else if (r && r->id() != "239" && r->id() != "235" && r->id() != "190") {
115 ++narrower_than_scope;
120 string const film_container = film()->container()->id();
122 if (scope && !narrower_than_scope && film_container == "185") {
123 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."));
126 if (!scope && narrower_than_scope && film_container == "239") {
127 hint (_("All of your content narrower than 1.90:1 but your DCP's container is Scope (2.39:1). This will pillar-box your content. You may prefer to set your DCP's container to have the same ratio as your content."));
133 Hints::check_unusual_container ()
135 string const film_container = film()->container()->id();
136 if (film_container != "185" && film_container != "239" && film_container != "190") {
137 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"));
143 Hints::check_high_j2k_bandwidth ()
145 if (film()->j2k_bandwidth() >= 245000000) {
146 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."));
152 Hints::check_frame_rate ()
154 shared_ptr<const Film> f = film ();
155 switch (f->video_frame_rate()) {
161 /* You might want to go to 24 */
162 string base = String::compose(_("You are set up for a DCP at a frame rate of %1 fps. This frame rate is not supported by all projectors. You may want to consider changing your frame rate to %2 fps."), 25, 24);
165 base += _("If you do use 25fps you should change your DCP standard to SMPTE.");
171 /* 30fps: we can't really offer any decent solutions */
172 hint (_("You are set up for a DCP frame rate of 30fps, which is not supported by all projectors. Be aware that you may have compatibility problems."));
177 /* You almost certainly want to go to half frame rate */
178 hint (String::compose(_("You are set up for a DCP at a frame rate of %1 fps. This frame rate is not supported by all projectors. You are advised to change the DCP frame rate to %2 fps."), f->video_frame_rate(), f->video_frame_rate() / 2));
185 Hints::check_speed_up ()
187 optional<double> lowest_speed_up;
188 optional<double> highest_speed_up;
189 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
190 double spu = film()->active_frame_rate_change(i->position()).speed_up;
191 if (!lowest_speed_up || spu < *lowest_speed_up) {
192 lowest_speed_up = spu;
194 if (!highest_speed_up || spu > *highest_speed_up) {
195 highest_speed_up = spu;
199 double worst_speed_up = 1;
200 if (highest_speed_up) {
201 worst_speed_up = *highest_speed_up;
203 if (lowest_speed_up) {
204 worst_speed_up = max (worst_speed_up, 1 / *lowest_speed_up);
207 if (worst_speed_up > 25.5/24.0) {
208 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 Hints::check_big_font_files ()
217 bool big_font_files = false;
218 if (film()->interop ()) {
219 BOOST_FOREACH (shared_ptr<Content> i, film()->content()) {
220 BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
221 BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
222 optional<boost::filesystem::path> const p = k->file ();
223 if (p && boost::filesystem::file_size(p.get()) >= (640 * 1024)) {
224 big_font_files = true;
231 if (big_font_files) {
232 hint (_("You have specified a font file which is larger than 640kB. This is very likely to cause problems on playback."));
241 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
242 if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
248 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));
254 Hints::check_3d_in_2d ()
257 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
258 if (i->video && i->video->frame_type() != VIDEO_FRAME_TYPE_2D) {
263 if (three_d > 0 && !film()->three_d()) {
264 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.)"));
270 Hints::check_loudness ()
272 boost::filesystem::path path = film()->audio_analysis_path(film()->playlist());
273 if (boost::filesystem::exists (path)) {
275 shared_ptr<AudioAnalysis> an (new AudioAnalysis (path));
279 vector<AudioAnalysis::PeakTime> sample_peak = an->sample_peak ();
280 vector<float> true_peak = an->true_peak ();
282 for (size_t i = 0; i < sample_peak.size(); ++i) {
283 float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
284 float const peak_dB = linear_to_db(peak) + an->gain_correction(film()->playlist());
286 ch += dcp::raw_convert<string> (short_audio_channel_name (i)) + ", ";
290 ch = ch.substr (0, ch.length() - 2);
293 hint (String::compose (
294 _("Your audio level is very high (on %1). You should reduce the gain of your audio content."),
299 } catch (OldFormatError& e) {
300 /* The audio analysis is too old to load in; just skip this hint as if
301 it had never been run.
311 shared_ptr<const Film> film = _film.lock ();
316 ContentList content = film->content ();
318 check_big_font_files ();
319 check_few_audio_channels ();
321 check_incorrect_container ();
322 check_unusual_container ();
323 check_high_j2k_bandwidth ();
330 emit (bind(boost::ref(Progress), _("Examining closed captions")));
332 shared_ptr<Player> player (new Player(film));
333 player->set_ignore_video ();
334 player->set_ignore_audio ();
335 player->Text.connect (bind(&Hints::text, this, _1, _2, _4));
337 struct timeval last_pulse;
338 gettimeofday (&last_pulse, 0);
341 while (!player->pass()) {
344 gettimeofday (&now, 0);
345 if ((seconds(now) - seconds(last_pulse)) > 1) {
349 emit (bind (boost::ref(Pulse)));
357 emit (bind(boost::ref(Finished)));
361 Hints::hint (string h)
363 emit(bind(boost::ref(Hint), h));
367 Hints::text (PlayerText text, TextType type, DCPTimePeriod period)
369 if (type != TEXT_CLOSED_CAPTION) {
373 int lines = text.string.size();
374 BOOST_FOREACH (StringText i, text.string) {
375 if (utf8_strlen(i.text()) > CLOSED_CAPTION_LENGTH) {
379 hint (String::compose(_("Some of your closed captions have lines longer than %1 characters, so they will probably be word-wrapped."), CLOSED_CAPTION_LENGTH));
384 if (!_too_many_ccap_lines && lines > CLOSED_CAPTION_LINES) {
385 hint (String::compose(_("Some of your closed captions span more than %1 lines, so they will be truncated."), CLOSED_CAPTION_LINES));
386 _too_many_ccap_lines = true;
389 /* XXX: maybe overlapping closed captions (i.e. different languages) are OK with Interop? */
390 if (film()->interop() && !_overlap_ccap && _last && _last->overlap(period)) {
391 _overlap_ccap = true;
392 hint (_("You have overlapping closed captions, which are not allowed in Interop DCPs. Change your DCP standard to SMPTE."));
399 shared_ptr<const Film>
402 shared_ptr<const Film> film = _film.lock ();
403 DCPOMATIC_ASSERT (film);