Use enum class for VideoRange.
[dcpomatic.git] / src / lib / hints.cc
index 5c9d3d8a41964fc96a33384dce8a2561f7129ffd..ebc42bc918f092a76c881c73df49e665c8c54934 100644 (file)
 #include "text_content.h"
 #include "audio_processor.h"
 #include "font.h"
+#include "font_data.h"
 #include "ratio.h"
 #include "audio_analysis.h"
 #include "compose.hpp"
 #include "util.h"
 #include "cross.h"
 #include "player.h"
+#include "writer.h"
+#include <dcp/cpl.h>
 #include <dcp/raw_convert.h>
-#include <boost/foreach.hpp>
+#include <dcp/reel.h>
+#include <dcp/reel_closed_caption_asset.h>
+#include <dcp/reel_subtitle_asset.h>
 #include <boost/algorithm/string.hpp>
 #include <iostream>
 
@@ -46,8 +51,8 @@ using std::pair;
 using std::min;
 using std::max;
 using std::cout;
-using boost::shared_ptr;
-using boost::weak_ptr;
+using std::shared_ptr;
+using std::weak_ptr;
 using boost::optional;
 using boost::bind;
 using namespace dcpomatic;
@@ -55,8 +60,16 @@ using namespace dcpomatic;
 using namespace boost::placeholders;
 #endif
 
+
+/* When checking to see if things are too big, we'll say they are if they
+ * are more than the target size minus this "slack."
+ */
+#define SIZE_SLACK 4096
+
+
 Hints::Hints (weak_ptr<const Film> film)
        : WeakConstFilm (film)
+       , _writer (new Writer(film, weak_ptr<Job>(), true))
        , _long_ccap (false)
        , _overlap_ccap (false)
        , _too_many_ccap_lines (false)
