Try to clean up source length handling.
authorCarl Hetherington <cth@carlh.net>
Wed, 24 Oct 2012 22:27:23 +0000 (23:27 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 24 Oct 2012 22:27:23 +0000 (23:27 +0100)
src/lib/check_hashes_job.cc
src/lib/decoder.cc
src/lib/film.cc
src/lib/film.h
src/lib/make_dcp_job.cc
src/lib/transcode_job.cc
src/wx/dcp_range_dialog.cc
src/wx/film_editor.cc
src/wx/properties_dialog.cc

index 88233ab665805c34b60328895375ba3a67c1ae5c..a9f8ac90b0633c54cc4401b7afe29e19574f6375 100644 (file)
@@ -27,6 +27,7 @@
 #include "ab_transcode_job.h"
 #include "transcode_job.h"
 #include "film.h"
 #include "ab_transcode_job.h"
 #include "transcode_job.h"
 #include "film.h"
+#include "exceptions.h"
 
 using std::string;
 using std::stringstream;
 
 using std::string;
 using std::stringstream;
@@ -52,7 +53,11 @@ CheckHashesJob::run ()
 {
        _bad = 0;
 
 {
        _bad = 0;
 
-       int const N = _film->dcp_length ();
+       if (!_film->dcp_length()) {
+               throw EncodeError ("cannot check hashes of a DCP with unknown length");
+       }
+       
+       int const N = _film->dcp_length().get();
        
        for (int i = 0; i < N; ++i) {
                string const j2k_file = _opt->frame_out_path (i, false);
        
        for (int i = 0; i < N; ++i) {
                string const j2k_file = _opt->frame_out_path (i, false);
@@ -78,7 +83,7 @@ CheckHashesJob::run ()
                        }
                }
 
                        }
                }
 
-               set_progress (float (i) / _film->length());
+               set_progress (float (i) / N);
        }
 
        if (_bad) {
        }
 
        if (_bad) {
index a786520106964dcd1bf8c4a9bbc2717b55f70894..eee288341d728fdc04d72d41157de1563381171a 100644 (file)
@@ -75,8 +75,8 @@ Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o,
        , _delay_in_bytes (0)
        , _audio_frames_processed (0)
 {
        , _delay_in_bytes (0)
        , _audio_frames_processed (0)
 {
-       if (_opt->decode_video_frequency != 0 && _film->length() == 0) {
-               throw DecodeError ("cannot do a partial decode if length == 0");
+       if (_opt->decode_video_frequency != 0 && !_film->length()) {
+               throw DecodeError ("cannot do a partial decode if length is unknown");
        }
 }
 
        }
 }
 
@@ -111,19 +111,19 @@ Decoder::process_end ()
           in to get it to the right length.
        */
 
           in to get it to the right length.
        */
 
-       int64_t const video_length_in_audio_frames = ((int64_t) _film->dcp_length() * audio_sample_rate() / frames_per_second());
+       int64_t const video_length_in_audio_frames = ((int64_t) last_video_frame() * audio_sample_rate() / frames_per_second());
        int64_t const audio_short_by_frames = video_length_in_audio_frames - _audio_frames_processed;
 
        _log->log (
                String::compose ("DCP length is %1 (%2 audio frames); %3 frames of audio processed.",
        int64_t const audio_short_by_frames = video_length_in_audio_frames - _audio_frames_processed;
 
        _log->log (
                String::compose ("DCP length is %1 (%2 audio frames); %3 frames of audio processed.",
-                                _film->dcp_length(),
+                                last_video_frame(),
                                 video_length_in_audio_frames,
                                 _audio_frames_processed)
                );
        
        if (audio_short_by_frames >= 0 && _opt->decode_audio) {
 
                                 video_length_in_audio_frames,
                                 _audio_frames_processed)
                );
        
        if (audio_short_by_frames >= 0 && _opt->decode_audio) {
 
-               _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", _film->dcp_length(), _audio_frames_processed));
+               _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", last_video_frame(), _audio_frames_processed));
                _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
                _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
@@ -150,13 +150,13 @@ Decoder::go ()
 {
        process_begin ();
 
 {
        process_begin ();
 
-       if (_job && _ignore_length) {
+       if (_job && !_film->dcp_length()) {
                _job->set_progress_unknown ();
        }
 
        while (pass () == false) {
                _job->set_progress_unknown ();
        }
 
        while (pass () == false) {
-               if (_job && !_ignore_length) {
-                       _job->set_progress (float (_video_frame) / _film->dcp_length());
+               if (_job && _film->dcp_length()) {
+                       _job->set_progress (float (_video_frame) / _film->dcp_length().get());
                }
        }
 
                }
        }
 
@@ -286,7 +286,7 @@ Decoder::process_video (AVFrame* frame)
 
        int gap = 0;
        if (_opt->decode_video_frequency != 0) {
 
        int gap = 0;
        if (_opt->decode_video_frequency != 0) {
-               gap = _film->length() / _opt->decode_video_frequency;
+               gap = _film->length().get() / _opt->decode_video_frequency;
        }
 
        if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame % gap) != 0) {
        }
 
        if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame % gap) != 0) {
index 8750ab442c185018fb61c6c09421b7551f5f32b0..0104f5a16ad74d46b35a8a0fedaa08457bd2c379 100644 (file)
@@ -62,6 +62,7 @@ using std::vector;
 using std::ifstream;
 using std::ofstream;
 using std::setfill;
 using std::ifstream;
 using std::ofstream;
 using std::setfill;
+using std::min;
 using boost::shared_ptr;
 using boost::lexical_cast;
 using boost::to_upper_copy;
 using boost::shared_ptr;
 using boost::lexical_cast;
 using boost::to_upper_copy;
@@ -81,7 +82,6 @@ Film::Film (string d, bool must_exist)
        , _dcp_content_type (0)
        , _format (0)
        , _scaler (Scaler::from_id ("bicubic"))
        , _dcp_content_type (0)
        , _format (0)
        , _scaler (Scaler::from_id ("bicubic"))
-       , _dcp_frames (0)
        , _dcp_trim_action (CUT)
        , _dcp_ab (false)
        , _audio_stream (-1)
        , _dcp_trim_action (CUT)
        , _dcp_ab (false)
        , _audio_stream (-1)
@@ -92,7 +92,6 @@ Film::Film (string d, bool must_exist)
        , _with_subtitles (false)
        , _subtitle_offset (0)
        , _subtitle_scale (1)
        , _with_subtitles (false)
        , _subtitle_offset (0)
        , _subtitle_scale (1)
-       , _length (0)
        , _audio_sample_rate (0)
        , _has_subtitles (false)
        , _frames_per_second (0)
        , _audio_sample_rate (0)
        , _has_subtitles (false)
        , _frames_per_second (0)
@@ -252,7 +251,7 @@ Film::make_dcp (bool transcode)
 
        shared_ptr<Options> o (new Options (j2k_dir(), ".j2c", dir ("wavs")));
        o->out_size = format()->dcp_size ();
 
        shared_ptr<Options> o (new Options (j2k_dir(), ".j2c", dir ("wavs")));
        o->out_size = format()->dcp_size ();
-       if (dcp_frames() == 0) {
+       if (!dcp_frames()) {
                /* Decode the whole film, no blacking */
                o->black_after = 0;
        } else {
                /* Decode the whole film, no blacking */
                o->black_after = 0;
        } else {
@@ -263,7 +262,7 @@ Film::make_dcp (bool transcode)
                        break;
                case BLACK_OUT:
                        /* Decode the whole film, but black some frames out */
                        break;
                case BLACK_OUT:
                        /* Decode the whole film, but black some frames out */
-                       o->black_after = dcp_frames ();
+                       o->black_after = dcp_frames().get ();
                }
        }
        
                }
        }
        
@@ -417,7 +416,7 @@ Film::write_metadata () const
                f << "filter " << (*i)->id () << "\n";
        }
        f << "scaler " << _scaler->id () << "\n";
                f << "filter " << (*i)->id () << "\n";
        }
        f << "scaler " << _scaler->id () << "\n";
