Various fixes to resampling.
[dcpomatic.git] / src / lib / film_state.cc
index 16378086c1fcd878e4781ff73192da02b33634cf..0c1ac87dc76d28f6470fd624300d15d6c8db8a60 100644 (file)
@@ -35,6 +35,7 @@
 #include "format.h"
 #include "dcp_content_type.h"
 #include "util.h"
+#include "exceptions.h"
 
 using namespace std;
 using namespace boost;
@@ -55,10 +56,10 @@ FilmState::write_metadata (ofstream& f) const
        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";
        }
@@ -92,6 +93,7 @@ FilmState::write_metadata (ofstream& f) const
        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";
 }
 
 /** Read state from a key / value pair.
@@ -113,13 +115,13 @@ FilmState::read_metadata (string k, string v)
        } 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") {
@@ -161,6 +163,8 @@ FilmState::read_metadata (string k, string v)
                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;
        }
 }
 
@@ -182,10 +186,14 @@ string
 FilmState::thumb_file_for_frame (int n) const
 {
        stringstream s;
-       s << dir ("thumbs") << "/";
        s.width (8);
        s << setfill('0') << n << ".tiff";
-       return s.str ();
+       
+       filesystem::path p;
+       p /= dir ("thumbs");
+       p /= s.str ();
+               
+       return p.string ();
 }
 
 
@@ -202,8 +210,8 @@ FilmState::thumb_frame (int n) const
 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;
 }
 
@@ -213,19 +221,21 @@ FilmState::cropped_size (Size s) const
 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
@@ -242,13 +252,50 @@ ContentType
 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
+{
+       double t = dcp_audio_sample_rate (audio_sample_rate);
+       if (rint (frames_per_second) != frames_per_second) {
+               if (fabs (frames_per_second - 23.976) < 1e-6) {
+                       /* 24fps drop-frame ie 24 * 1000 / 1001 frames per second;
+                          hence we need to resample the audio to dcp_audio_sample_rate * 1000 / 1001
+                          so that when we play it back at dcp_audio_sample_rate it is sped up
+                          by the same amount that the video is
+                       */
+                       t *= double(1000) / 1001;
+               } else {
+                       throw EncodeError ("unknown fractional frame rate");
+               }
+       }
+
+       return rint (t);
+}