#include <iomanip>
#include <sstream>
#include <boost/filesystem.hpp>
+#include <boost/date_time.hpp>
#include "film_state.h"
#include "scaler.h"
#include "filter.h"
#include "format.h"
#include "dcp_content_type.h"
#include "util.h"
+#include "exceptions.h"
using namespace std;
using namespace boost;
{
/* User stuff */
f << "name " << name << "\n";
+ f << "use_dci_name " << use_dci_name << "\n";
f << "content " << content << "\n";
if (dcp_content_type) {
f << "dcp_content_type " << dcp_content_type->pretty_name () << "\n";
if (format) {
f << "format " << format->as_metadata () << "\n";
}
- f << "left_crop " << left_crop << "\n";
- f << "right_crop " << right_crop << "\n";
- f << "top_crop " << top_crop << "\n";
- f << "bottom_crop " << bottom_crop << "\n";
+ f << "left_crop " << crop.left << "\n";
+ f << "right_crop " << crop.right << "\n";
+ f << "top_crop " << crop.top << "\n";
+ f << "bottom_crop " << crop.bottom << "\n";
for (vector<Filter const *>::const_iterator i = filters.begin(); i != filters.end(); ++i) {
f << "filter " << (*i)->id () << "\n";
}
}
f << "dcp_ab " << (dcp_ab ? "1" : "0") << "\n";
+ f << "selected_audio_stream " << audio_stream << "\n";
f << "audio_gain " << audio_gain << "\n";
f << "audio_delay " << audio_delay << "\n";
f << "still_duration " << still_duration << "\n";
+ f << "with_subtitles " << with_subtitles << "\n";
+ f << "subtitle_offset " << subtitle_offset << "\n";
+ f << "subtitle_scale " << subtitle_scale << "\n";
+ f << "audio_language " << audio_language << "\n";
+ f << "subtitle_language " << subtitle_language << "\n";
+ f << "territory " << territory << "\n";
+ f << "rating " << rating << "\n";
+ f << "studio " << studio << "\n";
+ f << "facility " << facility << "\n";
+ f << "package_type " << package_type << "\n";
/* Cached stuff; this is information about our content; we could
look it up each time, but that's slow.
f << "audio_channels " << audio_channels << "\n";
f << "audio_sample_rate " << audio_sample_rate << "\n";
f << "audio_sample_format " << audio_sample_format_to_string (audio_sample_format) << "\n";
+ f << "content_digest " << content_digest << "\n";
+ f << "selected_subtitle_stream " << subtitle_stream << "\n";
+ f << "has_subtitles " << has_subtitles << "\n";
+
+ for (vector<Stream>::const_iterator i = audio_streams.begin(); i != audio_streams.end(); ++i) {
+ f << "audio_stream " << i->to_string () << "\n";
+ }
+
+ for (vector<Stream>::const_iterator i = subtitle_streams.begin(); i != subtitle_streams.end(); ++i) {
+ f << "subtitle_stream " << i->to_string () << "\n";
+ }
}
/** Read state from a key / value pair.
/* 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 == "dcp_content_type") {
} else if (k == "format") {
format = Format::from_metadata (v);
} else if (k == "left_crop") {
- left_crop = atoi (v.c_str ());
+ crop.left = atoi (v.c_str ());
} else if (k == "right_crop") {
- right_crop = atoi (v.c_str ());
+ crop.right = atoi (v.c_str ());
} else if (k == "top_crop") {
- top_crop = atoi (v.c_str ());
+ crop.top = atoi (v.c_str ());
} else if (k == "bottom_crop") {
- bottom_crop = atoi (v.c_str ());
+ crop.bottom = atoi (v.c_str ());
} else if (k == "filter") {
filters.push_back (Filter::from_id (v));
} else if (k == "scaler") {
}
} else if (k == "dcp_ab") {
dcp_ab = (v == "1");
+ } else if (k == "selected_audio_stream") {
+ audio_stream = atoi (v.c_str ());
} 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 == "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 == "selected_subtitle_stream") {
+ subtitle_stream = atoi (v.c_str ());
+ } else if (k == "audio_language") {
+ audio_language = v;
+ } else if (k == "subtitle_language") {
+ subtitle_language = v;
+ } else if (k == "territory") {
+ territory = v;
+ } else if (k == "rating") {
+ rating = v;
+ } else if (k == "studio") {
+ studio = v;
+ } else if (k == "facility") {
+ facility = v;
+ } else if (k == "package_type") {
+ package_type = v;
}
/* Cached stuff */
audio_sample_rate = atoi (v.c_str ());
} else if (k == "audio_sample_format") {
audio_sample_format = audio_sample_format_from_string (v);
+ } else if (k == "content_digest") {
+ content_digest = v;
+ } else if (k == "has_subtitles") {
+ has_subtitles = (v == "1");
+ } else if (k == "audio_stream") {
+ audio_streams.push_back (Stream (v));
+ } else if (k == "subtitle_stream") {
+ subtitle_streams.push_back (Stream (v));
}
}
*/
string
FilmState::thumb_file_for_frame (int n) const
+{
+ return thumb_base_for_frame(n) + ".png";
+}
+
+string
+FilmState::thumb_base (int n) const
+{
+ return thumb_base_for_frame (thumb_frame (n));
+}
+
+string
+FilmState::thumb_base_for_frame (int n) const
{
stringstream s;
- s << dir ("thumbs") << "/";
s.width (8);
- s << setfill('0') << n << ".tiff";
- return s.str ();
+ s << setfill('0') << n;
+
+ filesystem::path p;
+ p /= dir ("thumbs");
+ p /= s.str ();
+
+ return p.string ();
}
Size
FilmState::cropped_size (Size s) const
{
- s.width -= left_crop + right_crop;
- s.height -= top_crop + bottom_crop;
+ s.width -= crop.left + crop.right;
+ s.height -= crop.top + crop.bottom;
return s;
}
string
FilmState::dir (string d) const
{
- stringstream s;
- s << directory << "/" << d;
- filesystem::create_directories (s.str ());
- return s.str ();
+ filesystem::path p;
+ p /= directory;
+ p /= d;
+ filesystem::create_directories (p);
+ return p.string ();
}
/** Given a file or directory name, return its full path within the Film's directory */
string
FilmState::file (string f) const
{
- stringstream s;
- s << directory << "/" << f;
- return s.str ();
+ filesystem::path p;
+ p /= directory;
+ p /= f;
+ return p.string ();
}
string
FilmState::content_type () const
{
#if BOOST_FILESYSTEM_VERSION == 3
- string const ext = filesystem::path(content).extension().string();
+ string ext = filesystem::path(content).extension().string();
#else
- string const ext = filesystem::path(content).extension();
+ string ext = filesystem::path(content).extension();
#endif
+
+ transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
+
if (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png") {
return STILL;
}
return VIDEO;
}
+
+/** @return Number of bytes per sample of a single channel */
+int
+FilmState::bytes_per_sample () const
+{
+ switch (audio_sample_format) {
+ case AV_SAMPLE_FMT_S16:
+ return 2;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+int
+FilmState::target_sample_rate () const
+{
+ /* Resample to a DCI-approved sample rate */
+ double t = dcp_audio_sample_rate (audio_sample_rate);
+
+ /* Compensate for the fact that video will be rounded to the
+ nearest integer number of frames per second.
+ */
+ if (rint (frames_per_second) != frames_per_second) {
+ t *= frames_per_second / rint (frames_per_second);
+ }
+
+ return rint (t);
+}
+
+int
+FilmState::dcp_length () const
+{
+ if (dcp_frames) {
+ return dcp_frames;
+ }
+
+ return length;
+}
+
+/** @return a DCI-compliant name for a DCP of this film */
+string
+FilmState::dci_name () const
+{
+ stringstream d;
+
+ string fixed_name = to_upper_copy (name);
+ for (size_t i = 0; i < fixed_name.length(); ++i) {
+ if (fixed_name[i] == ' ') {
+ fixed_name[i] = '-';
+ }
+ }
+
+ /* Spec is that the name part should be maximum 14 characters, as I understand it */
+ if (fixed_name.length() > 14) {
+ fixed_name = fixed_name.substr (0, 14);
+ }
+
+ d << fixed_name << "_";
+
+ if (dcp_content_type) {
+ d << dcp_content_type->dci_name() << "_";
+ }
+
+ if (format) {
+ d << format->dci_name() << "_";
+ }
+
+ if (!audio_language.empty ()) {
+ d << audio_language;
+ if (with_subtitles) {
+ if (!subtitle_language.empty ()) {
+ d << "-" << subtitle_language;
+ } else {
+ d << "-XX";
+ }
+ }
+
+ d << "_";
+ }
+
+ if (!territory.empty ()) {
+ d << territory;
+ if (!rating.empty ()) {
+ d << "-" << rating;
+ }
+ d << "_";
+ }
+
+ switch (audio_channels) {
+ case 1:
+ d << "10_";
+ break;
+ case 2:
+ d << "20_";
+ break;
+ case 6:
+ d << "51_";
+ break;
+ }
+
+ d << "2K_";
+
+ if (!studio.empty ()) {
+ d << studio << "_";
+ }
+
+ gregorian::date today = gregorian::day_clock::local_day ();
+ d << gregorian::to_iso_string (today) << "_";
+
+ if (!facility.empty ()) {
+ d << facility << "_";
+ }
+
+ if (!package_type.empty ()) {
+ d << package_type;
+ }
+
+ return d.str ();
+}
+
+/** @return name to give the DCP */
+string
+FilmState::dcp_name () const
+{
+ if (use_dci_name) {
+ return dci_name ();
+ }
+
+ return name;
+}
+
+