-       f << "dcp_frames " << _dcp_frames << "\n";
+       f << "dcp_frames " << _dcp_frames.get_value_or(0) << "\n";
 
        f << "dcp_trim_action ";
        switch (_dcp_trim_action) {
 
        f << "dcp_trim_action ";
        switch (_dcp_trim_action) {
@@ -454,7 +453,7 @@ Film::write_metadata () const
        }
        f << "width " << _size.width << "\n";
        f << "height " << _size.height << "\n";
        }
        f << "width " << _size.width << "\n";
        f << "height " << _size.height << "\n";
-       f << "length " << _length << "\n";
+       f << "length " << _length.get_value_or(0) << "\n";
        f << "audio_sample_rate " << _audio_sample_rate << "\n";
        f << "content_digest " << _content_digest << "\n";
        f << "has_subtitles " << _has_subtitles << "\n";
        f << "audio_sample_rate " << _audio_sample_rate << "\n";
        f << "content_digest " << _content_digest << "\n";
        f << "has_subtitles " << _has_subtitles << "\n";
@@ -508,7 +507,10 @@ Film::read_metadata ()
                } else if (k == "scaler") {
                        _scaler = Scaler::from_id (v);
                } else if (k == "dcp_frames") {
                } else if (k == "scaler") {
                        _scaler = Scaler::from_id (v);
                } else if (k == "dcp_frames") {
-                       _dcp_frames = atoi (v.c_str ());
+                       int const vv = atoi (v.c_str ());
+                       if (vv) {
+                               _dcp_frames = vv;
+                       }
                } else if (k == "dcp_trim_action") {
                        if (v == "cut") {
                                _dcp_trim_action = CUT;
                } else if (k == "dcp_trim_action") {
                        if (v == "cut") {
                                _dcp_trim_action = CUT;
@@ -561,7 +563,10 @@ Film::read_metadata ()
                } else if (k == "height") {
                        _size.height = atoi (v.c_str ());
                } else if (k == "length") {
                } else if (k == "height") {
                        _size.height = atoi (v.c_str ());
                } else if (k == "length") {
-                       _length = atof (v.c_str ());
+                       int const vv = atoi (v.c_str ());
+                       if (vv) {
+                               _length = vv;
+                       }
                } else if (k == "audio_sample_rate") {
                        _audio_sample_rate = atoi (v.c_str ());
                } else if (k == "content_digest") {
                } else if (k == "audio_sample_rate") {
                        _audio_sample_rate = atoi (v.c_str ());
                } else if (k == "content_digest") {
@@ -738,11 +743,15 @@ Film::target_audio_sample_rate () const
        return rint (t);
 }
 
        return rint (t);
 }
 
-int
+boost::optional<int>
 Film::dcp_length () const
 {
 Film::dcp_length () const
 {
+       if (!length()) {
+               return boost::optional<int> ();
+       }
+
        if (dcp_frames()) {
        if (dcp_frames()) {
-               return dcp_frames();
+               return min (dcp_frames().get(), length().get());
        }
 
        return length();
        }
 
        return length();
@@ -914,7 +923,7 @@ Film::set_content (string c)
        o->out_size = Size (1024, 1024);
        
        shared_ptr<Decoder> d = decoder_factory (shared_from_this(), o, 0, 0);
        o->out_size = Size (1024, 1024);
        
        shared_ptr<Decoder> d = decoder_factory (shared_from_this(), o, 0, 0);
-       
+
        set_size (d->native_size ());
        set_frames_per_second (d->frames_per_second ());
        set_audio_sample_rate (d->audio_sample_rate ());
        set_size (d->native_size ());
        set_frames_per_second (d->frames_per_second ());
        set_audio_sample_rate (d->audio_sample_rate ());
@@ -1246,6 +1255,16 @@ Film::set_length (int l)
        signal_changed (LENGTH);
 }
 
        signal_changed (LENGTH);
 }
 
+void
+Film::unset_length ()
+{
+       {
+               boost::mutex::scoped_lock lm (_state_mutex);
+               _length = boost::none;
+       }
+       signal_changed (LENGTH);
+}      
+
 void
 Film::set_audio_sample_rate (int r)
 {
 void
 Film::set_audio_sample_rate (int r)
 {
index 27be4331c6c3d3a1c60be34c57894047352b85d5..13189170684cb09fe11181dd3e0ba8150e63357c 100644 (file)
@@ -95,7 +95,7 @@ public:
        void read_metadata ();
 
        Size cropped_size (Size) const;
        void read_metadata ();
 
        Size cropped_size (Size) const;
-       int dcp_length () const;
+       boost::optional<int> dcp_length () const;
        std::string dci_name () const;
        std::string dcp_name () const;
 
        std::string dci_name () const;
        std::string dcp_name () const;
 
@@ -185,7 +185,7 @@ public:
                return _scaler;
        }
 
                return _scaler;
        }
 
-       int dcp_frames () const {
+       boost::optional<int> dcp_frames () const {
                boost::mutex::scoped_lock lm (_state_mutex);
                return _dcp_frames;
        }
                boost::mutex::scoped_lock lm (_state_mutex);
                return _dcp_frames;
        }
@@ -297,11 +297,11 @@ public:
                return _size;
        }
 
                return _size;
        }
 
