Improve transcode job progress reporting.
authorCarl Hetherington <cth@carlh.net>
Sat, 22 Sep 2012 10:35:36 +0000 (11:35 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 22 Sep 2012 10:35:36 +0000 (11:35 +0100)
ChangeLog
src/lib/encoder.cc
src/lib/encoder.h
src/lib/j2k_still_encoder.cc
src/lib/j2k_wav_encoder.cc
src/lib/job.cc
src/lib/job.h
src/lib/tiff_encoder.cc
src/lib/transcode_job.cc
src/lib/transcode_job.h

index 231c19556543e8d1942ca6fe62acc35d4c322405..a4869ed82b24be103f9ed9b671e369ea30479ead 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-09-22  Carl Hetherington  <cth@carlh.net>
+
+       * Improve transcode job progress reporting.
+
 2012-09-22  Carl Hetherington  <cth@carlh.net>
 
        * Version 0.50 released.
index c8eb24c807ab6264d442b9ddcf7fd5d8c27a97e3..18ccd3f5757b7d1250600704a970e399a7ac876c 100644 (file)
@@ -36,6 +36,8 @@ Encoder::Encoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Lo
        : _fs (s)
        , _opt (o)
        , _log (l)
+       , _just_skipped (false)
+       , _last_frame (0)
 {
 
 }
@@ -58,10 +60,27 @@ Encoder::current_frames_per_second () const
        return _history_size / (seconds (now) - seconds (_time_history.back ()));
 }
 
+bool
+Encoder::skipping () const
+{
+       boost::mutex::scoped_lock (_history_mutex);
+       return _just_skipped;
+}
+
+int
+Encoder::last_frame () const
+{
+       boost::mutex::scoped_lock (_history_mutex);
+       return _last_frame;
+}
+
 void
-Encoder::frame_done ()
+Encoder::frame_done (int n)
 {
        boost::mutex::scoped_lock lock (_history_mutex);
+       _just_skipped = false;
+       _last_frame = n;
+       
        struct timeval tv;
        gettimeofday (&tv, 0);
        _time_history.push_front (tv);
@@ -69,3 +88,13 @@ Encoder::frame_done ()
                _time_history.pop_back ();
        }
 }
+
+/** Called by a subclass when it has just skipped the processing
+    of a frame because it has already been done.
+*/
+void
+Encoder::frame_skipped ()
+{
+       boost::mutex::scoped_lock lock (_history_mutex);
+       _just_skipped = true;
+}
index bed2c09882172f47cbd709e5ec7980db3c9f00fe..5c0c4c03fdb95fabf993b5f7ad1fbc08f19cf111 100644 (file)
@@ -68,9 +68,12 @@ public:
        virtual void process_end () = 0;
 
        float current_frames_per_second () const;
+       bool skipping () const;
+       int last_frame () const;
 
 protected:
-       void frame_done ();
+       void frame_done (int n);
+       void frame_skipped ();
        
        /** FilmState of the film that we are encoding */
        boost::shared_ptr<const FilmState> _fs;
@@ -79,9 +82,13 @@ protected:
        /** Log */
        Log* _log;
 
+       /** Mutex for _time_history, _just_skipped and _last_frame */
        mutable boost::mutex _history_mutex;
        std::list<struct timeval> _time_history;
        static int const _history_size;
+       /** true if the last frame we processed was skipped (because it was already done) */
+       bool _just_skipped;
+       int _last_frame;
 };
 
 #endif
index 3109e244ce5e7fc29c44a773381d8e144d9701a6..8f3339a0afbcc41f7f2d2163f4df2bf054ff96d0 100644 (file)
@@ -76,6 +76,6 @@ J2KStillEncoder::process_video (shared_ptr<Image> yuv, int frame)
                        filesystem::copy_file (real, link);
 #endif                 
                }
-               frame_done ();
+               frame_done (0);
        }
 }
index ff450d1ad21e218efaec34ebddb7286951248acd..ef1e8edc1b1728285276163c0f4f2c129769387c 100644 (file)
@@ -126,6 +126,8 @@ J2KWAVEncoder::process_video (shared_ptr<Image> yuv, int frame)
                                          ));
                
                _worker_condition.notify_all ();