@@ -112,7 +125,7 @@ Hints::check_incorrect_container ()
 {
        int narrower_than_scope = 0;
        int scope = 0;
-       BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
+       for (auto i: film()->content()) {
                if (i->video) {
                        Ratio const * r = Ratio::nearest_from_ratio(i->video->scaled_size(film()->frame_size()).ratio());
                        if (r && r->id() == "239") {
@@ -192,7 +205,7 @@ Hints::check_speed_up ()
 {
        optional<double> lowest_speed_up;
        optional<double> highest_speed_up;
-       BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
+       for (auto i: film()->content()) {
                double spu = film()->active_frame_rate_change(i->position()).speed_up;
                if (!lowest_speed_up || spu < *lowest_speed_up) {
                        lowest_speed_up = spu;
@@ -222,11 +235,11 @@ Hints::check_big_font_files ()
 {
        bool big_font_files = false;
        if (film()->interop ()) {
-               BOOST_FOREACH (shared_ptr<Content> i, film()->content()) {
-                       BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
-                               BOOST_FOREACH (shared_ptr<Font> k, j->fonts()) {
+               for (auto i: film()->content()) {
+                       for (auto j: i->text) {
+                               for (auto k: j->fonts()) {
                                        optional<boost::filesystem::path> const p = k->file ();
-                                       if (p && boost::filesystem::file_size(p.get()) >= (640 * 1024)) {
+                                       if (p && boost::filesystem::file_size(p.get()) >= (MAX_FONT_FILE_SIZE - SIZE_SLACK)) {
                                                big_font_files = true;
                                        }
                                }
@@ -244,7 +257,7 @@ void
 Hints::check_vob ()
 {
        int vob = 0;
-       BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
+       for (auto i: film()->content()) {
                if (boost::algorithm::starts_with (i->path(0).filename().string(), "VTS_")) {
                        ++vob;
                }
@@ -260,7 +273,7 @@ void
 Hints::check_3d_in_2d ()
 {
        int three_d = 0;
-       BOOST_FOREACH (shared_ptr<const Content> i, film()->content()) {
+       for (auto i: film()->content()) {
                if (i->video && i->video->frame_type() != VIDEO_FRAME_TYPE_2D) {
                        ++three_d;
                }
@@ -311,6 +324,14 @@ Hints::check_loudness ()
 }
 
 
+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);
+}
+
+
 void
 Hints::thread ()
 {
@@ -339,7 +360,7 @@ Hints::thread ()
        shared_ptr<Player> player (new Player(film));
        player->set_ignore_video ();
        player->set_ignore_audio ();
-       player->Text.connect (bind(&Hints::text, this, _1, _2, _4));
+       player->Text.connect (bind(&Hints::text, this, _1, _2, _3, _4));
 
        struct timeval last_pulse;
        gettimeofday (&last_pulse, 0);
@@ -361,6 +382,53 @@ Hints::thread ()
                store_current ();
        }
 
+       _writer->write (player->get_subtitle_fonts());
+
+       bool ccap_xml_too_big = false;
+       bool ccap_mxf_too_big = false;
+       bool subs_mxf_too_big = false;
+
+       boost::filesystem::path 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;
+       }
+
+       dcp::DCP dcp (dcp_dir);
+       dcp.read ();
+       DCPOMATIC_ASSERT (dcp.cpls().size() == 1);
+       for (auto reel: dcp.cpls().front()->reels()) {
+               for (auto ccap: reel->closed_captions()) {
+                       if (ccap->asset() && ccap->asset()->xml_as_string().length() > static_cast<size_t>(MAX_CLOSED_CAPTION_XML_SIZE - SIZE_SLACK) && !ccap_xml_too_big) {
+                               hint (_(
+                                               "At least one of your closed caption files' XML part is larger than " MAX_CLOSED_CAPTION_XML_SIZE_TEXT
+                                               ".  You should divide the DCP into shorter reels."
+                                      ));
+                               ccap_xml_too_big = true;
+                       }
+                       if (subtitle_mxf_too_big(ccap->asset()) && !ccap_mxf_too_big) {
+                               hint (_(
+                                               "At least one of your closed caption files is larger than " MAX_TEXT_MXF_SIZE_TEXT
+                                               " in total.  You should divide the DCP into shorter reels."
+                                      ));
+                               ccap_mxf_too_big = true;
+                       }
+               }
+               if (reel->main_subtitle() && subtitle_mxf_too_big(reel->main_subtitle()->asset()) && !subs_mxf_too_big) {
+                       hint (_(
+                                       "At least one of your subtitle files is larger than " MAX_TEXT_MXF_SIZE_TEXT " in total.  "
+                                       "You should divide the DCP into shorter reels."
+                              ));
+                       subs_mxf_too_big = true;
+               }
+       }
+       boost::filesystem::remove_all (dcp_dir);
+
        emit (bind(boost::ref(Finished)));
 }
 
@@ -371,8 +439,10 @@ Hints::hint (string h)
 }
 
 void
-Hints::text (PlayerText text, TextType type, DCPTimePeriod period)
+Hints::text (PlayerText text, TextType type, optional<DCPTextTrack> track, DCPTimePeriod period)
 {
+       _writer->write (text, type, track, period);
+
        switch (type) {
        case TEXT_CLOSED_CAPTION:
                closed_caption (text, period);
@@ -390,7 +460,7 @@ void
 Hints::closed_caption (PlayerText text, DCPTimePeriod period)
 {
        int lines = text.string.size();
-       BOOST_FOREACH (StringText i, text.string) {
+       for (auto i: text.string) {
                if (utf8_strlen(i.text()) > MAX_CLOSED_CAPTION_LENGTH) {
                        ++lines;
                        if (!_long_ccap) {
@@ -447,7 +517,7 @@ Hints::open_subtitle (PlayerText text, DCPTimePeriod period)
        }
 
        size_t longest_line = 0;
-       BOOST_FOREACH (StringText const& i, text.string) {
+       for (auto const& i: text.string) {
                longest_line = max (longest_line, i.text().length());
        }
 
@@ -464,7 +534,7 @@ void
 Hints::check_ffec_and_ffmc_in_smpte_feature ()
 {
        shared_ptr<const Film> f = film();
-       if (!f->interop() && f->dcp_content_type()->libdcp_kind() == dcp::FEATURE && (!f->marker(dcp::FFEC) || !f->marker(dcp::FFMC))) {
+       if (!f->interop() && f->dcp_content_type()->libdcp_kind() == dcp::ContentKind::FEATURE && (!f->marker(dcp::Marker::FFEC) || !f->marker(dcp::Marker::FFMC))) {
                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."));
        }
 }