#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include "util.h"
-#include "decoder_factory.h"
class Job;
class Encoder;
+#include <libcxml/cxml.h>
#include "audio_content.h"
+using boost::shared_ptr;
+
AudioContent::AudioContent (boost::filesystem::path f)
: Content (f)
{
}
+
+AudioContent::AudioContent (shared_ptr<const cxml::Node> node)
+ : Content (node)
+{
+
+}
#include "content.h"
#include "util.h"
+namespace cxml {
+ class Node;
+}
+
class AudioContent : public virtual Content
{
public:
AudioContent (boost::filesystem::path);
+ AudioContent (boost::shared_ptr<const cxml::Node>);
virtual int audio_channels () const = 0;
virtual ContentAudioFrame audio_length () const = 0;
#include <fstream>
#include <glib.h>
#include <boost/filesystem.hpp>
+#include <libcxml/cxml.h>
#include "config.h"
#include "server.h"
#include "scaler.h"
using std::ifstream;
using std::string;
using std::ofstream;
+using std::list;
using boost::shared_ptr;
+using boost::optional;
Config* Config::_instance = 0;
_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");
+ _default_dci_metadata = DCIMetadata (f.node_child ("DCIMetadata"));
+}
+
+void
+Config::read_old_metadata ()
+{
+ ifstream f (file(true).c_str ());
string line;
while (getline (f, line)) {
if (line.empty ()) {
_language = v;
}
- _default_dci_metadata.read (k, v);
+ _default_dci_metadata.read_old_metadata (k, v);
}
}
/** @return Filename to write configuration to */
string
-Config::file () const
+Config::file (bool old) const
{
boost::filesystem::path p;
p /= g_get_user_config_dir ();
- p /= N_(".dvdomatic");
+ if (old) {
+ p /= ".dvdomatic";
+ } else {
+ p /= ".dvdomatic.xml";
+ }
return p.string ();
}
void
Config::write () const
{
- ofstream f (file().c_str ());
- f << N_("num_local_encoding_threads ") << _num_local_encoding_threads << N_("\n")
- << N_("default_directory ") << _default_directory << N_("\n")
- << N_("server_port ") << _server_port << N_("\n");
+ xmlpp::Document doc;
+ xmlpp::Element* root = doc.create_root_node ("Config");
+ root->add_child("NumLocalEncodingThreads")->add_child_text (boost::lexical_cast<string> (_num_local_encoding_threads));
+ root->add_child("DefaultDirectory")->add_child_text (_default_directory);
+ root->add_child("ServerPort")->add_child_text (boost::lexical_cast<string> (_server_port));
if (_reference_scaler) {
- f << "reference_scaler " << _reference_scaler->id () << "\n";
+ root->add_child("ReferenceScaler")->add_child_text (_reference_scaler->id ());
}
for (vector<Filter const *>::const_iterator i = _reference_filters.begin(); i != _reference_filters.end(); ++i) {
- f << N_("reference_filter ") << (*i)->id () << N_("\n");
+ root->add_child("ReferenceFilter")->add_child_text ((*i)->id ());
}
for (vector<ServerDescription*>::const_iterator i = _servers.begin(); i != _servers.end(); ++i) {
- f << N_("server ") << (*i)->as_metadata () << N_("\n");
+ (*i)->as_xml (root->add_child ("Server"));
}
- f << N_("tms_ip ") << _tms_ip << N_("\n");
- f << N_("tms_path ") << _tms_path << N_("\n");
- f << N_("tms_user ") << _tms_user << N_("\n");
- f << N_("tms_password ") << _tms_password << N_("\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());
}
- _default_dci_metadata.write (f);
+ _default_dci_metadata.as_xml (root->add_child ("DCIMetadata"));
+
+ doc.write_to_file_formatted (file (false));
}
string
private:
Config ();
- std::string file () const;
+ std::string file (bool) const;
+ void read_old_metadata ();
/** number of threads to use for J2K encoding on the local machine */
int _num_local_encoding_threads;
#include <boost/thread/mutex.hpp>
+#include <libxml++/libxml++.h>
+#include <libcxml/cxml.h>
#include "content.h"
#include "util.h"
}
+Content::Content (shared_ptr<const cxml::Node> node)
+{
+ _file = node->string_child ("File");
+ _digest = node->string_child ("Digest");
+}
+
+void
+Content::as_xml (xmlpp::Node* node) const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+ node->add_child("File")->add_child_text (_file.string());
+ node->add_child("Digest")->add_child_text (_digest);
+}
+
void
Content::examine (shared_ptr<Film>, shared_ptr<Job>, bool)
{
#include <boost/filesystem.hpp>
#include <boost/signals2.hpp>
#include <boost/thread/mutex.hpp>
+#include <libxml++/libxml++.h>
+
+namespace cxml {
+ class Node;
+}
class Job;
class Film;
{
public:
Content (boost::filesystem::path);
+ Content (boost::shared_ptr<const cxml::Node>);
virtual void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
virtual std::string summary () const = 0;
+ virtual void as_xml (xmlpp::Node *) const;
boost::filesystem::path file () const {
boost::mutex::scoped_lock lm (_mutex);
*/
#include <iostream>
+#include <libcxml/cxml.h>
#include "dci_metadata.h"
#include "i18n.h"
-using namespace std;
+using std::string;
+using boost::shared_ptr;
+
+DCIMetadata::DCIMetadata (shared_ptr<const cxml::Node> node)
+{
+ audio_language = node->string_child ("AudioLanguage");
+ subtitle_language = node->string_child ("SubtitleLanguage");
+ territory = node->string_child ("Territory");
+ rating = node->string_child ("Rating");
+ studio = node->string_child ("Studio");
+ facility = node->string_child ("Facility");
+ package_type = node->string_child ("PackageType");
+}
void
-DCIMetadata::write (ostream& f) const
+DCIMetadata::as_xml (xmlpp::Node* root) const
{
- f << N_("audio_language ") << audio_language << N_("\n");
- f << N_("subtitle_language ") << subtitle_language << N_("\n");
- f << N_("territory ") << territory << N_("\n");
- f << N_("rating ") << rating << N_("\n");
- f << N_("studio ") << studio << N_("\n");
- f << N_("facility ") << facility << N_("\n");
- f << N_("package_type ") << package_type << N_("\n");
+ root->add_child("AudioLanguage")->add_child_text (audio_language);
+ root->add_child("SubtitleLanguage")->add_child_text (subtitle_language);
+ root->add_child("Territory")->add_child_text (territory);
+ root->add_child("Rating")->add_child_text (rating);
+ root->add_child("Studio")->add_child_text (studio);
+ root->add_child("Facility")->add_child_text (facility);
+ root->add_child("PackageType")->add_child_text (package_type);
}
void
-DCIMetadata::read (string k, string v)
+DCIMetadata::read_old_metadata (string k, string v)
{
if (k == N_("audio_language")) {
audio_language = v;
#define DVDOMATIC_DCI_METADATA_H
#include <string>
+#include <libxml++/libxml++.h>
+
+namespace cxml {
+ class Node;
+}
class DCIMetadata
{
public:
- void read (std::string, std::string);
- void write (std::ostream &) const;
+ DCIMetadata () {}
+ DCIMetadata (boost::shared_ptr<const cxml::Node>);
+
+ void as_xml (xmlpp::Node *) const;
+ void read_old_metadata (std::string, std::string);
std::string audio_language;
std::string subtitle_language;
+++ /dev/null
-/*
- 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.
-
-*/
-
-/** @file src/decoder_factory.cc
- * @brief A method to create an appropriate decoder for some content.
- */
-
-#include <boost/filesystem.hpp>
-#include "ffmpeg_decoder.h"
-#include "imagemagick_decoder.h"
-#include "film.h"
-#include "sndfile_decoder.h"
-#include "decoder_factory.h"
-
-using std::string;
-using std::pair;
-using std::make_pair;
-using boost::shared_ptr;
-using boost::dynamic_pointer_cast;
-
-Decoders
-decoder_factory (
- shared_ptr<Film> f
- )
-{
- return Decoders ();
-}
+++ /dev/null
-/*
- 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.
-
-*/
-
-#ifndef DVDOMATIC_DECODER_FACTORY_H
-#define DVDOMATIC_DECODER_FACTORY_H
-
-/** @file src/decoder_factory.h
- * @brief A method to create appropriate decoders for some content.
- */
-
-class Film;
-class VideoDecoder;
-class AudioDecoder;
-
-struct Decoders {
- Decoders () {}
-
- Decoders (boost::shared_ptr<VideoDecoder> v, boost::shared_ptr<AudioDecoder> a)
- : video (v)
- , audio (a)
- {}
-
- boost::shared_ptr<VideoDecoder> video;
- boost::shared_ptr<AudioDecoder> audio;
-};
-
-extern Decoders decoder_factory (
- boost::shared_ptr<Film>
- );
-
-#endif
+#include <libcxml/cxml.h>
#include "ffmpeg_content.h"
#include "ffmpeg_decoder.h"
#include "compose.hpp"
#include "i18n.h"
using std::string;
+using std::vector;
+using std::list;
using boost::shared_ptr;
+using boost::lexical_cast;
int const FFmpegContentProperty::SUBTITLE_STREAMS = 100;
int const FFmpegContentProperty::SUBTITLE_STREAM = 101;
}
+FFmpegContent::FFmpegContent (shared_ptr<const cxml::Node> node)
+ : Content (node)
+ , VideoContent (node)
+ , AudioContent (node)
+{
+ list<shared_ptr<cxml::Node> > c = node->node_children ("SubtitleStream");
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) {
+ _subtitle_streams.push_back (FFmpegSubtitleStream (*i));
+ if ((*i)->optional_number_child<int> ("Selected")) {
+ _subtitle_stream = _subtitle_streams.back ();
+ }
+ }
+
+ c = node->node_children ("AudioStream");
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) {
+ _audio_streams.push_back (FFmpegAudioStream (*i));
+ if ((*i)->optional_number_child<int> ("Selected")) {
+ _audio_stream = _audio_streams.back ();
+ }
+ }
+}
+
+void
+FFmpegContent::as_xml (xmlpp::Node* node) const
+{
+ node->add_child("Type")->add_child_text ("FFmpeg");
+ Content::as_xml (node);
+ VideoContent::as_xml (node);
+
+ boost::mutex::scoped_lock lm (_mutex);
+
+ for (vector<FFmpegSubtitleStream>::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
+ xmlpp::Node* t = node->add_child("SubtitleStream");
+ if (_subtitle_stream && *i == _subtitle_stream.get()) {
+ t->add_child("Selected")->add_child_text("1");
+ }
+ i->as_xml (t);
+ }
+
+ for (vector<FFmpegAudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) {
+ xmlpp::Node* t = node->add_child("AudioStream");
+ if (_audio_stream && *i == _audio_stream.get()) {
+ t->add_child("Selected")->add_child_text("1");
+ }
+ i->as_xml (t);
+ }
+}
+
void
FFmpegContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool quick)
{
{
return a.id == b.id;
}
+
+FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node)
+{
+ name = node->string_child ("Name");
+ id = node->number_child<int> ("Id");
+ frame_rate = node->number_child<int> ("FrameRate");
+ channel_layout = node->number_child<int64_t> ("ChannelLayout");
+}
+
+void
+FFmpegAudioStream::as_xml (xmlpp::Node* root) const
+{
+ root->add_child("Name")->add_child_text (name);
+ root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+ root->add_child("FrameRate")->add_child_text (lexical_cast<string> (frame_rate));
+ root->add_child("ChannelLayout")->add_child_text (lexical_cast<string> (channel_layout));
+}
+
+/** Construct a SubtitleStream from a value returned from to_string().
+ * @param t String returned from to_string().
+ * @param v State file version.
+ */
+FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr<const cxml::Node> node)
+{
+ name = node->string_child ("Name");
+ id = node->number_child<int> ("Id");
+}
+
+void
+FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const
+{
+ root->add_child("Name")->add_child_text (name);
+ root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+}
, channel_layout (c)
{}
+ FFmpegAudioStream (boost::shared_ptr<const cxml::Node>);
+
+ void as_xml (xmlpp::Node *) const;
+
int channels () const {
return av_get_channel_layout_nb_channels (channel_layout);
}
, id (i)
{}
+ FFmpegSubtitleStream (boost::shared_ptr<const cxml::Node>);
+
+ void as_xml (xmlpp::Node *) const;
+
std::string name;
int id;
};
{
public:
FFmpegContent (boost::filesystem::path);
+ FFmpegContent (boost::shared_ptr<const cxml::Node>);
void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
std::string summary () const;
+ void as_xml (xmlpp::Node *) const;
/* AudioContent */
int audio_channels () const;
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time.hpp>
+#include <libxml++/libxml++.h>
+#include <libcxml/cxml.h>
#include "film.h"
#include "format.h"
#include "job.h"
#include "exceptions.h"
#include "examine_content_job.h"
#include "scaler.h"
-#include "decoder_factory.h"
#include "config.h"
#include "version.h"
#include "ui_signaller.h"
#include "sndfile_decoder.h"
#include "analyse_audio_job.h"
#include "playlist.h"
+#include "ffmpeg_content.h"
+#include "imagemagick_content.h"
+#include "sndfile_content.h"
#include "i18n.h"
using std::min;
using std::make_pair;
using std::endl;
+using std::list;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::to_upper_copy;
, _scaler (Scaler::from_id ("bicubic"))
, _trim_start (0)
, _trim_end (0)
- , _dcp_ab (false)
+ , _ab (false)
, _audio_gain (0)
, _audio_delay (0)
, _with_subtitles (false)
, _scaler (o._scaler)
, _trim_start (o._trim_start)
, _trim_end (o._trim_end)
- , _dcp_ab (o._dcp_ab)
+ , _ab (o._ab)
, _audio_gain (o._audio_gain)
, _audio_delay (o._audio_delay)
, _with_subtitles (o._with_subtitles)
<< "_" << j2k_bandwidth()
<< "_" << boost::lexical_cast<int> (colour_lut());
- if (dcp_ab()) {
+ if (ab()) {
pair<string, string> fa = Filter::ffmpeg_strings (Config::instance()->reference_filters());
s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second;
}
shared_ptr<Job> r;
- if (dcp_ab()) {
+ if (ab()) {
r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this())));
} else {
r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this())));
void
Film::write_metadata () const
{
+ ContentList the_content = content ();
+
boost::mutex::scoped_lock lm (_state_mutex);
boost::filesystem::create_directories (directory());
- string const m = file ("metadata");
- ofstream f (m.c_str ());
- if (!f.good ()) {
- throw CreateFileError (m);
- }
-
- f << "version " << state_version << endl;
+ xmlpp::Document doc;
+ xmlpp::Element* root = doc.create_root_node ("Metadata");
- /* User stuff */
- f << "name " << _name << endl;
- f << "use_dci_name " << _use_dci_name << endl;
-// f << "content " << _content << endl;
- f << "trust_content_headers " << (_trust_content_headers ? "1" : "0") << endl;
+ root->add_child("Version")->add_child_text (boost::lexical_cast<string> (state_version));
+ root->add_child("Name")->add_child_text (_name);
+ root->add_child("UseDCIName")->add_child_text (_use_dci_name ? "1" : "0");
+ root->add_child("TrustContentHeaders")->add_child_text (_trust_content_headers ? "1" : "0");
if (_dcp_content_type) {
- f << "dcp_content_type " << _dcp_content_type->dci_name () << endl;
+ root->add_child("DCPContentType")->add_child_text (_dcp_content_type->dci_name ());
}
if (_format) {
- f << "format " << _format->as_metadata () << endl;
+ root->add_child("Format")->add_child_text (_format->id ());
}
- f << "left_crop " << _crop.left << endl;
- f << "right_crop " << _crop.right << endl;
- f << "top_crop " << _crop.top << endl;
- f << "bottom_crop " << _crop.bottom << endl;
- for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
- f << "filter " << (*i)->id () << endl;
- }
- f << "scaler " << _scaler->id () << endl;
- f << "trim_start " << _trim_start << endl;
- f << "trim_end " << _trim_end << endl;
- f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl;
-// if (_content_audio_stream) {
-// f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl;
-// }
-// for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
-// f << "external_audio " << *i << endl;
-// }
-// f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl;
- f << "audio_gain " << _audio_gain << endl;
- f << "audio_delay " << _audio_delay << endl;
-// f << "still_duration " << _still_duration << endl;
-// if (_subtitle_stream) {
-// f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl;
-// }
- f << "with_subtitles " << _with_subtitles << endl;
- f << "subtitle_offset " << _subtitle_offset << endl;
- f << "subtitle_scale " << _subtitle_scale << endl;
- f << "colour_lut " << _colour_lut << endl;
- f << "j2k_bandwidth " << _j2k_bandwidth << endl;
- _dci_metadata.write (f);
- f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl;
- f << "dcp_frame_rate " << _dcp_frame_rate << endl;
-// f << "width " << _size.width << endl;
-// f << "height " << _size.height << endl;
-// f << "length " << _length.get_value_or(0) << endl;
-// f << "content_digest " << _content_digest << endl;
-
-// for (vector<shared_ptr<AudioStream> >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
-// f << "content_audio_stream " << (*i)->to_string () << endl;
-// }
-
-// f << "external_audio_stream " << _sndfile_stream->to_string() << endl;
+ root->add_child("LeftCrop")->add_child_text (boost::lexical_cast<string> (_crop.left));
+ root->add_child("RightCrop")->add_child_text (boost::lexical_cast<string> (_crop.right));
+ root->add_child("TopCrop")->add_child_text (boost::lexical_cast<string> (_crop.top));
+ root->add_child("BottomCrop")->add_child_text (boost::lexical_cast<string> (_crop.bottom));
-// for (vector<shared_ptr<SubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
-// f << "subtitle_stream " << (*i)->to_string () << endl;
-// }
-
-// f << "source_frame_rate " << _source_frame_rate << endl;
+ for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
+ root->add_child("Filter")->add_child_text ((*i)->id ());
+ }
+
+ root->add_child("Scaler")->add_child_text (_scaler->id ());
+ root->add_child("TrimStart")->add_child_text (boost::lexical_cast<string> (_trim_start));
+ root->add_child("TrimEnd")->add_child_text (boost::lexical_cast<string> (_trim_end));
+ root->add_child("AB")->add_child_text (_ab ? "1" : "0");
+ root->add_child("AudioGain")->add_child_text (boost::lexical_cast<string> (_audio_gain));
+ root->add_child("AudioDelay")->add_child_text (boost::lexical_cast<string> (_audio_delay));
+ root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0");
+ root->add_child("SubtitleOffset")->add_child_text (boost::lexical_cast<string> (_subtitle_offset));
+ root->add_child("SubtitleScale")->add_child_text (boost::lexical_cast<string> (_subtitle_scale));
+ root->add_child("ColourLUT")->add_child_text (boost::lexical_cast<string> (_colour_lut));
+ root->add_child("J2KBandwidth")->add_child_text (boost::lexical_cast<string> (_j2k_bandwidth));
+ _dci_metadata.as_xml (root->add_child ("DCIMetadata"));
+ root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date));
+ root->add_child("DCPFrameRate")->add_child_text (boost::lexical_cast<string> (_dcp_frame_rate));
+
+ for (ContentList::iterator i = the_content.begin(); i != the_content.end(); ++i) {
+ (*i)->as_xml (root->add_child ("Content"));
+ }
+
+ doc.write_to_file_formatted (file ("metadata.xml"));
_dirty = false;
}
{
boost::mutex::scoped_lock lm (_state_mutex);
-// _external_audio.clear ();
-// _content_audio_streams.clear ();
-// _subtitle_streams.clear ();
-
- boost::optional<int> version;
-
- /* Backward compatibility things */
- boost::optional<int> audio_sample_rate;
- boost::optional<int> audio_stream_index;
- boost::optional<int> subtitle_stream_index;
-
- ifstream f (file ("metadata").c_str());
- if (!f.good()) {
- throw OpenFileError (file ("metadata"));
+ if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
+ throw StringError (_("This film was created with an older version of DVD-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!"));
}
+
+ cxml::File f (file ("metadata.xml"), "Metadata");
- multimap<string, string> kv = read_key_value (f);
+ _name = f.string_child ("Name");
+ _use_dci_name = f.bool_child ("UseDCIName");
+ _trust_content_headers = f.bool_child ("TrustContentHeaders");
- /* We need version before anything else */
- multimap<string, string>::iterator v = kv.find ("version");
- if (v != kv.end ()) {
- version = atoi (v->second.c_str());
+ {
+ optional<string> c = f.optional_string_child ("DCPContentType");
+ if (c) {
+ _dcp_content_type = DCPContentType::from_dci_name (c.get ());
+ }
}
-
- for (multimap<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) {
- string const k = i->first;
- string const v = i->second;
- if (k == "audio_sample_rate") {
- audio_sample_rate = atoi (v.c_str());
+ {
+ optional<string> c = f.optional_string_child ("Format");
+ if (c) {
+ _format = Format::from_id (c.get ());
}
+ }
- /* User-specified stuff */
- if (k == "name") {
- _name = v;
- } else if (k == "use_dci_name") {
- _use_dci_name = (v == "1");
- } else if (k == "content") {
-// _content = v;
- } else if (k == "trust_content_headers") {
- _trust_content_headers = (v == "1");
- } else if (k == "dcp_content_type") {
- if (version < 3) {
- _dcp_content_type = DCPContentType::from_pretty_name (v);
- } else {
- _dcp_content_type = DCPContentType::from_dci_name (v);
- }
- } else if (k == "format") {
- _format = Format::from_metadata (v);
- } else if (k == "left_crop") {
- _crop.left = atoi (v.c_str ());
- } else if (k == "right_crop") {
- _crop.right = atoi (v.c_str ());
- } else if (k == "top_crop") {
- _crop.top = atoi (v.c_str ());
- } else if (k == "bottom_crop") {
- _crop.bottom = atoi (v.c_str ());
- } else if (k == "filter") {
- _filters.push_back (Filter::from_id (v));
- } else if (k == "scaler") {
- _scaler = Scaler::from_id (v);
- } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") {
- _trim_start = atoi (v.c_str ());
- } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "trim_end") {
- _trim_end = atoi (v.c_str ());
- } else if (k == "dcp_ab") {
- _dcp_ab = (v == "1");
- } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) {
- if (!version) {
- audio_stream_index = atoi (v.c_str ());
- } else {
-// _content_audio_stream = audio_stream_factory (v, version);
- }
- } else if (k == "external_audio") {
-// _external_audio.push_back (v);
- } else if (k == "use_content_audio") {
-// _use_content_audio = (v == "1");
- } else if (k == "audio_gain") {
- _audio_gain = atof (v.c_str ());
- } else if (k == "audio_delay") {
- _audio_delay = atoi (v.c_str ());
- } else if (k == "still_duration") {
-// _still_duration = atoi (v.c_str ());
- } else if (k == "selected_subtitle_stream") {
- if (!version) {
- subtitle_stream_index = atoi (v.c_str ());
- } else {
-// _subtitle_stream = subtitle_stream_factory (v, version);
- }
- } else if (k == "with_subtitles") {
- _with_subtitles = (v == "1");
- } else if (k == "subtitle_offset") {
- _subtitle_offset = atoi (v.c_str ());
- } else if (k == "subtitle_scale") {
- _subtitle_scale = atof (v.c_str ());
- } else if (k == "colour_lut") {
- _colour_lut = atoi (v.c_str ());
- } else if (k == "j2k_bandwidth") {
- _j2k_bandwidth = atoi (v.c_str ());
- } else if (k == "dci_date") {
- _dci_date = boost::gregorian::from_undelimited_string (v);
- } else if (k == "dcp_frame_rate") {
- _dcp_frame_rate = atoi (v.c_str ());
+ _crop.left = f.number_child<int> ("CropLeft");
+ _crop.right = f.number_child<int> ("CropRight");
+ _crop.top = f.number_child<int> ("CropTop");
+ _crop.bottom = f.number_child<int> ("CropBottom");
+
+ {
+ list<shared_ptr<cxml::Node> > c = f.node_children ("Filter");
+ for (list<shared_ptr<cxml::Node> >::iterator i = c.begin(); i != c.end(); ++i) {
+ _filters.push_back (Filter::from_id ((*i)->content ()));
}
+ }
- _dci_metadata.read (k, v);
+ _scaler = Scaler::from_id (f.string_child ("Scaler"));
+ _trim_start = f.number_child<int> ("TrimStart");
+ _trim_end = f.number_child<int> ("TrimEnd");
+ _ab = f.bool_child ("AB");
+ _audio_gain = f.number_child<float> ("AudioGain");
+ _audio_delay = f.number_child<int> ("AudioDelay");
+ _with_subtitles = f.bool_child ("WithSubtitles");
+ _subtitle_offset = f.number_child<float> ("SubtitleOffset");
+ _subtitle_scale = f.number_child<float> ("SubtitleScale");
+ _colour_lut = f.number_child<int> ("ColourLUT");
+ _j2k_bandwidth = f.number_child<int> ("J2KBandwidth");
+ _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata"));
+ _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate"));
+ _dcp_frame_rate = f.number_child<int> ("DCPFrameRate");
+
+ list<shared_ptr<cxml::Node> > c = f.node_children ("Content");
+ for (list<shared_ptr<cxml::Node> >::iterator i = c.begin(); i != c.end(); ++i) {
+
+ string const type = (*i)->string_child ("Type");
- /* Cached stuff */
- if (k == "width") {
-// _size.width = atoi (v.c_str ());
- } else if (k == "height") {
-// _size.height = atoi (v.c_str ());
- } else if (k == "length") {
- int const vv = atoi (v.c_str ());
- if (vv) {
-// _length = vv;
- }
- } else if (k == "content_digest") {
-// _content_digest = v;
- } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) {
-// _content_audio_streams.push_back (audio_stream_factory (v, version));
- } else if (k == "external_audio_stream") {
-// _sndfile_stream = audio_stream_factory (v, version);
- } else if (k == "subtitle_stream") {
-// _subtitle_streams.push_back (subtitle_stream_factory (v, version));
- } else if (k == "source_frame_rate") {
-// _source_frame_rate = atof (v.c_str ());
- } else if (version < 4 && k == "frames_per_second") {
-// _source_frame_rate = atof (v.c_str ());
- /* Fill in what would have been used for DCP frame rate by the older version */
-// _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate);
+ if (type == "FFmpeg") {
+ _content.push_back (shared_ptr<Content> (new FFmpegContent (*i)));
+ } else if (type == "ImageMagick") {
+ _content.push_back (shared_ptr<Content> (new ImageMagickContent (*i)));
+ } else if (type == "Sndfile") {
+ _content.push_back (shared_ptr<Content> (new SndfileContent (*i)));
}
}
}
void
-Film::set_dcp_ab (bool a)
+Film::set_ab (bool a)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _dcp_ab = a;
+ _ab = a;
}
- signal_changed (DCP_AB);
+ signal_changed (AB);
}
void
SCALER,
TRIM_START,
TRIM_END,
- DCP_AB,
+ AB,
AUDIO_GAIN,
AUDIO_DELAY,
STILL_DURATION,
return _trim_end;
}
- bool dcp_ab () const {
+ bool ab () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _dcp_ab;
+ return _ab;
}
float audio_gain () const {
void set_scaler (Scaler const *);
void set_trim_start (int);
void set_trim_end (int);
- void set_dcp_ab (bool);
+ void set_ab (bool);
void set_audio_gain (float);
void set_audio_delay (int);
void set_still_duration (int);
is the video without any filters or post-processing, and the right half
has the specified filters and post-processing.
*/
- bool _dcp_ab;
+ bool _ab;
/** Gain to apply to audio in dB */
float _audio_gain;
/** Delay to apply to audio (positive moves audio later) in milliseconds */
+#include <libcxml/cxml.h>
#include "imagemagick_content.h"
#include "compose.hpp"
#include "i18n.h"
using std::string;
+using boost::shared_ptr;
ImageMagickContent::ImageMagickContent (boost::filesystem::path f)
: Content (f)
_video_length = 10 * 24;
}
+ImageMagickContent::ImageMagickContent (shared_ptr<const cxml::Node> node)
+ : Content (node)
+ , VideoContent (node)
+{
+
+}
+
string
ImageMagickContent::summary () const
{
#include "video_content.h"
+namespace cxml {
+ class Node;
+}
+
class ImageMagickContent : public VideoContent
{
public:
ImageMagickContent (boost::filesystem::path);
+ ImageMagickContent (boost::shared_ptr<const cxml::Node>);
std::string summary () const;
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_array.hpp>
+#include <libcxml/cxml.h>
#include "server.h"
#include "util.h"
#include "scaler.h"
using boost::scoped_array;
using libdcp::Size;
+ServerDescription::ServerDescription (shared_ptr<const cxml::Node> node)
+{
+ _host_name = node->string_child ("HostName");
+ _threads = node->number_child<int> ("Threads");
+}
+
+void
+ServerDescription::as_xml (xmlpp::Node* root) const
+{
+ root->add_child("HostName")->add_child_text (_host_name);
+ root->add_child("Threads")->add_child_text (boost::lexical_cast<string> (_threads));
+}
+
/** Create a server description from a string of metadata returned from as_metadata().
* @param v Metadata.
* @return ServerDescription, or 0.
return new ServerDescription (b[0], atoi (b[1].c_str ()));
}
-/** @return Description of this server as text */
-string
-ServerDescription::as_metadata () const
-{
- stringstream s;
- s << _host_name << N_(" ") << _threads;
- return s.str ();
-}
-
Server::Server (shared_ptr<Log> log)
: _log (log)
{
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/thread/condition.hpp>
+#include <libxml++/libxml++.h>
#include "log.h"
class Socket;
+namespace cxml {
+ class Node;
+}
+
/** @class ServerDescription
* @brief Class to describe a server to which we can send encoding work.
*/
, _threads (t)
{}
+ ServerDescription (boost::shared_ptr<const cxml::Node>);
+
/** @return server's host name or IP address in string form */
std::string host_name () const {
return _host_name;
_threads = t;
}
- std::string as_metadata () const;
+ void as_xml (xmlpp::Node *) const;
static ServerDescription * create_from_metadata (std::string v);
#include "i18n.h"
-using namespace std;
+using std::string;
+using boost::shared_ptr;
SndfileContent::SndfileContent (boost::filesystem::path f)
: Content (f)
}
+SndfileContent::SndfileContent (shared_ptr<const cxml::Node> node)
+ : Content (node)
+ , AudioContent (node)
+
+{
+
+}
+
string
SndfileContent::summary () const
{
#include "audio_content.h"
+namespace cxml {
+ class Node;
+}
+
class SndfileContent : public AudioContent
{
public:
SndfileContent (boost::filesystem::path);
+ SndfileContent (boost::shared_ptr<const cxml::Node>);
std::string summary () const;
#include <boost/signals2.hpp>
#include "transcoder.h"
#include "encoder.h"
-#include "decoder_factory.h"
#include "film.h"
#include "matcher.h"
#include "delay_line.h"
* as a parameter to the constructor.
*/
-#include "decoder_factory.h"
-
class Film;
class Job;
class Encoder;
+#include <libcxml/cxml.h>
#include "video_content.h"
#include "video_decoder.h"
int const VideoContentProperty::VIDEO_SIZE = 1;
int const VideoContentProperty::VIDEO_FRAME_RATE = 2;
+using std::string;
using boost::shared_ptr;
+using boost::lexical_cast;
VideoContent::VideoContent (boost::filesystem::path f)
: Content (f)
}
+VideoContent::VideoContent (shared_ptr<const cxml::Node> node)
+ : Content (node)
+{
+ _video_length = node->number_child<ContentVideoFrame> ("VideoLength");
+ _video_size.width = node->number_child<int> ("VideoWidth");
+ _video_size.height = node->number_child<int> ("VideoHeight");
+ _video_frame_rate = node->number_child<float> ("VideoFrameRate");
+}
+
+void
+VideoContent::as_xml (xmlpp::Node* node) const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+ node->add_child("VideoLength")->add_child_text (lexical_cast<string> (_video_length));
+ node->add_child("VideoWidth")->add_child_text (lexical_cast<string> (_video_size.width));
+ node->add_child("VideoHeight")->add_child_text (lexical_cast<string> (_video_size.height));
+ node->add_child("VideoFrameRate")->add_child_text (lexical_cast<string> (_video_frame_rate));
+}
+
void
VideoContent::take_from_video_decoder (shared_ptr<VideoDecoder> d)
{
{
public:
VideoContent (boost::filesystem::path);
+ VideoContent (boost::shared_ptr<const cxml::Node>);
+
+ void as_xml (xmlpp::Node *) const;
ContentVideoFrame video_length () const {
boost::mutex::scoped_lock lm (_mutex);
dcp_content_type.cc
dcp_video_frame.cc
decoder.cc
- decoder_factory.cc
delay_line.cc
dolby_cp750.cc
encoder.cc
obj.uselib = """
AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE
BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2
- SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP GLIB LZMA
+ SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP CXML GLIB LZMA
"""
if bld.env.TARGET_WINDOWS:
obj.uselib += ' WINSOCK2'
film->log()->set_level ((Log::Level) log_level);
cout << "\nMaking ";
- if (film->dcp_ab()) {
+ if (film->ab()) {
cout << "A/B ";
}
cout << "DCP for " << film->name() << "\n";
#include "exceptions.h"
#include "scaler.h"
#include "log.h"
-#include "decoder_factory.h"
#include "video_decoder.h"
+#include "playlist.h"
using std::cout;
using std::cerr;
server = new ServerDescription (server_host, 1);
shared_ptr<Film> film (new Film (film_dir, true));
- /* XXX */
-// opt.decode_audio = false;
-// opt.decode_subtitles = true;
-// opt.video_sync = true;
+ shared_ptr<Playlist> playlist = film->playlist ();
+ playlist->disable_audio ();
- Decoders decoders = decoder_factory (film);
try {
- decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3));
+ playlist->Video.connect (boost::bind (process_video, _1, _2, _3));
bool done = false;
while (!done) {
- done = decoders.video->pass ();
+ done = playlist->pass ();
}
} catch (std::exception& e) {
cerr << "Error: " << e.what() << "\n";
#include <boost/bind.hpp>
#include <wx/graphics.h>
#include "audio_plot.h"
-#include "lib/decoder_factory.h"
#include "lib/audio_decoder.h"
#include "lib/audio_analysis.h"
#include "wx/wx_util.h"
}
++r;
- _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B"));
- grid->Add (_dcp_ab, wxGBPosition (r, 0));
+ _ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B"));
+ grid->Add (_ab, wxGBPosition (r, 0));
++r;
vector<DCPContentType const *> const ct = DCPContentType::all ();
_dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this);
_best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this);
- _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this);
+ _ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::ab_toggled), 0, this);
_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this);
_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this);
_with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
/** Called when the DCP A/B switch has been toggled */
void
-FilmEditor::dcp_ab_toggled (wxCommandEvent &)
+FilmEditor::ab_toggled (wxCommandEvent &)
{
if (!_film) {
return;
}
- _film->set_dcp_ab (_dcp_ab->GetValue ());
+ _film->set_ab (_ab->GetValue ());
}
/** Called when the name widget has been changed */
checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
setup_dcp_name ();
break;
- case Film::DCP_AB:
- checked_set (_dcp_ab, _film->dcp_ab ());
+ case Film::AB:
+ checked_set (_ab, _film->ab ());
break;
case Film::SCALER:
checked_set (_scaler, Scaler::as_index (_film->scaler ()));
film_changed (Film::SCALER);
film_changed (Film::TRIM_START);
film_changed (Film::TRIM_END);
- film_changed (Film::DCP_AB);
+ film_changed (Film::AB);
film_changed (Film::AUDIO_GAIN);
film_changed (Film::AUDIO_DELAY);
film_changed (Film::WITH_SUBTITLES);
_dcp_frame_rate->Enable (s);
_trim_start->Enable (s);
_trim_end->Enable (s);
- _dcp_ab->Enable (s);
+ _ab->Enable (s);
_colour_lut->Enable (s);
_j2k_bandwidth->Enable (s);
_audio_gain->Enable (s);
void trim_start_changed (wxCommandEvent &);
void trim_end_changed (wxCommandEvent &);
void dcp_content_type_changed (wxCommandEvent &);
- void dcp_ab_toggled (wxCommandEvent &);
+ void ab_toggled (wxCommandEvent &);
void scaler_changed (wxCommandEvent &);
void audio_gain_changed (wxCommandEvent &);
void audio_gain_calculate_button_clicked (wxCommandEvent &);
wxSpinCtrl* _trim_start;
wxSpinCtrl* _trim_end;
/** Selector to generate an A/B comparison DCP */
- wxCheckBox* _dcp_ab;
+ wxCheckBox* _ab;
std::vector<Format const *> _formats;
#include <wx/wx.h>
#include "lib/film.h"
-#include "lib/decoder_factory.h"
class wxToggleButton;
class FFmpegPlayer;
f->set_filters (f_filters);
f->set_trim_start (42);
f->set_trim_end (99);
- f->set_dcp_ab (true);
+ f->set_ab (true);
f->write_metadata ();
stringstream s;
BOOST_CHECK_EQUAL (g_filters.back(), Filter::from_id ("unsharp"));
BOOST_CHECK_EQUAL (g->trim_start(), 42);
BOOST_CHECK_EQUAL (g->trim_end(), 99);
- BOOST_CHECK_EQUAL (g->dcp_ab(), true);
+ BOOST_CHECK_EQUAL (g->ab(), true);
g->write_metadata ();
BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0);