+/** @param n A thumb index.
+ * @return The path to the thumb's image file.
+ */
+string
+Film::thumb_file (int n) const
+{
+ return thumb_file_for_frame (thumb_frame (n));
+}
+
+/** @param n A frame index within the Film.
+ * @return The path to the thumb's image file for this frame;
+ * we assume that it exists.
+ */
+string
+Film::thumb_file_for_frame (int n) const
+{
+ return thumb_base_for_frame(n) + ".png";
+}
+
+string
+Film::thumb_base (int n) const
+{
+ return thumb_base_for_frame (thumb_frame (n));
+}
+
+string
+Film::thumb_base_for_frame (int n) const
+{
+ stringstream s;
+ s.width (8);
+ s << setfill('0') << n;
+
+ filesystem::path p;
+ p /= dir ("thumbs");
+ p /= s.str ();
+
+ return p.string ();
+}
+
+
+/** @param n A thumb index.
+ * @return The frame within the Film that it is for.
+ */
+int
+Film::thumb_frame (int n) const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ assert (n < int (_thumbs.size ()));
+ return _thumbs[n];
+}
+
+Size
+Film::cropped_size (Size s) const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ s.width -= _crop.left + _crop.right;
+ s.height -= _crop.top + _crop.bottom;
+ return s;
+}
+
+/** Given a directory name, return its full path within the Film's directory.
+ * The directory (and its parents) will be created if they do not exist.
+ */
+string
+Film::dir (string d) const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ 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
+Film::file (string f) const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return file_locked (f);
+}
+
+string
+Film::file_locked (string f) const
+{
+ filesystem::path p;
+ p /= _directory;
+ p /= f;
+ return p.string ();
+}
+
+/** @return full path of the content (actual video) file
+ * of the Film.
+ */
+string
+Film::content_path () const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ if (filesystem::path(_content).has_root_directory ()) {
+ return _content;
+ }
+
+ return file_locked (_content);
+}
+
+ContentType
+Film::content_type () const
+{
+#if BOOST_FILESYSTEM_VERSION == 3
+ string ext = filesystem::path(_content).extension().string();
+#else
+ 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 The sampling rate that we will resample the audio to */
+int
+Film::target_audio_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
+Film::dcp_length () const
+{
+ if (dcp_frames()) {
+ return dcp_frames();
+ }
+
+ return length();
+}
+
+/** @return a DCI-compliant name for a DCP of this film */
+string
+Film::dci_name () const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+
+ 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 (!_subtitle_language.empty() && _with_subtitles) {
+ d << "-" << _subtitle_language;
+ } else {
+ d << "-XX";
+ }
+
+ d << "_";
+ }
+
+ if (!_territory.empty ()) {
+ d << _territory;
+ if (!_rating.empty ()) {
+ d << "-" << _rating;
+ }
+ d << "_";
+ }
+
+ switch (_audio_streams[_audio_stream].channels()) {
+ case 1:
+ d << "10_";
+ break;
+ case 2:
+ d << "20_";
+ break;
+ case 6:
+ d << "51_";
+ break;
+ case 8:
+ d << "71_";
+ 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
+Film::dcp_name () const
+{
+ if (use_dci_name()) {
+ return dci_name ();
+ }
+
+ return name();
+}
+
+
+void
+Film::set_directory (string d)
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _directory = d;
+ _dirty = true;
+}
+