+       } else {
+               frame_skipped ();
        }
 }
 
@@ -190,7 +192,7 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server)
 
                if (encoded) {
                        encoded->write (_opt, vf->frame ());
-                       frame_done ();
+                       frame_done (vf->frame ());
                } else {
                        lock.lock ();
                        _queue.push_front (vf);
@@ -253,7 +255,7 @@ J2KWAVEncoder::process_end ()
                try {
                        shared_ptr<EncodedData> e = (*i)->encode_locally ();
                        e->write (_opt, (*i)->frame ());
-                       frame_done ();
+                       frame_done ((*i)->frame ());
                } catch (std::exception& e) {
                        stringstream s;
                        s << "Local encode failed " << e.what() << ".";
index 0feb73d31b22b00f59d6c5cd6c3dea12c8d38a2e..d446b3913208ee897913a27b1a938821258d9071 100644 (file)
@@ -236,11 +236,12 @@ Job::status () const
 {
        float const p = overall_progress ();
        int const t = elapsed_time ();
+       int const r = remaining_time ();
        
        stringstream s;
-       if (!finished () && p >= 0 && t > 10) {
-               s << rint (p * 100) << "%; about " << seconds_to_approximate_hms (t / p - t) << " remaining";
-       } else if (!finished () && t <= 10) {
+       if (!finished () && p >= 0 && t > 10 && r > 0) {
+               s << rint (p * 100) << "%; " << seconds_to_approximate_hms (r) << " remaining";
+       } else if (!finished () && (t <= 10 || r == 0)) {
                s << rint (p * 100) << "%";
        } else if (finished_ok ()) {
                s << "OK (ran for " << seconds_to_hms (t) << ")";
@@ -250,3 +251,9 @@ Job::status () const
 
        return s.str ();
 }
+
+int
+Job::remaining_time () const
+{
+       return elapsed_time() / overall_progress() - elapsed_time();
+}
index 2a77f78f7775e43009e5642fddb5710fcaf1c934..95599bdbb65bf1dd1ca8bae44b4347ac5bb1015d 100644 (file)
@@ -70,6 +70,8 @@ public:
 
 protected:
 
+       virtual int remaining_time () const;
+
        enum State {
                NEW,           ///< the job hasn't been started yet
                RUNNING,       ///< the job is running
index 2cf238006f2f6f4eece0245a0e140ad371427968..19e34741d9326f3d72e38506d97dd2b723c7f183 100644 (file)
@@ -73,5 +73,5 @@ TIFFEncoder::process_video (shared_ptr<Image> image, int frame)
        TIFFClose (output);
 
        boost::filesystem::rename (tmp_file, _opt->frame_out_path (frame, false));
-       frame_done ();
+       frame_done (frame);
 }
index 652a184419892164acc816b299db7fcfe95b0356..f4e3d7af9cee1a02a5f2e57bc159c47ab8b1dd64 100644 (file)
@@ -88,13 +88,30 @@ TranscodeJob::status () const
        if (!_encoder) {
                return "0%";
        }
+
+       if (_encoder->skipping ()) {
+               return "skipping frames already encoded";
+       }
+               
        
        float const fps = _encoder->current_frames_per_second ();
        if (fps == 0) {
                return Job::status ();
        }
-               
+
        stringstream s;
-       s << Job::status () << "; about " << fixed << setprecision (1) << fps << " frames per second.";
+
+       s << Job::status () << "; " << fixed << setprecision (1) << fps << " frames per second";
        return s.str ();
 }
+
+int
+TranscodeJob::remaining_time () const
+{
+       float fps = _encoder->current_frames_per_second ();
+       if (fps == 0) {
+               return 0;
+       }
+
+       return ((_fs->length - _encoder->last_frame()) / fps);
+}
index aa640f6979976105e2a214e34426840cd08613fa..737f10de968ea4b9ee0500cf51bfe2f3b6bc060c 100644 (file)
@@ -38,6 +38,9 @@ public:
        void run ();
        std::string status () const;
 
+protected:
+       int remaining_time () const;
+
 private:
        boost::shared_ptr<Encoder> _encoder;
 };