Allow specification of video bit rate separately for J2K and MPEG2.
[dcpomatic.git] / src / lib / hints.cc
index 3558d7a25c1dceb019db44218f0c98b8ee4c4907..8e678fdf15987916c48f48593d9a9b1680d28c0a 100644 (file)
 #include "player.h"
 #include "ratio.h"
 #include "text_content.h"
+#include "variant.h"
 #include "video_content.h"
 #include "writer.h"
 #include <dcp/cpl.h>
+#include <dcp/filesystem.h>
 #include <dcp/raw_convert.h>
 #include <dcp/reel.h>
 #include <dcp/reel_closed_caption_asset.h>
@@ -106,7 +108,13 @@ void
 Hints::check_few_audio_channels ()
 {
        if (film()->audio_channels() < 6) {
-               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."));
+               hint(
+                       variant::insert_dcpomatic(
+                               _("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 %1 will fill the extras with silence.")
+                               )
+                   );
        }
 }
 
@@ -116,7 +124,12 @@ Hints::check_upmixers ()
 {
        auto ap = film()->audio_processor();
        if (ap && (ap->id() == "stereo-5.1-upmix-a" || ap->id() == "stereo-5.1-upmix-b")) {
-               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."));
+               hint(variant::insert_dcpomatic(
+                               _("You are using %1'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.")
+                               )
+                   );
        }
 }
 
@@ -127,8 +140,8 @@ Hints::check_incorrect_container ()
        int narrower_than_scope = 0;
        int scope = 0;
        for (auto i: film()->content()) {
-               if (i->video) {
-                       auto const r = Ratio::nearest_from_ratio(i->video->scaled_size(film()->frame_size()).ratio());
+               if (i->video && i->video->size()) {
+                       auto const r = Ratio::nearest_from_ratio(i->video->scaled_size(film()->frame_size())->ratio());
                        if (r && r->id() == "239") {
                                ++scope;
                        } else if (r && r->id() != "239" && r->id() != "235" && r->id() != "190") {
@@ -160,10 +173,10 @@ Hints::check_unusual_container ()
 
 
 void
-Hints::check_high_j2k_bandwidth ()
+Hints::check_high_video_bit_rate()
 {
-       if (film()->j2k_bandwidth() >= 245000000) {
-               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."));
+       if (film()->video_encoding() == VideoEncoding::JPEG2000 && film()->video_bit_rate(VideoEncoding::JPEG2000) >= 245000000) {
+               hint (_("A few projectors have problems playing back very high bit-rate DCPs.  It is a good idea to drop the video bit rate down to about 200Mbit/s; this is unlikely to have any visible effect on the image."));
        }
 }
 
@@ -195,7 +208,7 @@ Hints::check_frame_rate ()
        case 50:
        case 60:
                /* You almost certainly want to go to half frame rate */
-               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));
+               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.  It is advisable to change the DCP frame rate to %2 fps."), f->video_frame_rate(), f->video_frame_rate() / 2));
                break;
        }
 }
@@ -235,7 +248,7 @@ Hints::check_speed_up ()
        }
 
        if (worst_speed_up > 25.5/24.0) {
-               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."));
+               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.  It is advisable to set your DCP frame rate to one closer to your content, provided that your target projection systems support your chosen DCP rate."));
        }
 
 }
@@ -245,7 +258,7 @@ void
 Hints::check_interop ()
 {
        if (film()->interop()) {
-               hint (_("In general it is now advisable to make SMPTE DCPs unless you have a particular reason to use Interop.  You are advised to set your DCP to use the SMPTE standard in the \"DCP\" tab."));
+               hint (_("In general it is now advisable to make SMPTE DCPs unless you have a particular reason to use Interop.  It is advisable to set your DCP to use the SMPTE standard in the \"DCP\" tab."));
        }
 }
 
