summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2016-08-24 11:40:34 +0100
committerCarl Hetherington <cth@carlh.net>2016-08-24 14:28:32 +0100
commit1a693725f9a8cc6ba58f65b2f1ef03255d295f23 (patch)
tree91596f7800dcc02103c90f8f19c763f45281603e /src/lib
parenta03e9a98ed667eb44c9dfbbeaf6da57f44992914 (diff)
Basic template support (#485).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/atmos_mxf_content.cc4
-rw-r--r--src/lib/atmos_mxf_content.h2
-rw-r--r--src/lib/audio_content.cc16
-rw-r--r--src/lib/audio_content.h1
-rw-r--r--src/lib/config.cc29
-rw-r--r--src/lib/config.h6
-rw-r--r--src/lib/content.cc29
-rw-r--r--src/lib/content.h4
-rw-r--r--src/lib/dcp_content.cc16
-rw-r--r--src/lib/dcp_content.h3
-rw-r--r--src/lib/dcp_subtitle_content.cc4
-rw-r--r--src/lib/dcp_subtitle_content.h2
-rw-r--r--src/lib/ffmpeg_content.cc13
-rw-r--r--src/lib/ffmpeg_content.h3
-rw-r--r--src/lib/film.cc116
-rw-r--r--src/lib/film.h14
-rw-r--r--src/lib/image_content.cc4
-rw-r--r--src/lib/image_content.h2
-rw-r--r--src/lib/playlist.cc4
-rw-r--r--src/lib/playlist.h2
-rw-r--r--src/lib/reel_writer.cc4
-rw-r--r--src/lib/subtitle_content.cc19
-rw-r--r--src/lib/subtitle_content.h1
-rw-r--r--src/lib/text_subtitle_content.cc4
-rw-r--r--src/lib/text_subtitle_content.h2
-rw-r--r--src/lib/video_content.cc11
-rw-r--r--src/lib/video_content.h1
-rw-r--r--src/lib/video_mxf_content.cc4
-rw-r--r--src/lib/video_mxf_content.h2
29 files changed, 258 insertions, 64 deletions
diff --git a/src/lib/atmos_mxf_content.cc b/src/lib/atmos_mxf_content.cc
index f8cc05178..2fd9ead06 100644
--- a/src/lib/atmos_mxf_content.cc
+++ b/src/lib/atmos_mxf_content.cc
@@ -79,10 +79,10 @@ AtmosMXFContent::summary () const
}
void
-AtmosMXFContent::as_xml (xmlpp::Node* node) const
+AtmosMXFContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("AtmosMXF");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
}
DCPTime
diff --git a/src/lib/atmos_mxf_content.h b/src/lib/atmos_mxf_content.h
index 10c969a7d..0f5225c2e 100644
--- a/src/lib/atmos_mxf_content.h
+++ b/src/lib/atmos_mxf_content.h
@@ -32,7 +32,7 @@ public:
void examine (boost::shared_ptr<Job> job);
std::string summary () const;
- void as_xml (xmlpp::Node* node) const;
+ void as_xml (xmlpp::Node* node, bool with_path) const;
DCPTime full_length () const;
static bool valid_mxf (boost::filesystem::path path);
diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc
index e66b8b998..5d89719f7 100644
--- a/src/lib/audio_content.cc
+++ b/src/lib/audio_content.cc
@@ -379,3 +379,19 @@ AudioContent::set_stream (AudioStreamPtr stream)
_parent->signal_changed (AudioContentProperty::STREAMS);
}
+
+void
+AudioContent::use_template (shared_ptr<const AudioContent> c)
+{
+ _gain = c->_gain;
+ _delay = c->_delay;
+
+ size_t i = 0;
+ size_t j = 0;
+
+ while (i < _streams.size() && j < c->_streams.size()) {
+ _streams[i]->set_mapping (c->_streams[j]->mapping());
+ ++i;
+ ++j;
+ }
+}
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h
index 92491bf89..1a2c2911d 100644
--- a/src/lib/audio_content.h
+++ b/src/lib/audio_content.h
@@ -48,6 +48,7 @@ public:
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
+ void use_template (boost::shared_ptr<const AudioContent> c);
AudioMapping mapping () const;
void set_mapping (AudioMapping);
diff --git a/src/lib/config.cc b/src/lib/config.cc
index 4184a7d1d..8f9cfab4b 100644
--- a/src/lib/config.cc
+++ b/src/lib/config.cc
@@ -29,6 +29,7 @@
#include "cinema.h"
#include "util.h"
#include "cross.h"
+#include "film.h"
#include <dcp/raw_convert.h>
#include <dcp/name_format.h>
#include <dcp/colour_matrix.h>
@@ -588,3 +589,31 @@ Config::set_cinemas_file (boost::filesystem::path file)
changed (OTHER);
}
+
+void
+Config::save_template (shared_ptr<const Film> film, string name) const
+{
+ film->write_template (template_path (name));
+}
+
+list<string>
+Config::template_names () const
+{
+ list<string> n;
+ for (boost::filesystem::directory_iterator i (path("templates")); i != boost::filesystem::directory_iterator(); ++i) {
+ n.push_back (i->path().filename().string());
+ }
+ return n;
+}
+
+bool
+Config::existing_template (string name) const
+{
+ return boost::filesystem::exists (template_path (name));
+}
+
+boost::filesystem::path
+Config::template_path (string name) const
+{
+ return path("templates") / tidy_for_filename (name);
+}
diff --git a/src/lib/config.h b/src/lib/config.h
index a988cda6b..213c13a83 100644
--- a/src/lib/config.h
+++ b/src/lib/config.h
@@ -39,6 +39,7 @@ class CinemaSoundProcessor;
class DCPContentType;
class Ratio;
class Cinema;
+class Film;
/** @class Config
* @brief A singleton class holding configuration.
@@ -514,6 +515,11 @@ public:
void write () const;
+ void save_template (boost::shared_ptr<const Film> film, std::string name) const;
+ bool existing_template (std::string name) const;
+ std::list<std::string> template_names () const;
+ boost::filesystem::path template_path (std::string name) const;
+
static Config* instance ();
static void drop ();
static void restore_defaults ();
diff --git a/src/lib/content.cc b/src/lib/content.cc
index 9083635f2..b5bae69b6 100644
--- a/src/lib/content.cc
+++ b/src/lib/content.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -25,6 +25,9 @@
#include "content.h"
#include "util.h"
#include "content_factory.h"
+#include "video_content.h"
+#include "audio_content.h"
+#include "subtitle_content.h"
#include "exceptions.h"
#include "film.h"
#include "job.h"
@@ -135,12 +138,14 @@ Content::Content (shared_ptr<const Film> film, vector<shared_ptr<Content> > c)
}
void
-Content::as_xml (xmlpp::Node* node) const
+Content::as_xml (xmlpp::Node* node, bool with_paths) const
{
boost::mutex::scoped_lock lm (_mutex);
- for (vector<boost::filesystem::path>::const_iterator i = _paths.begin(); i != _paths.end(); ++i) {
- node->add_child("Path")->add_child_text (i->string ());
+ if (with_paths) {
+ for (vector<boost::filesystem::path>::const_iterator i = _paths.begin(); i != _paths.end(); ++i) {
+ node->add_child("Path")->add_child_text (i->string ());
+ }
}
node->add_child("Digest")->add_child_text (_digest);
node->add_child("Position")->add_child_text (raw_convert<string> (_position.get ()));
@@ -231,7 +236,7 @@ Content::clone () const
/* This is a bit naughty, but I can't think of a compelling reason not to do it ... */
xmlpp::Document doc;
xmlpp::Node* node = doc.create_root_node ("Content");
- as_xml (node);
+ as_xml (node, true);
/* notes is unused here (we assume) */
list<string> notes;
@@ -383,3 +388,17 @@ Content::add_properties (list<UserProperty>& p) const
}
}
}
+
+void
+Content::use_template (shared_ptr<const Content> c)
+{
+ if (video && c->video) {
+ video->use_template (c->video);
+ }
+ if (audio && c->audio) {
+ audio->use_template (c->audio);
+ }
+ if (subtitle && c->subtitle) {
+ subtitle->use_template (c->subtitle);
+ }
+}
diff --git a/src/lib/content.h b/src/lib/content.h
index f8b5493c0..519ff8907 100644
--- a/src/lib/content.h
+++ b/src/lib/content.h
@@ -76,6 +76,8 @@ public:
*/
virtual void examine (boost::shared_ptr<Job> job);
+ virtual void use_template (boost::shared_ptr<const Content> c);
+
/** @return Quick one-line summary of the content, as will be presented in the
* film editor.
*/
@@ -86,7 +88,7 @@ public:
*/
virtual std::string technical_summary () const;
- virtual void as_xml (xmlpp::Node *) const;
+ virtual void as_xml (xmlpp::Node *, bool with_paths) const;
virtual DCPTime full_length () const = 0;
virtual std::string identifier () const;
/** @return points at which to split this content when
diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc
index 03e6f1aaa..a5c0e5da2 100644
--- a/src/lib/dcp_content.cc
+++ b/src/lib/dcp_content.cc
@@ -51,6 +51,7 @@ using boost::shared_ptr;
using boost::scoped_ptr;
using boost::optional;
using boost::function;
+using boost::dynamic_pointer_cast;
using dcp::raw_convert;
int const DCPContentProperty::CAN_BE_PLAYED = 600;
@@ -192,11 +193,11 @@ DCPContent::technical_summary () const
}
void
-DCPContent::as_xml (xmlpp::Node* node) const
+DCPContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("DCP");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
@@ -448,3 +449,14 @@ DCPContent::can_reference_subtitle (list<string>& why_not) const
return can_reference (bind (&Content::subtitle, _1), _("There is other subtitle content overlapping this DCP; remove it."), why_not);
}
+
+void
+DCPContent::use_template (shared_ptr<const Content> c)
+{
+ shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (c);
+ DCPOMATIC_ASSERT (dc);
+
+ _reference_video = dc->_reference_video;
+ _reference_audio = dc->_reference_audio;
+ _reference_subtitle = dc->_reference_subtitle;
+}
diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h
index f3a8236a2..11096037c 100644
--- a/src/lib/dcp_content.h
+++ b/src/lib/dcp_content.h
@@ -62,8 +62,9 @@ public:
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const Content> c);
void set_default_colour_conversion ();
std::list<DCPTime> reel_split_points () const;
diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc
index 015aebd72..8fee0b2ed 100644
--- a/src/lib/dcp_subtitle_content.cc
+++ b/src/lib/dcp_subtitle_content.cc
@@ -101,10 +101,10 @@ DCPSubtitleContent::technical_summary () const
}
void
-DCPSubtitleContent::as_xml (xmlpp::Node* node) const
+DCPSubtitleContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("DCPSubtitle");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (subtitle) {
subtitle->as_xml (node);
diff --git a/src/lib/dcp_subtitle_content.h b/src/lib/dcp_subtitle_content.h
index c29944605..36945adcd 100644
--- a/src/lib/dcp_subtitle_content.h
+++ b/src/lib/dcp_subtitle_content.h
@@ -30,7 +30,7 @@ public:
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
private:
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index b5c5ce0a8..77c7c9ecd 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -181,10 +181,10 @@ FFmpegContent::FFmpegContent (shared_ptr<const Film> film, vector<shared_ptr<Con
}
void
-FFmpegContent::as_xml (xmlpp::Node* node) const
+FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("FFmpeg");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
@@ -599,3 +599,12 @@ FFmpegContent::ffmpeg_audio_streams () const
return fa;
}
+
+void
+FFmpegContent::use_template (shared_ptr<const Content> c)
+{
+ Content::use_template (c);
+
+ shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (c);
+ _filters = fc->_filters;
+}
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index 666322669..91caac27c 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -55,9 +55,10 @@ public:
}
void examine (boost::shared_ptr<Job>);
+ void use_template (boost::shared_ptr<const Content> c);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
std::string identifier () const;
diff --git a/src/lib/film.cc b/src/lib/film.cc
index edb911217..e9788d09e 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -124,7 +124,7 @@ int const Film::current_state_version = 36;
* @param dir Film directory.
*/
-Film::Film (boost::filesystem::path dir, bool log)
+Film::Film (optional<boost::filesystem::path> dir)
: _playlist (new Playlist)
, _use_isdcf_name (true)
, _dcp_content_type (Config::instance()->default_dcp_content_type ())
@@ -152,27 +152,30 @@ Film::Film (boost::filesystem::path dir, bool log)
_playlist_order_changed_connection = _playlist->OrderChanged.connect (bind (&Film::playlist_order_changed, this));
_playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2, _3));
- /* Make state.directory a complete path without ..s (where possible)
- (Code swiped from Adam Bowen on stackoverflow)
- XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
- */
+ if (dir) {
+ /* Make state.directory a complete path without ..s (where possible)
+ (Code swiped from Adam Bowen on stackoverflow)
+ XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
+ */
- boost::filesystem::path p (boost::filesystem::system_complete (dir));
- boost::filesystem::path result;
- for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
- if (*i == "..") {
- if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
+ boost::filesystem::path p (boost::filesystem::system_complete (dir.get()));
+ boost::filesystem::path result;
+ for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
+ if (*i == "..") {
+ if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
+ result /= *i;
+ } else {
+ result = result.parent_path ();
+ }
+ } else if (*i != ".") {
result /= *i;
- } else {
- result = result.parent_path ();
}
- } else if (*i != ".") {
- result /= *i;
}
+
+ set_directory (result.make_preferred ());
}
- set_directory (result.make_preferred ());
- if (log) {
+ if (_directory) {
_log.reset (new FileLog (file ("log")));
} else {
_log.reset (new NullLog);
@@ -329,7 +332,7 @@ Film::send_dcp_to_tms ()
}
shared_ptr<xmlpp::Document>
-Film::metadata () const
+Film::metadata (bool with_content_paths) const
{
shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
xmlpp::Element* root = doc->create_root_node ("Metadata");
@@ -364,7 +367,7 @@ Film::metadata () const
root->add_child("ReelType")->add_child_text (raw_convert<string> (static_cast<int> (_reel_type)));
root->add_child("ReelLength")->add_child_text (raw_convert<string> (_reel_length));
root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
- _playlist->as_xml (root->add_child ("Playlist"));
+ _playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
return doc;
}
@@ -373,24 +376,38 @@ Film::metadata () const
void
Film::write_metadata () const
{
- boost::filesystem::create_directories (directory ());
+ DCPOMATIC_ASSERT (directory());
+ boost::filesystem::create_directories (directory().get());
shared_ptr<xmlpp::Document> doc = metadata ();
doc->write_to_file_formatted (file("metadata.xml").string ());
_dirty = false;
}
+/** Write a template from this film */
+void
+Film::write_template (boost::filesystem::path path) const
+{
+ boost::filesystem::create_directories (path.parent_path());
+ shared_ptr<xmlpp::Document> doc = metadata (false);
+ doc->write_to_file_formatted (path.string ());
+}
+
/** Read state from our metadata file.
* @return Notes about things that the user should know about, or empty.
*/
list<string>
-Film::read_metadata ()
+Film::read_metadata (optional<boost::filesystem::path> path)
{
- if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
- throw runtime_error (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!"));
+ if (!path) {
+ if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
+ throw runtime_error (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!"));
+ }
+
+ path = file ("metadata.xml");
}
cxml::Document f ("Metadata");
- f.read_file (file ("metadata.xml"));
+ f.read_file (path.get ());
_state_version = f.number_child<int> ("Version");
if (_state_version > current_state_version) {
@@ -462,7 +479,9 @@ Film::read_metadata ()
_playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
/* Write backtraces to this film's directory, until another film is loaded */
- set_backtrace_file (file ("backtrace.txt"));
+ if (_directory) {
+ set_backtrace_file (file ("backtrace.txt"));
+ }
_dirty = false;
return notes;
@@ -474,8 +493,10 @@ Film::read_metadata ()
boost::filesystem::path
Film::dir (boost::filesystem::path d) const
{
+ DCPOMATIC_ASSERT (_directory);
+
boost::filesystem::path p;
- p /= _directory;
+ p /= _directory.get();
p /= d;
boost::filesystem::create_directories (p);
@@ -489,8 +510,10 @@ Film::dir (boost::filesystem::path d) const
boost::filesystem::path
Film::file (boost::filesystem::path f) const
{
+ DCPOMATIC_ASSERT (_directory);
+
boost::filesystem::path p;
- p /= _directory;
+ p /= _directory.get();
p /= f;
boost::filesystem::create_directories (p.parent_path ());
@@ -943,9 +966,13 @@ Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const
vector<CPLSummary>
Film::cpls () const
{
+ if (!directory ()) {
+ return vector<CPLSummary> ();
+ }
+
vector<CPLSummary> out;
- boost::filesystem::path const dir = directory ();
+ boost::filesystem::path const dir = directory().get();
for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
if (
boost::filesystem::is_directory (*i) &&
@@ -1010,7 +1037,7 @@ Film::examine_content (shared_ptr<Content> c)
void
Film::examine_and_add_content (shared_ptr<Content> c)
{
- if (dynamic_pointer_cast<FFmpegContent> (c) && !_directory.empty ()) {
+ if (dynamic_pointer_cast<FFmpegContent> (c) && _directory) {
run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
}
@@ -1037,6 +1064,7 @@ Film::maybe_add_content (weak_ptr<Job> j, weak_ptr<Content> c)
}
add_content (content);
+
if (Config::instance()->automatic_audio_analysis() && content->audio) {
shared_ptr<Playlist> playlist (new Playlist);
playlist->add (content);
@@ -1058,6 +1086,15 @@ Film::add_content (shared_ptr<Content> c)
c->set_position (_playlist->subtitle_end ());
}
+ if (_template_film) {
+ /* Take settings from the first piece of content of c's type in _template */
+ BOOST_FOREACH (shared_ptr<Content> i, _template_film->content()) {
+ if (typeid(i.get()) == typeid(c.get())) {
+ c->use_template (i);
+ }
+ }
+ }
+
_playlist->add (c);
}
@@ -1487,3 +1524,26 @@ Film::fix_conflicting_settings ()
return notes;
}
+
+void
+Film::use_template (string name)
+{
+ _template_film.reset (new Film (optional<boost::filesystem::path>()));
+ _template_film->read_metadata (Config::instance()->template_path (name));
+ _use_isdcf_name = _template_film->_use_isdcf_name;
+ _dcp_content_type = _template_film->_dcp_content_type;
+ _container = _template_film->_container;
+ _resolution = _template_film->_resolution;
+ _j2k_bandwidth = _template_film->_j2k_bandwidth;
+ _video_frame_rate = _template_film->_video_frame_rate;
+ _signed = _template_film->_signed;
+ _encrypted = _template_film->_encrypted;
+ _audio_channels = _template_film->_audio_channels;
+ _sequence = _template_film->_sequence;
+ _three_d = _template_film->_three_d;
+ _interop = _template_film->_interop;
+ _audio_processor = _template_film->_audio_processor;
+ _reel_type = _template_film->_reel_type;
+ _reel_length = _template_film->_reel_length;
+ _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
+}
diff --git a/src/lib/film.h b/src/lib/film.h
index 82d1f78c0..5fa35b065 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -68,7 +68,7 @@ struct isdcf_name_test;
class Film : public boost::enable_shared_from_this<Film>, public Signaller, public boost::noncopyable
{
public:
- Film (boost::filesystem::path, bool log = true);
+ Film (boost::optional<boost::filesystem::path> dir);
~Film ();
boost::filesystem::path info_file (DCPTimePeriod p) const;
@@ -91,9 +91,11 @@ public:
boost::filesystem::path file (boost::filesystem::path f) const;
boost::filesystem::path dir (boost::filesystem::path d) const;
- std::list<std::string> read_metadata ();
+ void use_template (std::string name);
+ std::list<std::string> read_metadata (boost::optional<boost::filesystem::path> path = boost::optional<boost::filesystem::path> ());
void write_metadata () const;
- boost::shared_ptr<xmlpp::Document> metadata () const;
+ void write_template (boost::filesystem::path path) const;
+ boost::shared_ptr<xmlpp::Document> metadata (bool with_content_paths = true) const;
std::string isdcf_name (bool if_created_now) const;
std::string dcp_name (bool if_created_now = false) const;
@@ -200,7 +202,7 @@ public:
/* GET */
- boost::filesystem::path directory () const {
+ boost::optional<boost::filesystem::path> directory () const {
return _directory;
}
@@ -341,7 +343,7 @@ private:
/** Complete path to directory containing the film metadata;
* must not be relative.
*/
- boost::filesystem::path _directory;
+ boost::optional<boost::filesystem::path> _directory;
/** Name for DCP-o-matic */
std::string _name;
@@ -382,6 +384,8 @@ private:
/** true if our state has changed since we last saved it */
mutable bool _dirty;
+ /** film being used as a template, or 0 */
+ boost::shared_ptr<Film> _template_film;
boost::signals2::scoped_connection _playlist_changed_connection;
boost::signals2::scoped_connection _playlist_order_changed_connection;
diff --git a/src/lib/image_content.cc b/src/lib/image_content.cc
index 825f6da25..b27483978 100644
--- a/src/lib/image_content.cc
+++ b/src/lib/image_content.cc
@@ -100,10 +100,10 @@ ImageContent::technical_summary () const
}
void
-ImageContent::as_xml (xmlpp::Node* node) const
+ImageContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("Image");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
diff --git a/src/lib/image_content.h b/src/lib/image_content.h
index edcbec6dd..660d2ef9f 100644
--- a/src/lib/image_content.h
+++ b/src/lib/image_content.h
@@ -36,7 +36,7 @@ public:
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
std::string identifier () const;
diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc
index a8b5a26eb..a30dde633 100644
--- a/src/lib/playlist.cc
+++ b/src/lib/playlist.cc
@@ -175,10 +175,10 @@ Playlist::set_from_xml (shared_ptr<const Film> film, cxml::ConstNodePtr node, in
/** @param node <Playlist> node */
void
-Playlist::as_xml (xmlpp::Node* node)
+Playlist::as_xml (xmlpp::Node* node, bool with_content_paths)
{
BOOST_FOREACH (shared_ptr<Content> i, _content) {
- i->as_xml (node->add_child ("Content"));
+ i->as_xml (node->add_child ("Content"), with_content_paths);
}
}
diff --git a/src/lib/playlist.h b/src/lib/playlist.h
index e84b51a73..0a5c087de 100644
--- a/src/lib/playlist.h
+++ b/src/lib/playlist.h
@@ -45,7 +45,7 @@ public:
Playlist ();
~Playlist ();
- void as_xml (xmlpp::Node *);
+ void as_xml (xmlpp::Node *, bool with_content_paths);
void set_from_xml (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int, std::list<std::string> &);
void add (boost::shared_ptr<Content>);
diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc
index 692134654..72e10e86b 100644
--- a/src/lib/reel_writer.cc
+++ b/src/lib/reel_writer.cc
@@ -112,11 +112,13 @@ ReelWriter::ReelWriter (
_sound_asset->set_key (_film->key ());
}
+ DCPOMATIC_ASSERT (_film->directory());
+
/* Write the sound asset into the film directory so that we leave the creation
of the DCP directory until the last minute.
*/
_sound_asset_writer = _sound_asset->start_write (
- _film->directory() / audio_asset_filename (_sound_asset, _reel_index, _reel_count, _content_summary),
+ _film->directory().get() / audio_asset_filename (_sound_asset, _reel_index, _reel_count, _content_summary),
_film->interop() ? dcp::INTEROP : dcp::SMPTE
);
}
diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc
index c57c72fb1..34ffa3f4b 100644
--- a/src/lib/subtitle_content.cc
+++ b/src/lib/subtitle_content.cc
@@ -395,3 +395,22 @@ SubtitleContent::set_fade_out (ContentTime t)
{
maybe_set (_fade_out, t, SubtitleContentProperty::FADE_OUT);
}
+
+void
+SubtitleContent::use_template (shared_ptr<const SubtitleContent> c)
+{
+ _use = c->_use;
+ _burn = c->_burn;
+ _x_offset = c->_x_offset;
+ _y_offset = c->_y_offset;
+ _x_scale = c->_x_scale;
+ _y_scale = c->_y_scale;
+ _fonts = c->_fonts;
+ _colour = c->_colour;
+ _outline = c->_outline;
+ _shadow = c->_shadow;
+ _effect_colour = c->_effect_colour;
+ _line_spacing = c->_line_spacing;
+ _fade_in = c->_fade_in;
+ _fade_out = c->_fade_out;
+}
diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h
index fd02d032a..ddc97ce9f 100644
--- a/src/lib/subtitle_content.h
+++ b/src/lib/subtitle_content.h
@@ -62,6 +62,7 @@ public:
void as_xml (xmlpp::Node *) const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const SubtitleContent> c);
void add_font (boost::shared_ptr<Font> font);
diff --git a/src/lib/text_subtitle_content.cc b/src/lib/text_subtitle_content.cc
index 63144766a..08722a065 100644
--- a/src/lib/text_subtitle_content.cc
+++ b/src/lib/text_subtitle_content.cc
@@ -75,10 +75,10 @@ TextSubtitleContent::technical_summary () const
}
void
-TextSubtitleContent::as_xml (xmlpp::Node* node) const
+TextSubtitleContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("TextSubtitle");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (subtitle) {
subtitle->as_xml (node);
diff --git a/src/lib/text_subtitle_content.h b/src/lib/text_subtitle_content.h
index 3b9d396f6..fd0bad12a 100644
--- a/src/lib/text_subtitle_content.h
+++ b/src/lib/text_subtitle_content.h
@@ -38,7 +38,7 @@ public:
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
private:
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index 2b953f75b..ed1402608 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -525,3 +525,14 @@ VideoContent::set_fade_out (Frame t)
{
maybe_set (_fade_out, t, VideoContentProperty::FADE_OUT);
}
+
+void
+VideoContent::use_template (shared_ptr<const VideoContent> c)
+{
+ _colour_conversion = c->_colour_conversion;
+ _frame_type = c->_frame_type;
+ _crop = c->_crop;
+ _scale = c->_scale;
+ _fade_in = c->_fade_in;
+ _fade_out = c->_fade_out;
+}
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index d5ba38022..623a1858b 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -57,6 +57,7 @@ public:
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const VideoContent> c);
Frame length () const {
boost::mutex::scoped_lock lm (_mutex);
diff --git a/src/lib/video_mxf_content.cc b/src/lib/video_mxf_content.cc
index d86fc4cf6..1f4163122 100644
--- a/src/lib/video_mxf_content.cc
+++ b/src/lib/video_mxf_content.cc
@@ -102,10 +102,10 @@ VideoMXFContent::identifier () const
}
void
-VideoMXFContent::as_xml (xmlpp::Node* node) const
+VideoMXFContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("VideoMXF");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
video->as_xml (node);
}
diff --git a/src/lib/video_mxf_content.h b/src/lib/video_mxf_content.h
index ab5375c6b..08946242c 100644
--- a/src/lib/video_mxf_content.h
+++ b/src/lib/video_mxf_content.h
@@ -34,7 +34,7 @@ public:
std::string summary () const;
std::string technical_summary () const;
std::string identifier () const;
- void as_xml (xmlpp::Node* node) const;
+ void as_xml (xmlpp::Node* node, bool with_paths) const;
DCPTime full_length () const;
void add_properties (std::list<UserProperty>& p) const;
void set_default_colour_conversion ();