/*
- Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2022 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
+#include "lib/audio_content.h"
+#include "lib/config.h"
+#include "lib/cross.h"
+#include "lib/dcpomatic_log.h"
+#include "lib/encode_server_finder.h"
+#include "lib/ffmpeg_encoder.h"
#include "lib/film.h"
#include "lib/filter.h"
-#include "lib/transcode_job.h"
#include "lib/job_manager.h"
-#include "lib/util.h"
-#include "lib/version.h"
-#include "lib/cross.h"
-#include "lib/config.h"
-#include "lib/log.h"
-#include "lib/signal_manager.h"
-#include "lib/encode_server_finder.h"
#include "lib/json_server.h"
+#include "lib/log.h"
+#include "lib/make_dcp.h"
#include "lib/ratio.h"
+#include "lib/signal_manager.h"
+#include "lib/transcode_job.h"
+#include "lib/util.h"
+#include "lib/version.h"
#include "lib/video_content.h"
-#include "lib/audio_content.h"
-#include "lib/dcpomatic_log.h"
#include <dcp/version.h>
#include <getopt.h>
#include <iostream>
#include <iomanip>
-using std::string;
+
using std::cerr;
using std::cout;
-using std::vector;
+using std::dynamic_pointer_cast;
+using std::list;
using std::pair;
+using std::runtime_error;
using std::setw;
-using std::list;
using std::shared_ptr;
+using std::string;
+using std::vector;
using boost::optional;
-using std::dynamic_pointer_cast;
+
static void
help (string n)
{
cerr << "Syntax: " << n << " [OPTION] [<FILM>]\n"
- << " -v, --version show DCP-o-matic version\n"
- << " -h, --help show this help\n"
- << " -f, --flags show flags passed to C++ compiler on build\n"
- << " -n, --no-progress do not print progress to stdout\n"
- << " -r, --no-remote do not use any remote servers\n"
- << " -t, --threads specify number of local encoding threads (overriding configuration)\n"
- << " -j, --json <port> run a JSON server on the specified port\n"
- << " -k, --keep-going keep running even when the job is complete\n"
- << " -s, --servers <file> specify servers to use in a text file\n"
- << " -l, --list-servers just display a list of encoding servers that DCP-o-matic is configured to use; don't encode\n"
- << " -d, --dcp-path echo DCP's path to stdout on successful completion (implies -n)\n"
- << " -c, --config <dir> directory containing config.xml and cinemas.xml\n"
- << " --dump just dump a summary of the film's settings; don't encode\n"
- << " --no-check don't check project's content files for changes before making the DCP\n"
+ << " -v, --version show DCP-o-matic version\n"
+ << " -h, --help show this help\n"
+ << " -f, --flags show flags passed to C++ compiler on build\n"
+ << " -n, --no-progress do not print progress to stdout\n"
+ << " -r, --no-remote do not use any remote servers\n"
+ << " -t, --threads specify number of local encoding threads (overriding configuration)\n"
+ << " -j, --json <port> run a JSON server on the specified port\n"
+ << " -k, --keep-going keep running even when the job is complete\n"
+ << " -s, --servers <file> specify servers to use in a text file\n"
+ << " -l, --list-servers just display a list of encoding servers that DCP-o-matic is configured to use; don't encode\n"
+ << " -d, --dcp-path echo DCP's path to stdout on successful completion (implies -n)\n"
+ << " -c, --config <dir> directory containing config.xml and cinemas.xml\n"
+ << " --dump just dump a summary of the film's settings; don't encode\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"
<< "\n"
<< "<FILM> is the film directory.\n";
}
+
static void
print_dump (shared_ptr<Film> film)
{
if (c->video) {
cout << "\t" << c->video->size().width << "x" << c->video->size().height << "\n"
<< "\t" << c->active_video_frame_rate(film) << "fps\n"
- << "\tcrop left " << c->video->left_crop()
- << " right " << c->video->right_crop()
- << " top " << c->video->top_crop()
- << " bottom " << c->video->bottom_crop() << "\n";
+ << "\tcrop left " << c->video->requested_left_crop()
+ << " right " << c->video->requested_right_crop()
+ << " top " << c->video->requested_top_crop()
+ << " bottom " << c->video->requested_bottom_crop() << "\n";
if (c->video->custom_ratio()) {
cout << "\tscale to custom ratio " << *c->video->custom_ratio() << ":1\n";
}
}
}
+
static void
list_servers ()
{
while (true) {
int N = 0;
- list<EncodeServerDescription> servers = EncodeServerFinder::instance()->servers();
+ auto servers = EncodeServerFinder::instance()->servers();
/* This is a bit fiddly because we want to list configured servers that are down as well
as all those (configured and found by broadcast) that are up.
the number of threads it is offering.
*/
optional<int> threads;
- list<EncodeServerDescription>::iterator j = servers.begin ();
+ auto j = servers.begin ();
while (j != servers.end ()) {
if (i == j->host_name() && j->current_link_version()) {
threads = j->threads();
- list<EncodeServerDescription>::iterator tmp = j;
+ auto tmp = j;
++tmp;
servers.erase (j);
j = tmp;
bool dcp_path = false;
optional<boost::filesystem::path> config;
bool check = true;
+ optional<string> export_format;
+ optional<boost::filesystem::path> export_filename;
int option_index = 0;
while (true) {
/* Just using A, B, C ... from here on */
{ "dump", no_argument, 0, 'A' },
{ "no-check", no_argument, 0, 'B' },
+ { "export-format", required_argument, 0, 'C' },
+ { "export-filename", required_argument, 0, 'D' },
{ 0, 0, 0, 0 }
};
- int c = getopt_long (argc, argv, "vhfnrt:j:kAs:ldc:B", long_options, &option_index);
+ int c = getopt_long (argc, argv, "vhfnrt:j:kAs:ldc:BC:D:", long_options, &option_index);
if (c == -1) {
break;
case 'B':
check = false;
break;
+ case 'C':
+ export_format = optarg;
+ break;
+ case 'D':
+ export_filename = optarg;
+ break;
}
}
}
if (servers) {
- FILE* f = fopen_boost (*servers, "r");
+ dcp::File f(*servers, "r");
if (!f) {
cerr << "Could not open servers list file " << *servers << "\n";
exit (EXIT_FAILURE);
}
vector<string> servers;
- while (!feof (f)) {
+ while (!f.eof()) {
char buffer[128];
- if (fscanf (f, "%s.127", buffer) == 1) {
+ if (fscanf(f.get(), "%s.127", buffer) == 1) {
servers.push_back (buffer);
}
}
- fclose (f);
Config::instance()->set_servers (servers);
}
exit (EXIT_FAILURE);
}
+ if (export_format && !export_filename) {
+ cerr << "Argument --export-filename is required with --export-format\n";
+ exit (EXIT_FAILURE);
+ }
+
+ if (!export_format && export_filename) {
+ cerr << "Argument --export-format is required with --export-filename\n";
+ exit (EXIT_FAILURE);
+ }
+
+ if (export_format && *export_format != "mp4" && *export_format != "mov") {
+ cerr << "Unrecognised export format: must be mp4 or mov\n";
+ exit (EXIT_FAILURE);
+ }
+
film_dir = argv[optind];
dcpomatic_setup_path_encoding ();
dcpomatic_setup ();
signal_manager = new SignalManager ();
- if (no_remote) {
+ if (no_remote || export_format) {
EncodeServerFinder::instance()->stop ();
}
dcpomatic_log = film->log ();
- ContentList content = film->content ();
- for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
- vector<boost::filesystem::path> paths = (*i)->paths ();
- for (vector<boost::filesystem::path>::const_iterator j = paths.begin(); j != paths.end(); ++j) {
- if (!boost::filesystem::exists (*j)) {
- cerr << argv[0] << ": content file " << *j << " not found.\n";
+ for (auto i: film->content()) {
+ auto paths = i->paths();
+ for (auto j: paths) {
+ if (!boost::filesystem::exists(j)) {
+ cerr << argv[0] << ": content file " << j << " not found.\n";
exit (EXIT_FAILURE);
}
}
}
if (progress) {
- cout << "\nMaking DCP for " << film->name() << "\n";
+ if (export_format) {
+ cout << "\nExporting " << film->name() << "\n";
+ } else {
+ cout << "\nMaking DCP for " << film->name() << "\n";
+ }
+ }
+
+ TranscodeJob::ChangedBehaviour const behaviour = check ? TranscodeJob::ChangedBehaviour::STOP : TranscodeJob::ChangedBehaviour::IGNORE;
+
+ if (export_format) {
+ 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_HQ, false, false, false, 23
+ )
+ );
+ JobManager::instance()->add (job);
+ } else {
+ try {
+ make_dcp (film, behaviour);
+ } catch (runtime_error& e) {
+ std::cerr << "Could not make DCP: " << e.what() << "\n";
+ exit(EXIT_FAILURE);
+ }
}
- film->make_dcp (false, check);
bool const error = show_jobs_on_console (progress);
if (keep_going) {