Skip every other frame with 50fps sources.
authorCarl Hetherington <cth@carlh.net>
Sun, 4 Nov 2012 13:41:43 +0000 (13:41 +0000)
committerCarl Hetherington <cth@carlh.net>
Sun, 4 Nov 2012 13:41:43 +0000 (13:41 +0000)
src/lib/check_hashes_job.cc
src/lib/dcp_video_frame.cc
src/lib/decoder.cc
src/lib/examine_content_job.cc
src/lib/film.cc
src/lib/make_dcp_job.cc
src/lib/options.h
src/lib/tiff_decoder.cc
src/lib/util.cc
src/lib/util.h

index a9f8ac90b0633c54cc4401b7afe29e19574f6375..d1483933d3e0172707cf20772f3defe9781855dc 100644 (file)
@@ -58,8 +58,9 @@ CheckHashesJob::run ()
        }
        
        int const N = _film->dcp_length().get();
+       DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ());
        
-       for (int i = 0; i < N; ++i) {
+       for (int i = 0; i < N; i += dfr.skip) {
                string const j2k_file = _opt->frame_out_path (i, false);
                string const hash_file = j2k_file + ".md5";
 
index 9d6022efa52ca8cb6866c1538f9b387198d33550..1dcc81f0de980a6954c7add6394e0f4f001be6d2 100644 (file)
@@ -86,8 +86,7 @@ DCPVideoFrame::DCPVideoFrame (
        , _subtitle_scale (subtitle_scale)
        , _scaler (s)
        , _frame (f)
-         /* we round here; not sure if this is right */
-       , _frames_per_second (rint (fps))
+       , _frames_per_second (dcp_frame_rate(fps).frames_per_second)
        , _post_process (pp)
        , _colour_lut_index (clut)
        , _j2k_bandwidth (bw)
index 6f5d63358641d803a73ea31021d846ebe4c5a4c4..3feaf43e9784cf19cffd3a840386fbafe26c75fe 100644 (file)
@@ -61,9 +61,7 @@ Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o,
        , _delay_in_bytes (0)
        , _audio_frames_processed (0)
 {
-       if (_opt->decode_video_frequency != 0 && !_film->length()) {
-               throw DecodeError ("cannot do a partial decode if length is unknown");
-       }
+       
 }
 
 Decoder::~Decoder ()
@@ -101,7 +99,7 @@ Decoder::process_end ()
        int64_t const audio_short_by_frames = video_length_in_audio_frames - _audio_frames_processed;
 
        _film->log()->log (
-               String::compose ("DCP length is %1 (%2 audio frames); %3 frames of audio processed.",
+               String::compose ("Source length is %1 (%2 audio frames); %3 frames of audio processed.",
                                 video_frame_index(),
                                 video_length_in_audio_frames,
                                 _audio_frames_processed)
@@ -109,7 +107,7 @@ Decoder::process_end ()
        
        if (audio_short_by_frames >= 0 && _opt->decode_audio) {
 
-               _film->log()->log (String::compose ("DCP length is %1; %2 frames of audio processed.", video_frame_index(), _audio_frames_processed));
+               _film->log()->log (String::compose ("Source length is %1; %2 frames of audio processed.", video_frame_index(), _audio_frames_processed));
                _film->log()->log (String::compose ("Adding %1 frames of silence to the end.", audio_short_by_frames));
 
                /* XXX: this is slightly questionable; does memset () give silence with all
@@ -272,12 +270,7 @@ Decoder::process_video (AVFrame* frame)
 
        /* Use Film::length here as our one may be wrong */
 
-       int gap = 0;
-       if (_opt->decode_video_frequency != 0) {
-               gap = _film->length().get() / _opt->decode_video_frequency;
-       }
-
-       if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame_index % gap) != 0) {
+       if (_opt->decode_video_skip != 0 && (_video_frame_index % _opt->decode_video_skip) != 0) {
                ++_video_frame_index;
                return;
        }
index 943e9fbf7dfa2a33c7a27b6800a789676139d69c..6d1233a8cdd70133e2856d1de0d22326d0bec843 100644 (file)
@@ -84,7 +84,11 @@ ExamineContentJob::run ()
                o->out_size = _film->size ();
                o->apply_crop = false;
                o->decode_audio = false;
-               o->decode_video_frequency = 128;
+               if (_film->length() > 0) {
+                       o->decode_video_skip = _film->length().get() / 128;
+               } else {
+                       o->decode_video_skip = 0;
+               }
                o->decode_subtitles = true;
                shared_ptr<ImageMagickEncoder> e (new ImageMagickEncoder (_film, o));
                Transcoder w (_film, o, this, e);
index 9c351a64df9f344090088da2f4038cc31f9f27fc..d29c044657ccbe33bd1b419b3578eda657f8a0a8 100644 (file)
@@ -272,6 +272,7 @@ Film::make_dcp (bool transcode)
        o->padding = format()->dcp_padding (shared_from_this ());
        o->ratio = format()->ratio_as_float (shared_from_this ());
        o->decode_subtitles = with_subtitles ();
+       o->decode_video_skip = dcp_frame_rate (frames_per_second()).skip;
 
        shared_ptr<Job> r;
 
@@ -716,11 +717,13 @@ Film::target_audio_sample_rate () const
        /* Resample to a DCI-approved sample rate */
        double t = dcp_audio_sample_rate (audio_sample_rate());
 
+       DCPFrameRate dfr = dcp_frame_rate (frames_per_second ());
+
        /* 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());
+       if (dfr.run_fast) {
+               t *= _frames_per_second * dfr.skip / dfr.frames_per_second;
        }
 
        return rint (t);
index bf01119e4995d9bb520adc30348cea9765e5dfdd..4102f838401d9f5f35fc8aa977ab9355694dfeba 100644 (file)
@@ -58,7 +58,7 @@ MakeDCPJob::name () const
 string
 MakeDCPJob::j2c_path (int f) const
 {
-       return _opt->frame_out_path (f, false);
+       return _opt->frame_out_path (f * dcp_frame_rate(_film->frames_per_second()).skip, false);
 }
 
 string
@@ -79,21 +79,23 @@ MakeDCPJob::run ()
        /* Remove any old DCP */
        boost::filesystem::remove_all (dcp_path);
 
+       DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ());
+
        int frames = 0;
        switch (_film->content_type ()) {
        case VIDEO:
-               frames = _film->dcp_length().get();
+               frames = _film->dcp_length().get() / dfr.skip;
                break;
        case STILL:
                frames = _film->still_duration() * ImageMagickDecoder::static_frames_per_second ();
                break;
        }
-       
+
        libdcp::DCP dcp (_film->dir (_film->dcp_name()));
        dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1));
 
        shared_ptr<libdcp::CPL> cpl (
-               new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, rint (_film->frames_per_second()))
+               new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second)
                );
        
        dcp.add_cpl (cpl);
