C++11 tidying.
[dcpomatic.git] / src / lib / hints.cc
index cfd8a29ddfff2e42709f9c5490c09a5d27b77a2f..64122db8d5bab6be1ab41a6d14d5c68933a66d2a 100644 (file)
 
 */
 
+
+#include "audio_analysis.h"
+#include "audio_content.h"
+#include "audio_processor.h"
+#include "compose.hpp"
+#include "content.h"
+#include "cross.h"
 #include "dcp_content_type.h"
-#include "hints.h"
-#include "types.h"
 #include "film.h"
-#include "content.h"
-#include "video_content.h"
-#include "text_content.h"
-#include "audio_processor.h"
 #include "font.h"
 #include "font_data.h"
+#include "hints.h"
+#include "player.h"
 #include "ratio.h"
-#include "audio_analysis.h"
-#include "compose.hpp"
+#include "text_content.h"
+#include "types.h"
 #include "util.h"
-#include "cross.h"
-#include "player.h"
+#include "video_content.h"
 #include "writer.h"
 #include <dcp/cpl.h>
 #include <dcp/raw_convert.h>
@@ -45,6 +47,7 @@
 
 #include "i18n.h"
 
+
 using std::cout;
 using std::make_shared;
 using std::max;
@@ -73,20 +76,23 @@ using namespace boost::placeholders;
  */
 
 
-Hints::Hints (weak_ptr<const Film> film)
-       : WeakConstFilm (film)
-       , _writer (new Writer(film, weak_ptr<Job>(), true))
+Hints::Hints (weak_ptr<const Film> weak_film)
+       : WeakConstFilm (weak_film)
+       , _writer (new Writer(weak_film, weak_ptr<Job>(), true))
+       , _analyser (film(), film()->playlist(), true, [](float) {})
        , _stop (false)
 {
 
 }
 
+
 void
 Hints::start ()
 {
        _thread = boost::thread (bind(&Hints::thread, this));
 }
 