@@ -259,7 +272,7 @@ Hints::check_big_font_files ()
                        for (auto j: i->text) {
                                for (auto k: j->fonts()) {
                                        auto const p = k->file ();
-                                       if (p && boost::filesystem::file_size(p.get()) >= (MAX_FONT_FILE_SIZE - SIZE_SLACK)) {
+                                       if (p && dcp::filesystem::file_size(p.get()) >= (MAX_FONT_FILE_SIZE - SIZE_SLACK)) {
                                                big_font_files = true;
                                        }
                                }
@@ -310,7 +323,7 @@ bool
 Hints::check_loudness ()
 {
        auto path = film()->audio_analysis_path(film()->playlist());
-       if (!boost::filesystem::exists(path)) {
+       if (!dcp::filesystem::exists(path)) {
                return false;
        }
 
@@ -352,7 +365,7 @@ static
 bool
 subtitle_mxf_too_big (shared_ptr<dcp::SubtitleAsset> asset)
 {
-       return asset && asset->file() && boost::filesystem::file_size(*asset->file()) >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK);
+       return asset && asset->file() && dcp::filesystem::file_size(*asset->file()) >= (MAX_TEXT_MXF_SIZE - SIZE_SLACK);
 }
 
 
@@ -369,77 +382,105 @@ Hints::check_out_of_range_markers ()
 
 
 void
-Hints::thread ()
-try
+Hints::scan_content(shared_ptr<const Film> film)
 {
-       start_of_thread ("Hints");
+       auto const check_loudness_done = check_loudness();
 
-       auto film = _film.lock ();
-       if (!film) {
-               return;
-       }
+       auto content = film->playlist()->content();
+       auto iter = std::find_if(content.begin(), content.end(), [](shared_ptr<const Content> content) {
+               auto text_iter = std::find_if(content->text.begin(), content->text.end(), [](shared_ptr<const TextContent> text) {
+                       return text->use();
+               });
+               return text_iter != content->text.end();
+       });
 
-       auto content = film->content ();
+       auto const have_text = iter != content.end();
 
-       check_certificates ();
-       check_interop ();
-       check_big_font_files ();
-       check_few_audio_channels ();
-       check_upmixers ();
-       check_incorrect_container ();
-       check_unusual_container ();
-       check_high_j2k_bandwidth ();
-       check_frame_rate ();
-       check_4k_3d ();
-       check_speed_up ();
-       check_vob ();
-       check_3d_in_2d ();
-       auto const check_loudness_done = check_loudness ();
-       check_ffec_and_ffmc_in_smpte_feature ();
-       check_out_of_range_markers ();
-       check_subtitle_languages();
-       check_audio_language ();
-       check_8_or_16_audio_channels();
+       if (check_loudness_done && !have_text) {
+               /* We don't need to check loudness, and we don't have any active text to check,
+                * so a scan of the content is pointless.
+                */
+               return;
+       }
 
-       if (check_loudness_done) {
+       if (check_loudness_done && have_text) {
                emit (bind(boost::ref(Progress), _("Examining subtitles and closed captions")));
+       } else if (!check_loudness_done && !have_text) {
+               emit (bind(boost::ref(Progress), _("Examining audio")));
        } else {
                emit (bind(boost::ref(Progress), _("Examining audio, subtitles and closed captions")));
        }
 
        auto player = make_shared<Player>(film, Image::Alignment::COMPACT);
-       player->set_ignore_video ();
+       player->set_ignore_video();
        if (check_loudness_done || _disable_audio_analysis) {
                /* We don't need to analyse audio because we already loaded a suitable analysis */
-               player->set_ignore_audio ();
+               player->set_ignore_audio();
+       } else {
+               /* Send auto to the analyser to check loudness */
+               player->Audio.connect(bind(&Hints::audio, this, _1, _2));
        }
-       player->Audio.connect (bind(&Hints::audio, this, _1, _2));
-       player->Text.connect (bind(&Hints::text, this, _1, _2, _3, _4));
+       player->Text.connect(bind(&Hints::text, this, _1, _2, _3, _4));
 
        struct timeval last_pulse;
-       gettimeofday (&last_pulse, 0);
+       gettimeofday(&last_pulse, 0);
 
-       _writer->write (player->get_subtitle_fonts());
+       _writer->write(player->get_subtitle_fonts());
 
        while (!player->pass()) {
 
                struct timeval now;
-               gettimeofday (&now, 0);
+               gettimeofday(&now, 0);
                if ((seconds(now) - seconds(last_pulse)) > 1) {
                        if (_stop) {
                                return;
                        }
-                       emit (bind (boost::ref(Pulse)));
+                       emit(bind(boost::ref(Pulse)));
                        last_pulse = now;
                }
        }
 
        if (!check_loudness_done) {
-               _analyser.finish ();
+               _analyser.finish();
                _analyser.get().write(film->audio_analysis_path(film->playlist()));
-               check_loudness ();
+               check_loudness();
+       }
+}
+
+
+void
+Hints::thread ()
+try
+{
+       start_of_thread ("Hints");
+
+       auto film = _film.lock ();
+       if (!film) {
+               return;
        }
 
+       auto content = film->content ();
+
+       check_certificates ();
+       check_interop ();
+       check_big_font_files ();
+       check_few_audio_channels ();
+       check_upmixers ();
+       check_incorrect_container ();
+       check_unusual_container ();
+       check_high_video_bit_rate();
+       check_frame_rate ();
+       check_4k_3d ();
+       check_speed_up ();
+       check_vob ();
+       check_3d_in_2d ();
+       check_ffec_and_ffmc_in_smpte_feature ();
+       check_out_of_range_markers ();
+       check_subtitle_languages();
+       check_audio_language ();
+       check_8_or_16_audio_channels();
+
+       scan_content(film);
 
        if (_long_subtitle && !_very_long_subtitle) {
                hint (_("At least one of your subtitle lines has more than 52 characters.  It is recommended to make each line 52 characters at most in length."));
@@ -452,7 +493,7 @@ try
        bool subs_mxf_too_big = false;
 
        auto dcp_dir = film->dir("hints") / dcpomatic::get_process_id();
-       boost::filesystem::remove_all (dcp_dir);
+       dcp::filesystem::remove_all(dcp_dir);
 
        _writer->finish (film->dir("hints") / dcpomatic::get_process_id());
 
@@ -484,7 +525,7 @@ try
                        subs_mxf_too_big = true;
                }
        }
-       boost::filesystem::remove_all (dcp_dir);
+       dcp::filesystem::remove_all(dcp_dir);
 
        emit (bind(boost::ref(Finished)));
 }
@@ -689,16 +730,20 @@ Hints::check_certificates ()
 
        switch (*bad) {
        case Config::BAD_SIGNER_UTF8_STRINGS:
-               hint(_("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs contains a small error "
-                      "which will prevent DCPs from being validated correctly on some systems.  You are advised to "
-                      "re-create the signing certificate chain by clicking the \"Re-make certificates and key...\" "
-                      "button in the Keys page of Preferences."));
+               hint(variant::insert_dcpomatic(
+                               _("The certificate chain that %1 uses for signing DCPs and KDMs contains a small error "
+                                 "which will prevent DCPs from being validated correctly on some systems.  It is advisable to "
+                                 "re-create the signing certificate chain by clicking the \"Re-make certificates and key...\" "
+                                 "button in the Keys page of Preferences.")
+                               ));
                break;
        case Config::BAD_SIGNER_VALIDITY_TOO_LONG:
-               hint(_("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs has a validity period "
-                      "that is too long.  This will cause problems playing back DCPs on some systems. "
-                      "You are advised to re-create the signing certificate chain by clicking the "
-                      "\"Re-make certificates and key...\" button in the Keys page of Preferences."));
+               hint(variant::insert_dcpomatic(
+                               _("The certificate chain that %1 uses for signing DCPs and KDMs has a validity period "
+                                 "that is too long.  This will cause problems playing back DCPs on some systems. "
+                                 "It is advisable to re-create the signing certificate chain by clicking the "
+                                 "\"Re-make certificates and key...\" button in the Keys page of Preferences.")
+                               ));
                break;
        default:
                /* Some bad situations can't happen here as DCP-o-matic would have refused to start until they are fixed */