Update documentation and CLI UI with hint info
[dcpomatic.git] / src / tools / dcpomatic_cli.cc
index 9c1d072d8438afb3f1d573048a457bafb1bab1da..40461b7949d338300a07dee27ac9a5b0f9b5f90a 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 
+#include "lib/ansi.h"
 #include "lib/audio_content.h"
 #include "lib/config.h"
 #include "lib/cross.h"
@@ -27,6 +28,7 @@
 #include "lib/ffmpeg_encoder.h"
 #include "lib/film.h"
 #include "lib/filter.h"
+#include "lib/hints.h"
 #include "lib/job_manager.h"
 #include "lib/json_server.h"
 #include "lib/log.h"
@@ -76,6 +78,7 @@ help (string n)
             << "      --no-check                    don't check project's content files for changes before making the DCP\n"
             << "      --export-format <format>      export project to a file, rather than making a DCP: specify mov or mp4\n"
             << "      --export-filename <filename>  filename to export to with --export-format\n"
+            << "      --hints                       analyze film for hints before encoding and abort if any are found\n"
             << "\n"
             << "<FILM> is the film directory.\n";
 }
@@ -196,6 +199,62 @@ list_servers ()
 }
 
 
+bool
+show_jobs_on_console (bool progress)
+{
+       bool first = true;
+       bool error = false;
+       while (true) {
+
+               dcpomatic_sleep_seconds (5);
+
+               auto jobs = JobManager::instance()->get();
+
+               if (!first && progress) {
+                       for (size_t i = 0; i < jobs.size(); ++i) {
+                               cout << UP_ONE_LINE_AND_ERASE;
+                       }
+                       cout.flush ();
+               }
+
+               first = false;
+
+               for (auto i: jobs) {
+                       if (progress) {
+                               cout << i->name();
+                               if (!i->sub_name().empty()) {
+                                       cout << "; " << i->sub_name();
+                               }
+                               cout << ": ";
+
+                               if (i->progress ()) {
+                                       cout << i->status() << "                            \n";
+                               } else {
+                                       cout << ": Running           \n";
+                               }
+                       }
+
+                       if (!progress && i->finished_in_error()) {
+                               /* We won't see this error if we haven't been showing progress,
+                                  so show it now.
+                               */
+                               cout << i->status() << "\n";
+                       }
+
+                       if (i->finished_in_error()) {
+                               error = true;
+                       }
+               }
+
+               if (!JobManager::instance()->work_to_do()) {
+                       break;
+               }
+       }
+
+       return error;
+}
+
+
 int
 main (int argc, char* argv[])
 {
@@ -213,6 +272,7 @@ main (int argc, char* argv[])
        bool check = true;
        optional<string> export_format;
        optional<boost::filesystem::path> export_filename;
+       bool hints = false;
 
        int option_index = 0;
        while (true) {
@@ -234,10 +294,11 @@ main (int argc, char* argv[])
                        { "no-check", no_argument, 0, 'B' },
                        { "export-format", required_argument, 0, 'C' },
                        { "export-filename", required_argument, 0, 'D' },
+                       { "hints", no_argument, 0, 'E' },
                        { 0, 0, 0, 0 }
                };
 
-               int c = getopt_long (argc, argv, "vhfnrt:j:kAs:ldc:BC:D:", long_options, &option_index);
+               int c = getopt_long (argc, argv, "vhfnrt:j:kAs:ldc:BC:D:E", long_options, &option_index);
 
                if (c == -1) {
                        break;
@@ -293,6 +354,9 @@ main (int argc, char* argv[])
                case 'D':
                        export_filename = optarg;
                        break;
+               case 'E':
+                       hints = true;
+                       break;
                }
        }
 
@@ -385,6 +449,52 @@ main (int argc, char* argv[])
                }
        }
 
+       if (!export_format && hints) {
+               string const prefix = "Checking project for hints";
+               bool pulse_phase = false;
+               vector<string> hints;
+               bool finished = false;
+
+               Hints hint_finder(film);
+               hint_finder.Progress.connect([prefix](string progress) {
+                                            std::cout << UP_ONE_LINE_AND_ERASE << prefix << ": " << progress << "\n";
+                                            std::cout.flush();
+                                            });
+               hint_finder.Pulse.connect([prefix, &pulse_phase]() {
+                                         std::cout << UP_ONE_LINE_AND_ERASE << prefix << ": " << (pulse_phase ? "X" : "x") << "\n";
+                                         std::cout.flush();
+                                         pulse_phase = !pulse_phase;
+                                         });
+               hint_finder.Hint.connect([&hints](string hint) {
+                                        hints.push_back(hint);
+                                        });
+               hint_finder.Finished.connect([&finished]() {
+                                            finished = true;
+                                            });
+
+               std::cout << prefix << ":\n";
+               std::cout.flush();
+
+               hint_finder.start();
+               while (!finished) {
+                       signal_manager->ui_idle();
+                       dcpomatic_sleep_milliseconds(200);
+               }
+
+               std::cout << UP_ONE_LINE_AND_ERASE;
+
+               if (!hints.empty()) {
+                       std::cout << "Hints:\n\n";
+                       for (auto hint: hints) {
+                               std::cout << word_wrap("* " + hint, 70) << "\n";
+                       }
+                       std::cout << "*** Encoding aborted because hints were found ***\n\n";
+                       std::cout << "Modify your settings and run the command again, or run without\n";
+                       std::cout << "the `--hints' option to ignore these hints and encode anyway.\n";
+                       exit(EXIT_FAILURE);
+               }
+       }
+
        if (progress) {
                if (export_format) {
                        cout << "\nExporting " << film->name() << "\n";
@@ -399,7 +509,7 @@ main (int argc, char* argv[])
                auto job = std::make_shared<TranscodeJob>(film, behaviour);
                job->set_encoder (
                        std::make_shared<FFmpegEncoder> (
-                               film, job, *export_filename, *export_format == "mp4" ? ExportFormat::H264_AAC : ExportFormat::PRORES, false, false, false, 23
+                               film, job, *export_filename, *export_format == "mp4" ? ExportFormat::H264_AAC : ExportFormat::PRORES_HQ, false, false, false, 23
                                )
                        );
                JobManager::instance()->add (job);