2 Copyright (C) 2016-2020 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/>.
21 #include "dcp_content_type.h"
26 #include "video_content.h"
27 #include "text_content.h"
28 #include "audio_processor.h"
31 #include "audio_analysis.h"
32 #include "compose.hpp"
36 #include <dcp/raw_convert.h>
37 #include <boost/foreach.hpp>
38 #include <boost/algorithm/string.hpp>
49 using boost::shared_ptr;
50 using boost::weak_ptr;
51 using boost::optional;
53 using namespace dcpomatic;
54 #if BOOST_VERSION >= 106100
55 using namespace boost::placeholders;
58 Hints::Hints (weak_ptr<const Film> film)
61 , _overlap_ccap (false)
62 , _too_many_ccap_lines (false)
71 _thread = boost::thread (bind(&Hints::thread, this));
76 boost::this_thread::disable_interruption dis;
87 Hints::check_few_audio_channels ()
89 if (film()->audio_channels() < 6) {
90 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."));
96 Hints::check_upmixers ()
98 AudioProcessor const * ap = film()->audio_processor();
99 if (ap && (ap->id() == "stereo-5.1-upmix-a" || ap->id() == "stereo-5.1-upmix-b")) {
100 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."));
106 Hints::check_incorrect_container ()
108 int narrower_than_scope = 0;
110 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
112 Ratio const * r = Ratio::nearest_from_ratio(i->video->scaled_size(film()->frame_size()).ratio());
113 if (r && r->id() == "239") {
115 } else if (r && r->id() != "239" && r->id() != "235" && r->id() != "190") {
116 ++narrower_than_scope;
121 string const film_container = film()->container()->id();
123 if (scope && !narrower_than_scope && film_container == "185") {
124 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."));
127 if (!scope && narrower_than_scope && film_container == "239") {
128 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."));
134 Hints::check_unusual_container ()
136 string const film_container = film()->container()->id();
137 if (film_container != "185" && film_container != "239" && film_container != "190") {
138 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"));
144 Hints::check_high_j2k_bandwidth ()
146 if (film()->j2k_bandwidth() >= 245000000) {
147 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."));
153 Hints::check_frame_rate ()
155 shared_ptr<const Film> f = film ();
156 switch (f->video_frame_rate()) {
162 /* You might want to go to 24 */
163 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);
166 base += _("If you do use 25fps you should change your DCP standard to SMPTE.");
172 /* 30fps: we can't really offer any decent solutions */
173 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."));
178 /* You almost certainly want to go to half frame rate */
179 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));
186 Hints::check_speed_up ()
188 optional<double> lowest_speed_up;
189 optional<double> highest_speed_up;
190 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
191 double spu = film()->active_frame_rate_change(i->position()).speed_up;
192 if (!lowest_speed_up || spu < *lowest_speed_up) {
193 lowest_speed_up = spu;
195 if (!highest_speed_up || spu > *highest_speed_up) {
196 highest_speed_up = spu;
200 double worst_speed_up = 1;
201 if (highest_speed_up) {
202 worst_speed_up = *highest_speed_up;
204 if (lowest_speed_up) {
205 worst_speed_up = max (worst_speed_up, 1 / *lowest_speed_up);
208 if (worst_speed_up > 25.5/24.0) {
209 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."));
216 Hints::check_big_font_files ()
218 bool big_font_files = false;
219 if (film()->interop ()) {
220 BOOST_FOREACH (shared_ptr<Content> i, film()->content()) {
221 BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
222 BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
223 optional<boost::filesystem::path> const p = k->file ();
224 if (p && boost::filesystem::file_size(p.get()) >= (640 * 1024)) {
225 big_font_files = true;
232 if (big_font_files) {
233 hint (_("You have specified a font file which is larger than 640kB. This is very likely to cause problems on playback."));
242 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
243 if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
249 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));
255 Hints::check_3d_in_2d ()
258 BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
259 if (i->video && i->video->frame_type() != VIDEO_FRAME_TYPE_2D) {
264 if (three_d > 0 && !film()->three_d()) {
265 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.)"));
271 Hints::check_loudness ()
273 boost::filesystem::path path = film()->audio_analysis_path(film()->playlist());
274 if (boost::filesystem::exists (path)) {
276 shared_ptr<AudioAnalysis> an (new AudioAnalysis (path));
280 vector<AudioAnalysis::PeakTime> sample_peak = an->sample_peak ();
281 vector<float> true_peak = an->true_peak ();
283 for (size_t i = 0; i < sample_peak.size(); ++i) {
284 float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
285 float const peak_dB = linear_to_db(peak) + an->gain_correction(film()->playlist());
287 ch += dcp::raw_convert<string> (short_audio_channel_name (i)) + ", ";
291 ch = ch.substr (0, ch.length() - 2);
294 hint (String::compose (
295 _("Your audio level is very high (on %1). You should reduce the gain of your audio content."),
300 } catch (OldFormatError& e) {
301 /* The audio analysis is too old to load in; just skip this hint as if
302 it had never been run.
312 shared_ptr<const Film> film = _film.lock ();
317 ContentList content = film->content ();
319 check_big_font_files ();
320 check_few_audio_channels ();
322 check_incorrect_container ();
323 check_unusual_container ();
324 check_high_j2k_bandwidth ();
330 check_ffec_and_ffmc_in_smpte_feature ();
332 emit (bind(boost::ref(Progress), _("Examining closed captions")));
334 shared_ptr<Player> player (new Player(film));
335 player->set_ignore_video ();
336 player->set_ignore_audio ();
337 player->Text.connect (bind(&Hints::text, this, _1, _2, _4));
339 struct timeval last_pulse;
340 gettimeofday (&last_pulse, 0);
343 while (!player->pass()) {
346 gettimeofday (&now, 0);
347 if ((seconds(now) - seconds(last_pulse)) > 1) {
351 emit (bind (boost::ref(Pulse)));
359 emit (bind(boost::ref(Finished)));
363 Hints::hint (string h)
365 emit(bind(boost::ref(Hint), h));
369 Hints::text (PlayerText text, TextType type, DCPTimePeriod period)
371 if (type != TEXT_CLOSED_CAPTION) {
375 int lines = text.string.size();
376 BOOST_FOREACH (StringText i, text.string) {
377 if (utf8_strlen(i.text()) > CLOSED_CAPTION_LENGTH) {
381 hint (String::compose(_("Some of your closed captions have lines longer than %1 characters, so they will probably be word-wrapped."), CLOSED_CAPTION_LENGTH));
386 if (!_too_many_ccap_lines && lines > CLOSED_CAPTION_LINES) {
387 hint (String::compose(_("Some of your closed captions span more than %1 lines, so they will be truncated."), CLOSED_CAPTION_LINES));
388 _too_many_ccap_lines = true;
391 /* XXX: maybe overlapping closed captions (i.e. different languages) are OK with Interop? */
392 if (film()->interop() && !_overlap_ccap && _last && _last->overlap(period)) {
393 _overlap_ccap = true;
394 hint (_("You have overlapping closed captions, which are not allowed in Interop DCPs. Change your DCP standard to SMPTE."));
401 shared_ptr<const Film>
404 shared_ptr<const Film> film = _film.lock ();
405 DCPOMATIC_ASSERT (film);
411 Hints::check_ffec_and_ffmc_in_smpte_feature ()
413 shared_ptr<const Film> f = film();
414 if (!f->interop() && f->dcp_content_type()->libdcp_kind() == dcp::FEATURE && (!f->marker(dcp::FFEC) || !f->marker(dcp::FFMC))) {
415 hint (_("SMPTE DCPs with the type FTR (feature) should have markers for the first frame of end credits (FFEC) and the first frame of moving credits (FFMC). You should add these markers using the 'Markers' button in the DCP tab."));