@@ -105,7 +107,7 @@ MakeDCPJob::run ()
                        _film->dir (_film->dcp_name()),
                        "video.mxf",
                        &dcp.Progress,
-                       rint (_film->frames_per_second()),
+                       dfr.frames_per_second,
                        frames,
                        _opt->out_size.width,
                        _opt->out_size.height
@@ -124,7 +126,7 @@ MakeDCPJob::run ()
                                _film->dir (_film->dcp_name()),
                                "audio.mxf",
                                &dcp.Progress,
-                               rint (_film->frames_per_second()),
+                               dfr.frames_per_second,
                                frames,
                                _film->audio_channels()
                                )
index 86db35210a377cad8f3a0caa08059214f467751d..f4381ef684de4798a2e0e68e6c6f56a6dce78ba2 100644 (file)
@@ -40,7 +40,7 @@ public:
                : padding (0)
                , apply_crop (true)
                , black_after (0)
-               , decode_video_frequency (0)
+               , decode_video_skip (0)
                , decode_audio (true)
                , decode_subtitles (false)
                , _frame_out_path (f)
@@ -98,7 +98,8 @@ public:
        int padding;                ///< number of pixels of padding (in terms of the output size) each side of the image
        bool apply_crop;            ///< true to apply cropping
        int black_after;            ///< first frame for which to output a black frame, rather than the actual video content, or 0 for none
-       int decode_video_frequency; ///< skip frames so that this many are decoded in all (or 0) (for generating thumbnails)
+       int decode_video_skip;      ///< skip frames such that we don't decode any frame where (index % decode_video_skip) != 0; e.g.
+                                   ///< 1 for every frame, 2 for every other frame, etc.
        bool decode_audio;          ///< true to decode audio, otherwise false
        bool decode_subtitles;
 
index 9058fcc2a5ba6ab82c8b94081c9f60e2b3517fa4..1500b9b48a5962ca018e84e639cd108e1fd931a4 100644 (file)
@@ -198,7 +198,7 @@ TIFFDecoder::pixel_format () const
 int
 TIFFDecoder::time_base_numerator () const
 {
-       return rint (_film->frames_per_second());
+       return dcp_frame_rate(_film->frames_per_second()).frames_per_second;
 }
 
 
index b68f7e392f4597675b5252e755f8247c8fdc6db0..d89ebd0d51cc9fc6cf916e66e924f961c548d292 100644 (file)
@@ -374,6 +374,24 @@ md5_digest (string file)
        return s.str ();
 }
 
+DCPFrameRate
+dcp_frame_rate (float fps)
+{
+       DCPFrameRate dfr;
+
+       dfr.run_fast = (fps != rint (fps));
+       dfr.frames_per_second = rint (fps);
+       dfr.skip = 1;
+
+       /* XXX: somewhat arbitrary */
+       if (fps == 50) {
+               dfr.frames_per_second = 25;
+               dfr.skip = 2;
+       }
+
+       return dfr;
+}
+
 /** @param An arbitrary sampling rate.
  *  @return The appropriate DCP-approved sampling rate (48kHz or 96kHz).
  */
index 1af6500856770d33796a462e91f337b404210e9d..26c6ed9faba6d940e32b279474435d4cd69d0aa3 100644 (file)
@@ -54,6 +54,13 @@ extern std::string md5_digest (std::string);
 extern std::string md5_digest (void const *, int);
 extern void ensure_ui_thread ();
 
+struct DCPFrameRate
+{
+       int frames_per_second;
+       int skip;
+       bool run_fast;
+};
+
 enum ContentType {
        STILL,
        VIDEO
@@ -157,6 +164,7 @@ struct Rect
 
 extern std::string crop_string (Position, Size);
 extern int dcp_audio_sample_rate (int);
+extern DCPFrameRate dcp_frame_rate (float);
 extern std::string colour_lut_index_to_name (int index);
 extern int round_up (int, int);
 extern std::multimap<std::string, std::string> read_key_value (std::istream& s);