, _reference_scaler (Scaler::from_id (N_("bicubic")))
, _tms_path (N_("."))
, _sound_processor (SoundProcessor::from_id (N_("dolby_cp750")))
+ , _default_still_length (10)
+ , _default_format (0)
+ , _default_dcp_content_type (0)
{
_allowed_dcp_frame_rates.push_back (24);
_allowed_dcp_frame_rates.push_back (25);
_allowed_dcp_frame_rates.push_back (48);
_allowed_dcp_frame_rates.push_back (50);
_allowed_dcp_frame_rates.push_back (60);
+
+ if (!boost::filesystem::exists (file (false))) {
+ read_old_metadata ();
+ return;
+ }
+
+ cxml::File f (file (false), "Config");
+ optional<string> c;
+
+ _num_local_encoding_threads = f.number_child<int> ("NumLocalEncodingThreads");
+ _default_directory = f.string_child ("DefaultDirectory");
+ _server_port = f.number_child<int> ("ServerPort");
+ c = f.optional_string_child ("ReferenceScaler");
+ if (c) {
+ _reference_scaler = Scaler::from_id (c.get ());
+ }
+
+ list<shared_ptr<cxml::Node> > filters = f.node_children ("ReferenceFilter");
+ for (list<shared_ptr<cxml::Node> >::iterator i = filters.begin(); i != filters.end(); ++i) {
+ _reference_filters.push_back (Filter::from_id ((*i)->content ()));
+ }
- ifstream f (file().c_str ());
+ list<shared_ptr<cxml::Node> > servers = f.node_children ("Server");
+ for (list<shared_ptr<cxml::Node> >::iterator i = servers.begin(); i != servers.end(); ++i) {
+ _servers.push_back (new ServerDescription (*i));
+ }
+
+ _tms_ip = f.string_child ("TMSIP");
+ _tms_path = f.string_child ("TMSPath");
+ _tms_user = f.string_child ("TMSUser");
+ _tms_password = f.string_child ("TMSPassword");
+
+ c = f.optional_string_child ("SoundProcessor");
+ if (c) {
+ _sound_processor = SoundProcessor::from_id (c.get ());
+ }
+
+ _language = f.optional_string_child ("Language");
++
++ c = f.optional_string_child ("DefaultFormat");
++ if (c) {
++ _default_format = Format::from_id (c.get ());
++ }
++
++ c = f.optional_string_child ("DefaultDCPContentType");
++ if (c) {
++ _default_dcp_content_type = DCPContentType::from_dci_name (c.get ());
++ }
++
++ _dcp_metadata.issuer = f.optional_string_child ("DCPMetadataIssuer").get_value_or ("");
++ _dcp_metadata.creator = f.optional_string_child ("DCPMetadataCreator").get_value_or ("");
++
+ _default_dci_metadata = DCIMetadata (f.node_child ("DCIMetadata"));
+ _default_still_length = f.optional_number_child<int>("DefaultStillLength").get_value_or (10);
+}
+
+void
+Config::read_old_metadata ()
+{
+ ifstream f (file(true).c_str ());
string line;
while (getline (f, line)) {
if (line.empty ()) {
_sound_processor = SoundProcessor::from_id (v);
} else if (k == "language") {
_language = v;
- _default_format = Format::from_metadata (v);
+ } else if (k == "default_format") {
++ _default_format = Format::from_id (v);
+ } else if (k == "default_dcp_content_type") {
+ _default_dcp_content_type = DCPContentType::from_dci_name (v);
+ } else if (k == "dcp_metadata_issuer") {
+ _dcp_metadata.issuer = v;
+ } else if (k == "dcp_metadata_creator") {
+ _dcp_metadata.creator = v;
+ } else if (k == "dcp_metadata_issue_date") {
+ _dcp_metadata.issue_date = v;
}
- _default_dci_metadata.read (k, v);
+ _default_dci_metadata.read_old_metadata (k, v);
}
}
}
for (vector<ServerDescription*>::const_iterator i = _servers.begin(); i != _servers.end(); ++i) {
- f << "server " << (*i)->as_metadata () << "\n";
+ (*i)->as_xml (root->add_child ("Server"));
}
- f << "tms_ip " << _tms_ip << "\n";
- f << "tms_path " << _tms_path << "\n";
- f << "tms_user " << _tms_user << "\n";
- f << "tms_password " << _tms_password << "\n";
+ root->add_child("TMSIP")->add_child_text (_tms_ip);
+ root->add_child("TMSPath")->add_child_text (_tms_path);
+ root->add_child("TMSUser")->add_child_text (_tms_user);
+ root->add_child("TMSPassword")->add_child_text (_tms_password);
if (_sound_processor) {
- f << "sound_processor " << _sound_processor->id () << "\n";
+ root->add_child("SoundProcessor")->add_child_text (_sound_processor->id ());
}
if (_language) {
- f << "language " << _language.get() << "\n";
+ root->add_child("Language")->add_child_text (_language.get());
}
- f << "default_format " << _default_format->as_metadata() << "\n";
+ if (_default_format) {
- f << "default_dcp_content_type " << _default_dcp_content_type->dci_name() << "\n";
++ root->add_child("DefaultFormat")->add_child_text (_default_format->id ());
+ }
+ if (_default_dcp_content_type) {
- f << "dcp_metadata_issuer " << _dcp_metadata.issuer << "\n";
- f << "dcp_metadata_creator " << _dcp_metadata.creator << "\n";
- f << "dcp_metadata_issue_date " << _dcp_metadata.issue_date << "\n";
++ root->add_child("DefaultDCPContentType")->add_child_text (_default_dcp_content_type->dci_name ());
+ }
++ root->add_child("DCPMetadataIssuer")->add_child_text (_dcp_metadata.issuer);
++ root->add_child("DCPMetadataCreator")->add_child_text (_dcp_metadata.creator);
+
+ _default_dci_metadata.as_xml (root->add_child ("DCIMetadata"));
+
+ root->add_child("DefaultStillLength")->add_child_text (lexical_cast<string> (_default_still_length));
- _default_dci_metadata.write (f);
+ doc.write_to_file_formatted (file (false));
}
string
return _language;
}
+ int default_still_length () const {
+ return _default_still_length;
+ }
+
+ Format const * default_format () const {
+ return _default_format;
+ }
+
+ DCPContentType const * default_dcp_content_type () const {
+ return _default_dcp_content_type;
+ }
+
+ libdcp::XMLMetadata dcp_metadata () const {
+ return _dcp_metadata;
+ }
+
/** @param n New number of local encoding threads */
void set_num_local_encoding_threads (int n) {
_num_local_encoding_threads = n;
_language = boost::none;
}
+ void set_default_still_length (int s) {
+ _default_still_length = s;
+ }
+
+ void set_default_format (Format const * f) {
+ _default_format = f;
+ }
+
+ void set_default_dcp_content_type (DCPContentType const * t) {
+ _default_dcp_content_type = t;
+ }
+
+ void set_dcp_metadata (libdcp::XMLMetadata m) {
+ _dcp_metadata = m;
+ }
+
void write () const;
static Config* instance ();
/** Default DCI metadata for newly-created Films */
DCIMetadata _default_dci_metadata;
boost::optional<std::string> _language;
+ int _default_still_length;
+ Format const * _default_format;
+ DCPContentType const * _default_dcp_content_type;
+ libdcp::XMLMetadata _dcp_metadata;
/** Singleton instance, or 0 */
static Config* _instance;
*/
Film::Film (string d, bool must_exist)
- : _use_dci_name (true)
- , _trust_content_header (true)
+ : _playlist (new Playlist)
+ , _use_dci_name (true)
+ , _trust_content_headers (true)
- , _dcp_content_type (0)
- , _format (Format::from_id ("185"))
+ , _dcp_content_type (Config::instance()->default_dcp_content_type ())
+ , _format (Config::instance()->default_format ())
, _scaler (Scaler::from_id ("bicubic"))
, _trim_start (0)
, _trim_end (0)
return s.str ();
}
--/** @return Identifier for this format as metadata for a Film's metadata file */
--string
--Format::as_metadata () const
--{
-- return _id;
--}
--
/** Fill our _formats vector with all available formats */
void
Format::setup_formats ()
return *j;
}
--
--/** @param m Metadata, as returned from as_metadata().
-- * @return Matching Format, or 0.
-- */
--Format const *
--Format::from_metadata (string m)
--{
-- return from_id (m);
--}
--
/** @return All available formats */
vector<Format const *>
Format::all ()
return _dci_name;
}
-- std::string as_metadata () const;
--
static Format const * from_nickname (std::string n);
-- static Format const * from_metadata (std::string m);
static Format const * from_id (std::string i);
static std::vector<Format const *> all ();
static void setup_formats ();
#include <libdcp/sound_asset.h>
#include <libdcp/picture_frame.h>
#include <libdcp/reel.h>
+#include <libdcp/dcp.h>
+ #include <libdcp/cpl.h>
#include "writer.h"
#include "compose.hpp"
#include "film.h"
#include "format.h"
#include "log.h"
#include "dcp_video_frame.h"
+#include "dcp_content_type.h"
+#include "player.h"
+#include "audio_mapping.h"
+ #include "config.h"
#include "i18n.h"
--- /dev/null
- #include <libdcp/test_mode.h>
+/*
+ Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include <iomanip>
+#include <getopt.h>
- << " -t, --test run in test mode (repeatable UUID generation, timestamps etc.)\n"
+#include <libdcp/version.h>
+#include "format.h"
+#include "film.h"
+#include "filter.h"
+#include "transcode_job.h"
+#include "job_manager.h"
+#include "ab_transcode_job.h"
+#include "util.h"
+#include "scaler.h"
+#include "version.h"
+#include "cross.h"
+#include "config.h"
+#include "log.h"
+
+using std::string;
+using std::cerr;
+using std::cout;
+using std::vector;
+using std::pair;
+using std::list;
+using boost::shared_ptr;
+
+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"
+ << " -d, --deps list DCP-o-matic dependency details and quit\n"
- bool test_mode = false;
+ << " -n, --no-progress do not print progress to stdout\n"
+ << " -r, --no-remote do not use any remote servers\n"
+ << "\n"
+ << "<FILM> is the film directory.\n";
+}
+
+int
+main (int argc, char* argv[])
+{
+ string film_dir;
- { "test", no_argument, 0, 't'},
+ bool progress = true;
+ bool no_remote = false;
+ int log_level = 0;
+
+ int option_index = 0;
+ while (1) {
+ static struct option long_options[] = {
+ { "version", no_argument, 0, 'v'},
+ { "help", no_argument, 0, 'h'},
+ { "deps", no_argument, 0, 'd'},
- int c = getopt_long (argc, argv, "vhdtnrl:", long_options, &option_index);
+ { "no-progress", no_argument, 0, 'n'},
+ { "no-remote", no_argument, 0, 'r'},
+ { "log-level", required_argument, 0, 'l' },
+ { 0, 0, 0, 0 }
+ };
+
- case 't':
- test_mode = true;
- break;
++ int c = getopt_long (argc, argv, "vhdnrl:", long_options, &option_index);
+
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'v':
+ cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n";
+ exit (EXIT_SUCCESS);
+ case 'h':
+ help (argv[0]);
+ exit (EXIT_SUCCESS);
+ case 'd':
+ cout << dependency_version_summary () << "\n";
+ exit (EXIT_SUCCESS);
- if (test_mode) {
- libdcp::enable_test_mode ();
- cout << dependency_version_summary() << "\n";
- }
-
+ case 'n':
+ progress = false;
+ break;
+ case 'r':
+ no_remote = true;
+ break;
+ case 'l':
+ log_level = atoi (optarg);
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ help (argv[0]);
+ exit (EXIT_FAILURE);
+ }
+
+ film_dir = argv[optind];
+
+ dcpomatic_setup ();
+
+ if (no_remote) {
+ Config::instance()->set_servers (vector<ServerDescription*> ());
+ }
+
+ cout << "DCP-o-matic " << dcpomatic_version << " git " << dcpomatic_git_commit;
+ char buf[256];
+ if (gethostname (buf, 256) == 0) {
+ cout << " on " << buf;
+ }
+ cout << "\n";
+
- cout << "Test mode: " << (test_mode ? "yes" : "no") << "\n";
+ shared_ptr<Film> film;
+ try {
+ film.reset (new Film (film_dir, true));
+ } catch (std::exception& e) {
+ cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
+ exit (EXIT_FAILURE);
+ }
+
+ film->log()->set_level ((Log::Level) log_level);
+
+ cout << "\nMaking ";
+ if (film->ab()) {
+ cout << "A/B ";
+ }
+ cout << "DCP for " << film->name() << "\n";
+// cout << "Content: " << film->content() << "\n";
+ pair<string, string> const f = Filter::ffmpeg_strings (film->filters ());
+ cout << "Filters: " << f.first << " " << f.second << "\n";
+
+ film->make_dcp ();
+
+ bool should_stop = false;
+ bool first = true;
+ bool error = false;
+ while (!should_stop) {
+
+ dcpomatic_sleep (5);
+
+ list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
+
+ if (!first && progress) {
+ cout << "\033[" << jobs.size() << "A";
+ cout.flush ();
+ }
+
+ first = false;
+
+ int unfinished = 0;
+ int finished_in_error = 0;
+
+ for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) {
+ if (progress) {
+ cout << (*i)->name() << ": ";
+
+ float const p = (*i)->overall_progress ();
+
+ if (p >= 0) {
+ cout << (*i)->status() << " \n";
+ } else {
+ cout << ": Running \n";
+ }
+ }
+
+ if (!(*i)->finished ()) {
+ ++unfinished;
+ }
+
+ if ((*i)->finished_in_error ()) {
+ ++finished_in_error;
+ error = true;
+ }
+
+ 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 (unfinished == 0 || finished_in_error != 0) {
+ should_stop = true;
+ }
+ }
+
+ return error ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
table->Add (s, 1, wxEXPAND);
table->AddSpacer (0);
}
++}
++
++void
++ConfigDialog::make_metadata_panel ()
++{
++ _metadata_panel = new wxPanel (_notebook);
++ wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
++ _metadata_panel->SetSizer (s);
++
++ wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
++ table->AddGrowableCol (1, 1);
++ s->Add (table, 1, wxALL | wxEXPAND, 8);
++
++ add_label_to_sizer (table, _metadata_panel, _("Issuer"));
++ _issuer = new wxTextCtrl (_metadata_panel, wxID_ANY);
++ table->Add (_issuer, 1, wxEXPAND);
++
++ add_label_to_sizer (table, _metadata_panel, _("Creator"));
++ _creator = new wxTextCtrl (_metadata_panel, wxID_ANY);
++ table->Add (_creator, 1, wxEXPAND);
Config* config = Config::instance ();
--
-- _reference_scaler->SetSelection (Scaler::as_index (config->reference_scaler ()));
-- _reference_scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (ConfigDialog::reference_scaler_changed), 0, this);
-- pair<string, string> p = Filter::ffmpeg_strings (config->reference_filters ());
-- _reference_filters->SetLabel (std_to_wx (p.first) + N_(" ") + std_to_wx (p.second));
-- _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this);
++ _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
++ _issuer->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::issuer_changed), 0, this);
++ _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
++ _creator->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (ConfigDialog::creator_changed), 0, this);
}
void
_language->Enable (_set_language->GetValue ());
}
+void
+ConfigDialog::default_still_length_changed (wxCommandEvent &)
+{
+ Config::instance()->set_default_still_length (_default_still_length->GetValue ());
+}
++
+ void
+ ConfigDialog::default_format_changed (wxCommandEvent &)
+ {
+ vector<Format const *> fmt = Format::all ();
+ Config::instance()->set_default_format (fmt[_default_format->GetSelection()]);
+ }
+
+ void
+ ConfigDialog::default_dcp_content_type_changed (wxCommandEvent &)
+ {
+ vector<DCPContentType const *> ct = DCPContentType::all ();
+ Config::instance()->set_default_dcp_content_type (ct[_default_dcp_content_type->GetSelection()]);
+ }
+
+ void
+ ConfigDialog::issuer_changed (wxCommandEvent &)
+ {
+ libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
+ m.issuer = wx_to_std (_issuer->GetValue ());
+ Config::instance()->set_dcp_metadata (m);
+ }
+
+ void
+ ConfigDialog::creator_changed (wxCommandEvent &)
+ {
+ libdcp::XMLMetadata m = Config::instance()->dcp_metadata ();
+ m.creator = wx_to_std (_creator->GetValue ());
+ Config::instance()->set_dcp_metadata (m);
+ }