-       int length () const {
+       boost::optional<int> length () const {
                boost::mutex::scoped_lock lm (_state_mutex);
                return _length;
        }
                boost::mutex::scoped_lock lm (_state_mutex);
                return _length;
        }
-
+       
        int audio_sample_rate () const {
                boost::mutex::scoped_lock lm (_state_mutex);
                return _audio_sample_rate;
        int audio_sample_rate () const {
                boost::mutex::scoped_lock lm (_state_mutex);
                return _audio_sample_rate;
@@ -369,6 +369,7 @@ public:
        void set_thumbs (std::vector<int>);
        void set_size (Size);
        void set_length (int);
        void set_thumbs (std::vector<int>);
        void set_size (Size);
        void set_length (int);
+       void unset_length ();
        void set_audio_sample_rate (int);
        void set_content_digest (std::string);
        void set_has_subtitles (bool);
        void set_audio_sample_rate (int);
        void set_content_digest (std::string);
        void set_has_subtitles (bool);
@@ -418,8 +419,8 @@ private:
        std::vector<Filter const *> _filters;
        /** Scaler algorithm to use */
        Scaler const * _scaler;
        std::vector<Filter const *> _filters;
        /** Scaler algorithm to use */
        Scaler const * _scaler;
-       /** Number of frames to put in the DCP, or 0 for all */
-       int _dcp_frames;
+       /** Maximum number of frames to put in the DCP, if applicable */
+       boost::optional<int> _dcp_frames;
        /** What to do with audio when trimming DCPs */
        TrimAction _dcp_trim_action;
        /** true to create an A/B comparison DCP, where the left half of the image
        /** What to do with audio when trimming DCPs */
        TrimAction _dcp_trim_action;
        /** true to create an A/B comparison DCP, where the left half of the image
@@ -461,8 +462,8 @@ private:
        std::vector<int> _thumbs;
        /** Size, in pixels, of the source (ignoring cropping) */
        Size _size;
        std::vector<int> _thumbs;
        /** Size, in pixels, of the source (ignoring cropping) */
        Size _size;
-       /** Length of the source in frames */
-       int _length;
+       /** Actual length of the source (in video frames) from examining it */
+       boost::optional<int> _length;
        /** Sample rate of the source audio, in Hz */
        int _audio_sample_rate;
        /** MD5 digest of our content file */
        /** Sample rate of the source audio, in Hz */
        int _audio_sample_rate;
        /** MD5 digest of our content file */
index e2c90a854c3e25d96253f1d72617a6ed98ef3074..2bb0e1ba0c49fa637518042a2caec09fa41eb2d5 100644 (file)
@@ -70,6 +70,10 @@ MakeDCPJob::wav_path (libdcp::Channel c) const
 void
 MakeDCPJob::run ()
 {
 void
 MakeDCPJob::run ()
 {
+       if (!_film->dcp_length()) {
+               throw EncodeError ("cannot make a DCP when the source length is not known");
+       }
+       
        string const dcp_path = _film->dir (_film->dcp_name());
 
        /* Remove any old DCP */
        string const dcp_path = _film->dir (_film->dcp_name());
 
        /* Remove any old DCP */
@@ -78,7 +82,7 @@ MakeDCPJob::run ()
        int frames = 0;
        switch (_film->content_type ()) {
        case VIDEO:
        int frames = 0;
        switch (_film->content_type ()) {
        case VIDEO:
-               frames = _film->dcp_length ();
+               frames = _film->dcp_length().get();
                break;
        case STILL:
                frames = _film->still_duration() * ImageMagickDecoder::static_frames_per_second ();
                break;
        case STILL:
                frames = _film->still_duration() * ImageMagickDecoder::static_frames_per_second ();
index cf16b8ab650982b8e65b09b4c50909af6d39f8b6..877214316eb75dcd1e2c352d61bc71019927b852 100644 (file)
@@ -109,5 +109,6 @@ TranscodeJob::remaining_time () const
                return 0;
        }
 
                return 0;
        }
 
-       return ((_film->dcp_length() - _encoder->last_frame()) / fps);
+       /* We assume that dcp_length() is valid */
+       return ((_film->dcp_length().get() - _encoder->last_frame()) / fps);
 }
 }
index aed6808cbd595470a1969745e445c640034e2a15..6363275caf81940cd41683cda93d9ab65a9d17d3 100644 (file)
@@ -50,10 +50,10 @@ DCPRangeDialog::DCPRangeDialog (wxWindow* p, Film* f)
        table->Add (_black_out);
 
        _n_frames->SetRange (1, INT_MAX - 1);
        table->Add (_black_out);
 
        _n_frames->SetRange (1, INT_MAX - 1);
-       if (_film->dcp_frames() > 0) {
+       if (_film->dcp_frames()) {
                _whole->SetValue (false);
                _first->SetValue (true);
                _whole->SetValue (false);
                _first->SetValue (true);
-               _n_frames->SetValue (_film->dcp_frames ());
+               _n_frames->SetValue (_film->dcp_frames().get());
        } else {
                _whole->SetValue (true);
                _first->SetValue (false);
        } else {
                _whole->SetValue (true);
                _first->SetValue (false);
index 542cde7d7917b09c526de6860a17c882ef9db50f..b90731cf3464393cad2920177f3300d92d018bcc 100644 (file)
@@ -478,10 +478,10 @@ FilmEditor::film_changed (Film::Property p)
                }
                break;
        case Film::LENGTH:
                }
                break;
        case Film::LENGTH:
-               if (_film->frames_per_second() > 0 && _film->length() > 0) {
-                       s << _film->length() << " frames; " << seconds_to_hms (_film->length() / _film->frames_per_second());
-               } else if (_film->length() > 0) {
-                       s << _film->length() << " frames";
+               if (_film->frames_per_second() > 0 && _film->length()) {
+                       s << _film->length().get() << " frames; " << seconds_to_hms (_film->length().get() / _film->frames_per_second());
+               } else if (_film->length()) {
+                       s << _film->length().get() << " frames";
                } 
                _length->SetLabel (std_to_wx (s.str ()));
                break;
                } 
                _length->SetLabel (std_to_wx (s.str ()));
                break;
index 67f1fc91bef2bd5e5b245ddd8464ee38e9c79155..b8a47e0e37fe1913dc242c4b6efaccf7bc203e69 100644 (file)
@@ -49,16 +49,21 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, Film* film)
        add_label_to_sizer (table, this, "Frames already encoded");
        _encoded = new ThreadedStaticText (this, "counting...", boost::bind (&PropertiesDialog::frames_already_encoded, this));
        table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL);
        add_label_to_sizer (table, this, "Frames already encoded");
        _encoded = new ThreadedStaticText (this, "counting...", boost::bind (&PropertiesDialog::frames_already_encoded, this));
        table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL);
