/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 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
*/
-#include <stdexcept>
-#include <iostream>
-#include <algorithm>
-#include <fstream>
-#include <cstdlib>
-#include <sstream>
-#include <iomanip>
-#include <unistd.h>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/lexical_cast.hpp>
-#include <libxml++/libxml++.h>
-#include <libcxml/cxml.h>
-#include <dcp/signer_chain.h>
-#include <dcp/cpl.h>
-#include <dcp/signer.h>
-#include <dcp/util.h>
-#include <dcp/local_time.h>
-#include <dcp/raw_convert.h>
+/** @file src/film.cc
+ * @brief A representation of some audio and video content, and details of
+ * how they should be presented in a DCP.
+ */
+
#include "film.h"
#include "job.h"
#include "util.h"
#include "examine_content_job.h"
#include "scaler.h"
#include "config.h"
-#include "version.h"
#include "ui_signaller.h"
#include "playlist.h"
#include "player.h"
#include "ratio.h"
#include "cross.h"
#include "cinema.h"
+#include "safe_stringstream.h"
+#include "environment_info.h"
+#include <libcxml/cxml.h>
+#include <dcp/cpl.h>
+#include <dcp/signer.h>
+#include <dcp/util.h>
+#include <dcp/local_time.h>
+#include <dcp/raw_convert.h>
+#include <dcp/decrypted_kdm.h>
+#include <libxml++/libxml++.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+#include <unistd.h>
+#include <stdexcept>
+#include <iostream>
+#include <algorithm>
+#include <fstream>
+#include <cstdlib>
+#include <iomanip>
+#include <set>
#include "i18n.h"
using std::string;
-using std::stringstream;
using std::multimap;
using std::pair;
using std::map;
using std::endl;
using std::cout;
using std::list;
+using std::set;
using boost::shared_ptr;
using boost::weak_ptr;
using boost::dynamic_pointer_cast;
* Use <Scale> tag in <VideoContent> rather than <Ratio>.
* 8 -> 9
* DCI -> ISDCF
+ * 9 -> 10
+ * Subtitle X and Y scale.
*
* Bumped to 32 for 2.0 branch; some times are expressed in Times rather
* than frames now.
}
}
- set_directory (result);
+ set_directory (result.make_preferred ());
if (log) {
_log.reset (new FileLog (file ("log")));
} else {
string
Film::video_identifier () const
{
- assert (container ());
+ DCPOMATIC_ASSERT (container ());
- stringstream s;
+ SafeStringStream s;
s.imbue (std::locale::classic ());
s << container()->id()
throw BadSettingError (_("name"), _("cannot contain slashes"));
}
- /* It seems to make sense to auto-save metadata here, since the make DCP may last
- a long time, and crashes/power failures are moderately likely.
- */
- write_metadata ();
-
- LOG_GENERAL ("DCP-o-matic %1 git %2 using %3", dcpomatic_version, dcpomatic_git_commit, dependency_version_summary());
-
- {
- char buffer[128];
- gethostname (buffer, sizeof (buffer));
- LOG_GENERAL ("Starting to make DCP on %1", buffer);
- }
+ environment_info (log ());
ContentList cl = content ();
for (ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
LOG_GENERAL ("DCP video rate %1 fps", video_frame_rate());
LOG_GENERAL ("%1 threads", Config::instance()->num_local_encoding_threads());
LOG_GENERAL ("J2K bandwidth %1", j2k_bandwidth());
-#ifdef DCPOMATIC_DEBUG
- LOG_GENERAL_NC ("DCP-o-matic built in debug mode.");
-#else
- LOG_GENERAL_NC ("DCP-o-matic built in optimised mode.");
-#endif
-#ifdef LIBDCP_DEBUG
- LOG_GENERAL_NC ("libdcp built in debug mode.");
-#else
- LOG_GENERAL_NC ("libdcp built in optimised mode.");
-#endif
-
-#ifdef DCPOMATIC_WINDOWS
- OSVERSIONINFO info;
- info.dwOSVersionInfoSize = sizeof (info);
- GetVersionEx (&info);
- LOG_GENERAL ("Windows version %1.%2.%3 SP %4", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber, info.szCSDVersion);
-#endif
-
- LOG_GENERAL ("CPU: %1, %2 processors", cpu_info(), boost::thread::hardware_concurrency ());
- list<pair<string, string> > const m = mount_info ();
- for (list<pair<string, string> >::const_iterator i = m.begin(); i != m.end(); ++i) {
- LOG_GENERAL ("Mount: %1 %2", i->first, i->second);
- }
if (container() == 0) {
throw MissingSettingError (_("container"));
/* This method is the only one that can return notes (so far) */
_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"));
+
_dirty = false;
return notes;
}
string
Film::isdcf_name (bool if_created_now) const
{
- stringstream d;
+ SafeStringStream d;
string raw_name = name ();
d << "_" << container()->isdcf_name();
}
- /* XXX: this only works for content which has been scaled to a given ratio,
- and uses the first bit of content only.
- */
+ /* XXX: this uses the first bit of content only */
/* The standard says we don't do this for trailers, for some strange reason */
if (dcp_content_type() && dcp_content_type()->libdcp_kind() != dcp::TRAILER) {
ContentList cl = content ();
Ratio const * content_ratio = 0;
- for (ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
+ for (ContentList::iterator i = cl.begin(); i != cl.end(); ++i) {
shared_ptr<VideoContent> vc = dynamic_pointer_cast<VideoContent> (*i);
- if (vc && (content_ratio == 0 || vc->scale().ratio() != content_ratio)) {
- content_ratio = vc->scale().ratio();
+ if (vc) {
+ /* Here's the first piece of video content */
+ if (vc->scale().ratio ()) {
+ content_ratio = vc->scale().ratio ();
+ } else {
+ content_ratio = Ratio::from_ratio (vc->video_size().ratio ());
+ }
+ break;
}
}
boost::filesystem::path p;
p /= info_dir ();
- stringstream s;
+ SafeStringStream s;
s.width (8);
s << setfill('0') << f;
p /= "j2c";
p /= video_identifier ();
- stringstream s;
+ SafeStringStream s;
s.width (8);
s << setfill('0') << f;
return _playlist->content ();
}
+void
+Film::examine_content (shared_ptr<Content> c)
+{
+ shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c));
+ JobManager::instance()->add (j);
+}
+
void
Film::examine_and_add_content (shared_ptr<Content> c)
{
return dcp::Size (4096, 2160);
}
- assert (false);
+ DCPOMATIC_ASSERT (false);
return dcp::Size ();
}
dcp::Size
Film::frame_size () const
{
- return fit_ratio_within (container()->ratio(), full_frame ());
+ return fit_ratio_within (container()->ratio(), full_frame (), 1);
}
dcp::EncryptedKDM
Film::make_kdm (
- shared_ptr<dcp::Certificate> target,
+ dcp::Certificate target,
boost::filesystem::path cpl_file,
dcp::LocalTime from,
dcp::LocalTime until,
) const
{
shared_ptr<const dcp::CPL> cpl (new dcp::CPL (cpl_file));
+ shared_ptr<const dcp::Signer> signer = Config::instance()->signer();
+ if (!signer->valid ()) {
+ throw InvalidSignerError ();
+ }
+
return dcp::DecryptedKDM (
- cpl, from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string()
- ).encrypt (make_signer(), target, formulation);
+ cpl, key(), from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string()
+ ).encrypt (signer, target, formulation);
}
list<dcp::EncryptedKDM>
list<dcp::EncryptedKDM> kdms;
for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
- kdms.push_back (make_kdm ((*i)->certificate, dcp, from, until, formulation));
+ if ((*i)->certificate) {
+ kdms.push_back (make_kdm ((*i)->certificate.get(), dcp, from, until, formulation));
+ }
}
return kdms;
available = double (s.available) / 1073741824.0f;
return (available - required) > 1;
}
+
+string
+Film::subtitle_language () const
+{
+ set<string> languages;
+
+ ContentList cl = content ();
+ BOOST_FOREACH (shared_ptr<Content>& c, cl) {
+ shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (c);
+ if (sc) {
+ languages.insert (sc->subtitle_language ());
+ }
+ }
+
+ string all;
+ BOOST_FOREACH (string s, languages) {
+ if (!all.empty ()) {
+ all += "/" + s;
+ } else {
+ all += s;
+ }
+ }
+
+ return all;
+}