+
 Hints::~Hints ()
 {
        boost::this_thread::disable_interruption dis;
@@ -151,7 +157,7 @@ Hints::check_unusual_container ()
 {
        auto const film_container = film()->container()->id();
        if (film_container != "185" && film_container != "239") {
-               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"));
+               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."));
        }
 }
 
@@ -255,7 +261,7 @@ Hints::check_big_font_files ()
                for (auto i: film()->content()) {
                        for (auto j: i->text) {
                                for (auto k: j->fonts()) {
-                                       optional<boost::filesystem::path> const p = k->file ();
+                                       auto const p = k->file ();
                                        if (p && boost::filesystem::file_size(p.get()) >= (MAX_FONT_FILE_SIZE - SIZE_SLACK)) {
                                                big_font_files = true;
                                        }
@@ -275,7 +281,7 @@ Hints::check_vob ()
 {
        int vob = 0;
        for (auto i: film()->content()) {
-               if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
+               if (boost::algorithm::starts_with(i->path(0).filename().string(), "VTS_")) {
                        ++vob;
                }
        }
@@ -302,42 +308,46 @@ Hints::check_3d_in_2d ()
 }
 
 
-void
+/** @return true if the loudness could be checked, false if it could not because no analysis was available */
+bool
 Hints::check_loudness ()
 {
        auto path = film()->audio_analysis_path(film()->playlist());
-       if (boost::filesystem::exists (path)) {
-               try {
-                       auto an = make_shared<AudioAnalysis>(path);
+       if (!boost::filesystem::exists(path)) {
+               return false;
+       }
+
+       try {
+               auto an = make_shared<AudioAnalysis>(path);
 
-                       string ch;
+               string ch;
 
-                       auto sample_peak = an->sample_peak ();
-                       auto true_peak = an->true_peak ();
+               auto sample_peak = an->sample_peak ();
+               auto true_peak = an->true_peak ();
 
-                       for (size_t i = 0; i < sample_peak.size(); ++i) {
-                               float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
-                               float const peak_dB = linear_to_db(peak) + an->gain_correction(film()->playlist());
-                               if (peak_dB > -3) {
-                                       ch += dcp::raw_convert<string> (short_audio_channel_name (i)) + ", ";
-                               }
+               for (size_t i = 0; i < sample_peak.size(); ++i) {
+                       float const peak = max (sample_peak[i].peak, true_peak.empty() ? 0 : true_peak[i]);
+                       float const peak_dB = linear_to_db(peak) + an->gain_correction(film()->playlist());
+                       if (peak_dB > -3) {
+                               ch += dcp::raw_convert<string>(short_audio_channel_name(i)) + ", ";
                        }
+               }
 
-                       ch = ch.substr (0, ch.length() - 2);
+               ch = ch.substr (0, ch.length() - 2);
 
-                       if (!ch.empty ()) {
-                               hint (String::compose (
-                                             _("Your audio level is very high (on %1).  You should reduce the gain of your audio content."),
-                                             ch
-                                             )
-                                       );
-                       }
-               } catch (OldFormatError& e) {
-                       /* The audio analysis is too old to load in; just skip this hint as if
-                          it had never been run.
-                       */
+               if (!ch.empty()) {
+                       hint(String::compose(
+                                       _("Your audio level is very high (on %1).  You should reduce the gain of your audio content."),
+                                       ch
+                                       )
+                            );
                }
+       } catch (OldFormatError& e) {
+               /* The audio analysis is too old to load in */
+               return false;
        }
+
+       return true;
 }
 
 
@@ -363,7 +373,10 @@ Hints::check_out_of_range_markers ()
 
 void
 Hints::thread ()
+try
 {
+       start_of_thread ("Hints");
+
        auto film = _film.lock ();
        if (!film) {
                return;
@@ -383,36 +396,47 @@ Hints::thread ()
        check_speed_up ();
        check_vob ();
        check_3d_in_2d ();
-       check_loudness ();
+       auto const check_loudness_done = check_loudness ();
        check_ffec_and_ffmc_in_smpte_feature ();
        check_out_of_range_markers ();
        check_text_languages ();
+       check_audio_language ();
 
-       emit (bind(boost::ref(Progress), _("Examining subtitles and closed captions")));
+       if (check_loudness_done) {
+               emit (bind(boost::ref(Progress), _("Examining subtitles and closed captions")));
+       } else {
+               emit (bind(boost::ref(Progress), _("Examining audio, subtitles and closed captions")));
+       }
 
        auto player = make_shared<Player>(film);
        player->set_ignore_video ();
-       player->set_ignore_audio ();
+       if (check_loudness_done) {
+               /* We don't need to analyse audio because we already loaded a suitable analysis */
+               player->set_ignore_audio ();
+       }
+       player->Audio.connect (bind(&Hints::audio, this, _1, _2));
        player->Text.connect (bind(&Hints::text, this, _1, _2, _3, _4));
 
        struct timeval last_pulse;
        gettimeofday (&last_pulse, 0);
 
-       try {
-               while (!player->pass()) {
+       while (!player->pass()) {
 
-                       struct timeval now;
-                       gettimeofday (&now, 0);
-                       if ((seconds(now) - seconds(last_pulse)) > 1) {
-                               if (_stop) {
-                                       break;
-                               }
-                               emit (bind (boost::ref(Pulse)));
-                               last_pulse = now;
+               struct timeval now;
+               gettimeofday (&now, 0);
+               if ((seconds(now) - seconds(last_pulse)) > 1) {
+                       if (_stop) {
+                               return;
                        }
+                       emit (bind (boost::ref(Pulse)));
+                       last_pulse = now;
                }
-       } catch (...) {
-               store_current ();
+       }
+
+       if (!check_loudness_done) {
+               _analyser.finish ();
+               _analyser.get().write(film->audio_analysis_path(film->playlist()));
+               check_loudness ();
        }
 
        _writer->write (player->get_subtitle_fonts());
@@ -427,16 +451,10 @@ Hints::thread ()
        bool ccap_mxf_too_big = false;
        bool subs_mxf_too_big = false;
 
-       boost::filesystem::path dcp_dir = film->dir("hints") / dcpomatic::get_process_id();
+       auto dcp_dir = film->dir("hints") / dcpomatic::get_process_id();
        boost::filesystem::remove_all (dcp_dir);
 
-       try {
-               _writer->finish (film->dir("hints") / dcpomatic::get_process_id());
-       } catch (...) {
-               store_current ();
-               emit (bind(boost::ref(Finished)));
-               return;
-       }
+       _writer->finish (film->dir("hints") / dcpomatic::get_process_id());
 
        dcp::DCP dcp (dcp_dir);
        dcp.read ();
@@ -470,6 +488,15 @@ Hints::thread ()
 
        emit (bind(boost::ref(Finished)));
 }
+catch (boost::thread_interrupted)
+{
+       /* The Hints object is being destroyed before it has finished, so just give up */
+}
+catch (...)
+{
+       store_current ();
+}
+
 
 void
 Hints::hint (string h)
@@ -477,6 +504,14 @@ Hints::hint (string h)
        emit(bind(boost::ref(Hint), h));
 }
 
+
+void
+Hints::audio (shared_ptr<AudioBuffers> audio, DCPTime time)
+{
+       _analyser.analyse (audio, time);
+}
+
+
 void
 Hints::text (PlayerText text, TextType type, optional<DCPTextTrack> track, DCPTimePeriod period)
 {
@@ -603,3 +638,20 @@ Hints::check_text_languages ()
                }
        }
 }
+
+
+void
+Hints::check_audio_language ()
+{
+       auto content = film()->content();
+       auto mapped_audio =
+               std::find_if(content.begin(), content.end(), [](shared_ptr<const Content> c) {
+                       return c->audio && !c->audio->mapping().mapped_output_channels().empty();
+               });
+
+       if (mapped_audio != content.end() && !film()->audio_language()) {
+               hint (_("Some of your content has audio but you have not set the audio language.  It is advisable to set the audio language "
+                       "in the \"DCP\" tab unless your audio has no spoken parts."));
+       }
+}
+