-       
-       _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length ())));
-       double const disk = ((double) Config::instance()->j2k_bandwidth() / 8) * _film->length() / (_film->frames_per_second () * 1073741824);
-       stringstream s;
-       s << fixed << setprecision (1) << disk << "Gb";
-       _disk_for_frames->SetLabel (std_to_wx (s.str ()));
 
 
-       stringstream t;
-       t << fixed << setprecision (1) << (disk * 2) << "Gb";
-       _total_disk->SetLabel (std_to_wx (t.str ()));
+       if (_film->length()) {
+               _frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().get())));
+               double const disk = ((double) Config::instance()->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824);
+               stringstream s;
+               s << fixed << setprecision (1) << disk << "Gb";
+               _disk_for_frames->SetLabel (std_to_wx (s.str ()));
+               stringstream t;
+               t << fixed << setprecision (1) << (disk * 2) << "Gb";
+               _total_disk->SetLabel (std_to_wx (t.str ()));
+       } else {
+               _frames->SetLabel (_("unknown"));
+               _disk_for_frames->SetLabel (_("unknown"));
+               _total_disk->SetLabel (_("unknown"));
+       }
 
        wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
        overall_sizer->Add (table, 0, wxALL, 6);
 
        wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
        overall_sizer->Add (table, 0, wxALL, 6);
@@ -82,8 +87,8 @@ PropertiesDialog::frames_already_encoded () const
                return "";
        }
        
                return "";
        }
        
-       if (_film->length()) {
-               u << " (" << (_film->encoded_frames() * 100 / _film->length()) << "%)";
+       if (_film->dcp_length()) {
+               u << " (" << (_film->encoded_frames() * 100 / _film->dcp_length().get()) << "%)";
        }
        return u.str ();
 }
        }
        return u.str ();
 }