From: Carl Hetherington Date: Wed, 24 Aug 2016 10:40:34 +0000 (+0100) Subject: Basic template support (#485). X-Git-Tag: v2.9.16~14 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=1a693725f9a8cc6ba58f65b2f1ef03255d295f23 Basic template support (#485). --- 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); 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 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 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 #include #include @@ -588,3 +589,31 @@ Config::set_cinemas_file (boost::filesystem::path file) changed (OTHER); } + +void +Config::save_template (shared_ptr film, string name) const +{ + film->write_template (template_path (name)); +} + +list +Config::template_names () const +{ + list 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 film, std::string name) const; + bool existing_template (std::string name) const; + std::list 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 + Copyright (C) 2013-2016 Carl Hetherington 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 film, vector > 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::const_iterator i = _paths.begin(); i != _paths.end(); ++i) { - node->add_child("Path")->add_child_text (i->string ()); + if (with_paths) { + for (vector::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 (_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 notes; @@ -383,3 +388,17 @@ Content::add_properties (list& p) const } } } + +void +Content::use_template (shared_ptr 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); + virtual void use_template (boost::shared_ptr 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& 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 c) +{ + shared_ptr dc = dynamic_pointer_cast (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); 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 c); void set_default_colour_conversion (); std::list 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); 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 film, vectoradd_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 c) +{ + Content::use_template (c); + + shared_ptr fc = dynamic_pointer_cast (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); + void use_template (boost::shared_ptr 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 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 -Film::metadata () const +Film::metadata (bool with_content_paths) const { shared_ptr 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 (static_cast (_reel_type))); root->add_child("ReelLength")->add_child_text (raw_convert (_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 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 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 -Film::read_metadata () +Film::read_metadata (optional 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 ("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 Film::cpls () const { + if (!directory ()) { + return vector (); + } + vector 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 c) void Film::examine_and_add_content (shared_ptr c) { - if (dynamic_pointer_cast (c) && !_directory.empty ()) { + if (dynamic_pointer_cast (c) && _directory) { run_ffprobe (c->path(0), file ("ffprobe.log"), _log); } @@ -1037,6 +1064,7 @@ Film::maybe_add_content (weak_ptr j, weak_ptr c) } add_content (content); + if (Config::instance()->automatic_audio_analysis() && content->audio) { shared_ptr playlist (new Playlist); playlist->add (content); @@ -1058,6 +1086,15 @@ Film::add_content (shared_ptr 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 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())); + _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, public Signaller, public boost::noncopyable { public: - Film (boost::filesystem::path, bool log = true); + Film (boost::optional 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 read_metadata (); + void use_template (std::string name); + std::list read_metadata (boost::optional path = boost::optional ()); void write_metadata () const; - boost::shared_ptr metadata () const; + void write_template (boost::filesystem::path path) const; + boost::shared_ptr 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 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 _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 _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); 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 film, cxml::ConstNodePtr node, in /** @param node node */ void -Playlist::as_xml (xmlpp::Node* node) +Playlist::as_xml (xmlpp::Node* node, bool with_content_paths) { BOOST_FOREACH (shared_ptr 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, cxml::ConstNodePtr, int, std::list &); void add (boost::shared_ptr); 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 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 c); void add_font (boost::shared_ptr 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); 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 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 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& p) const; void set_default_colour_conversion (); diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index d4695f1fa..63e5ca6b1 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -38,6 +38,7 @@ #include "wx/content_panel.h" #include "wx/report_problem_dialog.h" #include "wx/video_waveform_dialog.h" +#include "wx/save_template_dialog.h" #include "lib/film.h" #include "lib/config.h" #include "lib/util.h" @@ -143,6 +144,7 @@ enum { ID_file_new = 1, ID_file_open, ID_file_save, + ID_file_save_as_template, ID_file_history, /* Allow spare IDs after _history for the recent files list */ ID_content_scale_to_fit_width = 100, @@ -210,6 +212,7 @@ public: Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_new, this), ID_file_new); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_open, this), ID_file_open); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_save, this), ID_file_save); + Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_save_as_template, this), ID_file_save_as_template); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_history, this, _1), ID_file_history, ID_file_history + HISTORY_SIZE); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES); @@ -278,9 +281,12 @@ public: } } - void new_film (boost::filesystem::path path) + void new_film (boost::filesystem::path path, optional template_name) { shared_ptr film (new Film (path)); + if (template_name) { + film->use_template (template_name.get()); + } film->write_metadata (); film->set_name (path.filename().generic_string()); set_film (film); @@ -320,7 +326,9 @@ public: delete _video_waveform_dialog; _video_waveform_dialog = 0; set_menu_sensitivity (); - Config::instance()->add_to_history (_film->directory ()); + if (_film->directory()) { + Config::instance()->add_to_history (_film->directory().get()); + } } shared_ptr film () const { @@ -346,27 +354,27 @@ private: if (r == wxID_OK) { - if (boost::filesystem::is_directory (d->get_path()) && !boost::filesystem::is_empty(d->get_path())) { + if (boost::filesystem::is_directory (d->path()) && !boost::filesystem::is_empty(d->path())) { if (!confirm_dialog ( this, std_to_wx ( String::compose (wx_to_std (_("The directory %1 already exists and is not empty. " "Are you sure you want to use it?")), - d->get_path().string().c_str()) + d->path().string().c_str()) ) )) { return; } - } else if (boost::filesystem::is_regular_file (d->get_path())) { + } else if (boost::filesystem::is_regular_file (d->path())) { error_dialog ( this, - String::compose (wx_to_std (_("%1 already exists as a file, so you cannot use it for a new film.")), d->get_path().c_str()) + String::compose (wx_to_std (_("%1 already exists as a file, so you cannot use it for a new film.")), d->path().c_str()) ); return; } if (maybe_save_then_delete_film ()) { - new_film (d->get_path ()); + new_film (d->path(), d->template_name()); } } @@ -404,6 +412,22 @@ private: _film->write_metadata (); } + void file_save_as_template () + { + SaveTemplateDialog* d = new SaveTemplateDialog (this); + int const r = d->ShowModal (); + if (r == wxID_OK) { + bool ok = true; + if (Config::instance()->existing_template (d->name ())) { + ok = confirm_dialog (d, _("There is already a template with this name. Do you want to overwrite it?")); + } + if (ok) { + Config::instance()->save_template (_film, d->name ()); + } + } + d->Destroy (); + } + void file_history (wxCommandEvent& event) { vector history = Config::instance()->history (); @@ -528,7 +552,8 @@ private: boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); Socket socket (5); socket.connect (*endpoint_iterator); - string s = _film->directory().string (); + DCPOMATIC_ASSERT (_film->directory ()); + string s = _film->directory()->string (); socket.write (s.length() + 1); socket.write ((uint8_t *) s.c_str(), s.length() + 1); /* OK\0 */ @@ -616,6 +641,7 @@ private: void jobs_show_dcp () { + DCPOMATIC_ASSERT (_film->directory ()); #ifdef DCPOMATIC_WINDOWS wstringstream args; args << "/select," << _film->dir (_film->dcp_name(false)); @@ -625,14 +651,14 @@ private: #ifdef DCPOMATIC_LINUX int r = system ("which nautilus"); if (WEXITSTATUS (r) == 0) { - r = system (string ("nautilus " + _film->directory().string()).c_str ()); + r = system (string ("nautilus " + _film->directory()->string()).c_str ()); if (WEXITSTATUS (r)) { error_dialog (this, _("Could not show DCP (could not run nautilus)")); } } else { int r = system ("which konqueror"); if (WEXITSTATUS (r) == 0) { - r = system (string ("konqueror " + _film->directory().string()).c_str ()); + r = system (string ("konqueror " + _film->directory()->string()).c_str ()); if (WEXITSTATUS (r)) { error_dialog (this, _("Could not show DCP (could not run konqueror)")); } @@ -826,6 +852,8 @@ private: add_item (_file_menu, _("&Open...\tCtrl-O"), ID_file_open, ALWAYS); _file_menu->AppendSeparator (); add_item (_file_menu, _("&Save\tCtrl-S"), ID_file_save, NEEDS_FILM); + _file_menu->AppendSeparator (); + add_item (_file_menu, _("Save as &template..."), ID_file_save_as_template, NEEDS_FILM); _history_position = _file_menu->GetMenuItems().GetCount(); @@ -1055,7 +1083,7 @@ private: } if (!_film_to_create.empty ()) { - _frame->new_film (_film_to_create); + _frame->new_film (_film_to_create, optional ()); if (!_content_to_add.empty ()) { _frame->film()->examine_and_add_content (content_factory (_frame->film(), _content_to_add)); } diff --git a/src/tools/dcpomatic_batch.cc b/src/tools/dcpomatic_batch.cc index a112e457a..9e2d6969d 100644 --- a/src/tools/dcpomatic_batch.cc +++ b/src/tools/dcpomatic_batch.cc @@ -45,7 +45,7 @@ using boost::shared_ptr; using boost::thread; using boost::scoped_array; -static std::string film_to_load; +static boost::optional film_to_load; enum { ID_file_add_film = 1, @@ -318,13 +318,15 @@ class App : public wxApp this->Bind (wxEVT_IDLE, boost::bind (&App::idle, this)); shared_ptr film; - if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) { + if (film_to_load && boost::filesystem::is_directory (film_to_load.get())) { try { - film.reset (new Film (film_to_load)); + film.reset (new Film (film_to_load.get())); film->read_metadata (); film->make_dcp (); } catch (exception& e) { - error_dialog (0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load, e.what()))); + error_dialog ( + 0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load->string(), e.what())) + ); } } diff --git a/src/tools/dcpomatic_cli.cc b/src/tools/dcpomatic_cli.cc index bd1a4e4aa..00087d6a0 100644 --- a/src/tools/dcpomatic_cli.cc +++ b/src/tools/dcpomatic_cli.cc @@ -173,7 +173,7 @@ show_servers () int main (int argc, char* argv[]) { - string film_dir; + boost::filesystem::path film_dir; bool progress = true; bool no_remote = false; optional threads; @@ -278,7 +278,7 @@ main (int argc, char* argv[]) film.reset (new Film (film_dir)); film->read_metadata (); } catch (std::exception& e) { - cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n"; + cerr << argv[0] << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n"; exit (EXIT_FAILURE); } diff --git a/src/tools/dcpomatic_create.cc b/src/tools/dcpomatic_create.cc index fd950807c..a3adc8e3e 100644 --- a/src/tools/dcpomatic_create.cc +++ b/src/tools/dcpomatic_create.cc @@ -44,6 +44,7 @@ using std::list; using std::exception; using boost::shared_ptr; using boost::dynamic_pointer_cast; +using boost::optional; static void syntax (string n) @@ -52,6 +53,7 @@ syntax (string n) << " -v, --version show DCP-o-matic version\n" << " -h, --help show this help\n" << " -n, --name film name\n" + << " -t, --template template name\n" << " -c, --dcp-content-type FTR, SHR, TLR, TST, XSN, RTG, TSR, POL, PSA or ADV\n" << " --container-ratio 119, 133, 137, 138, 166, 178, 185 or 239\n" << " --content-ratio 119, 133, 137, 138, 166, 178, 185 or 239\n" @@ -88,6 +90,7 @@ main (int argc, char* argv[]) dcpomatic_setup (); string name; + optional template_name; DCPContentType const * dcp_content_type = DCPContentType::from_isdcf_name ("TST"); Ratio const * container_ratio = 0; Ratio const * content_ratio = 0; @@ -103,6 +106,7 @@ main (int argc, char* argv[]) { "version", no_argument, 0, 'v'}, { "help", no_argument, 0, 'h'}, { "name", required_argument, 0, 'n'}, + { "template", required_argument, 0, 'f'}, { "dcp-content-type", required_argument, 0, 'c'}, { "container-ratio", required_argument, 0, 'A'}, { "content-ratio", required_argument, 0, 'B'}, @@ -114,7 +118,7 @@ main (int argc, char* argv[]) { 0, 0, 0, 0} }; - int c = getopt_long (argc, argv, "vhn:c:A:B:C:s:o:DE", long_options, &option_index); + int c = getopt_long (argc, argv, "vhn:f:c:A:B:C:s:o:DE", long_options, &option_index); if (c == -1) { break; } @@ -129,6 +133,9 @@ main (int argc, char* argv[]) case 'n': name = optarg; break; + case 't': + template_name = optarg; + break; case 'c': dcp_content_type = DCPContentType::from_isdcf_name (optarg); if (dcp_content_type == 0) { @@ -206,7 +213,10 @@ main (int argc, char* argv[]) } try { - shared_ptr film (new Film (output, false)); + shared_ptr film (new Film (output)); + if (template_name) { + film->use_template (template_name.get()); + } film->set_name (name); film->set_container (container_ratio); diff --git a/src/tools/dcpomatic_kdm_cli.cc b/src/tools/dcpomatic_kdm_cli.cc index 65b98ee42..f0097d7de 100644 --- a/src/tools/dcpomatic_kdm_cli.cc +++ b/src/tools/dcpomatic_kdm_cli.cc @@ -39,6 +39,7 @@ using std::cerr; using std::list; using std::vector; using boost::shared_ptr; +using boost::optional; static void help () @@ -217,7 +218,7 @@ int main (int argc, char* argv[]) valid_to = valid_from.get() + duration_from_string (duration_string); } - string const film_dir = argv[optind]; + boost::filesystem::path const film_dir = argv[optind]; dcpomatic_setup_path_encoding (); dcpomatic_setup (); @@ -230,7 +231,7 @@ int main (int argc, char* argv[]) cout << "Read film " << film->name () << "\n"; } } catch (std::exception& e) { - cerr << program_name << ": error reading film `" << film_dir << "' (" << e.what() << ")\n"; + cerr << program_name << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n"; exit (EXIT_FAILURE); } diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index 5e50df227..cb3d49f31 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -41,6 +41,7 @@ using std::cerr; using std::string; using std::pair; using boost::shared_ptr; +using boost::optional; using dcp::Data; static shared_ptr film; @@ -101,7 +102,7 @@ help (string n) int main (int argc, char* argv[]) { - string film_dir; + boost::filesystem::path film_dir; string server_host; while (true) { @@ -132,7 +133,7 @@ main (int argc, char* argv[]) } } - if (server_host.empty() || film_dir.empty()) { + if (server_host.empty() || film_dir.string().empty()) { help (argv[0]); exit (EXIT_FAILURE); } diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index a5e1e82e9..edf5d3bd7 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -127,8 +127,8 @@ FilmEditor::set_film (shared_ptr film) _film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _2)); } - if (_film) { - FileChanged (_film->directory ()); + if (_film && _film->directory()) { + FileChanged (_film->directory().get()); } else { FileChanged (""); } diff --git a/src/wx/new_film_dialog.cc b/src/wx/new_film_dialog.cc index 04b9e1057..907b289b5 100644 --- a/src/wx/new_film_dialog.cc +++ b/src/wx/new_film_dialog.cc @@ -18,14 +18,15 @@ */ -#include -#include #include "lib/config.h" #include "new_film_dialog.h" #include "wx_util.h" #ifdef DCPOMATIC_USE_OWN_PICKER #include "dir_picker_ctrl.h" #endif +#include +#include +#include using namespace std; using namespace boost; @@ -53,21 +54,49 @@ NewFilmDialog::NewFilmDialog (wxWindow* parent) _folder->SetPath (std_to_wx (_directory.get().string())); add (_folder); + _use_template = new wxCheckBox (this, wxID_ANY, _("From template")); + add (_use_template); + _template_name = new wxChoice (this, wxID_ANY); + add (_template_name); + _name->SetFocus (); + _template_name->Enable (false); + + BOOST_FOREACH (string i, Config::instance()->template_names ()) { + _template_name->Append (std_to_wx (i)); + } + + _use_template->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, bind (&NewFilmDialog::use_template_clicked, this)); layout (); } +void +NewFilmDialog::use_template_clicked () +{ + _template_name->Enable (_use_template->GetValue ()); +} + NewFilmDialog::~NewFilmDialog () { _directory = wx_to_std (_folder->GetPath ()); } boost::filesystem::path -NewFilmDialog::get_path () const +NewFilmDialog::path () const { filesystem::path p; p /= wx_to_std (_folder->GetPath ()); p /= wx_to_std (_name->GetValue ()); return p; } + +optional +NewFilmDialog::template_name () const +{ + if (!_use_template->GetValue() || _template_name->GetSelection() == -1) { + return optional (); + } + + return wx_to_std (_template_name->GetString(_template_name->GetSelection())); +} diff --git a/src/wx/new_film_dialog.h b/src/wx/new_film_dialog.h index 6dc83d815..81dd29fea 100644 --- a/src/wx/new_film_dialog.h +++ b/src/wx/new_film_dialog.h @@ -31,14 +31,19 @@ public: NewFilmDialog (wxWindow *); ~NewFilmDialog (); - boost::filesystem::path get_path () const; + boost::filesystem::path path () const; + boost::optional template_name () const; private: + void use_template_clicked (); + wxTextCtrl* _name; #ifdef DCPOMATIC_USE_OWN_PICKER DirPickerCtrl* _folder; #else wxDirPickerCtrl* _folder; #endif + wxCheckBox* _use_template; + wxChoice* _template_name; static boost::optional _directory; }; diff --git a/src/wx/save_template_dialog.cc b/src/wx/save_template_dialog.cc new file mode 100644 index 000000000..eff61a256 --- /dev/null +++ b/src/wx/save_template_dialog.cc @@ -0,0 +1,40 @@ +/* + Copyright (C) 2016 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic 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. + + DCP-o-matic 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 DCP-o-matic. If not, see . + +*/ + +#include "save_template_dialog.h" +#include "wx_util.h" +#include + +using std::string; + +SaveTemplateDialog::SaveTemplateDialog (wxWindow* parent) + : TableDialog (parent, _("Save template"), 2, 1, true) +{ + add (_("Template name"), true); + _name = add (new wxTextCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (300, -1))); + _name->SetFocus (); + layout (); +} + +string +SaveTemplateDialog::name () const +{ + return wx_to_std (_name->GetValue ()); +} diff --git a/src/wx/save_template_dialog.h b/src/wx/save_template_dialog.h new file mode 100644 index 000000000..8069fa2f0 --- /dev/null +++ b/src/wx/save_template_dialog.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2016 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic 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. + + DCP-o-matic 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 DCP-o-matic. If not, see . + +*/ + +#include "table_dialog.h" + +class SaveTemplateDialog : public TableDialog +{ +public: + SaveTemplateDialog (wxWindow* parent); + + std::string name () const; + +private: + wxTextCtrl* _name; +}; diff --git a/src/wx/wscript b/src/wx/wscript index ee77e6c20..1f9aed6b3 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -75,6 +75,7 @@ sources = """ repeat_dialog.cc report_problem_dialog.cc rgba_colour_picker.cc + save_template_dialog.cc screen_dialog.cc screens_panel.cc self_dkdm_dialog.cc diff --git a/test/ffmpeg_dcp_test.cc b/test/ffmpeg_dcp_test.cc index a28119110..748695efe 100644 --- a/test/ffmpeg_dcp_test.cc +++ b/test/ffmpeg_dcp_test.cc @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_dcp_test) BOOST_AUTO_TEST_CASE (ffmpeg_have_dcp_test) { boost::filesystem::path p = test_film_dir ("ffmpeg_dcp_test"); - shared_ptr film (new Film (p.string ())); + shared_ptr film (new Film (p)); film->read_metadata (); BOOST_CHECK (!film->cpls().empty()); diff --git a/test/srt_subtitle_test.cc b/test/srt_subtitle_test.cc index d29a91ed2..f733567d5 100644 --- a/test/srt_subtitle_test.cc +++ b/test/srt_subtitle_test.cc @@ -87,7 +87,7 @@ check_subtitle_file (shared_ptr film, boost::filesystem::path ref) { /* Find the subtitle file and check it */ for ( - boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory() / film->dcp_name (false)); + boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory().get() / film->dcp_name (false)); i != boost::filesystem::directory_iterator (); ++i) { diff --git a/test/ssa_subtitle_test.cc b/test/ssa_subtitle_test.cc index f6c65b1af..ed8c20424 100644 --- a/test/ssa_subtitle_test.cc +++ b/test/ssa_subtitle_test.cc @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE (ssa_subtitle_test1) /* Find the subtitle file and check it */ for ( - boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory() / film->dcp_name (false)); + boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory().get() / film->dcp_name (false)); i != boost::filesystem::directory_iterator (); ++i) { diff --git a/test/test.cc b/test/test.cc index 0b98f7b82..86dddbeda 100644 --- a/test/test.cc +++ b/test/test.cc @@ -112,7 +112,7 @@ new_test_film (string name) boost::filesystem::remove_all (p); } - shared_ptr film = shared_ptr (new Film (p.string())); + shared_ptr film = shared_ptr (new Film (p)); film->write_metadata (); return film; }