Add estimated completion time to vpxenc
authorJohn Koleszar <jkoleszar@google.com>
Wed, 13 Feb 2013 05:17:56 +0000 (21:17 -0800)
committerJohn Koleszar <jkoleszar@google.com>
Mon, 4 Mar 2013 21:18:55 +0000 (13:18 -0800)
Make the progress line more useful by providing per-frame updates of
processing frame rate and estimated time remaining.

Fixes issue #534.

Change-Id: Ic91551878ff4b2f5db1cedaafb588add220cfa52

vpxenc.c

index 8de73f7..435021e 100644 (file)
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -301,6 +301,7 @@ struct detect_buffer {
 struct input_state {
   char                 *fn;
   FILE                 *file;
+  off_t                 length;
   y4m_input             y4m;
   struct detect_buffer  detect;
   enum video_file_type  file_type;
@@ -1730,6 +1731,14 @@ void open_input_file(struct input_state *input) {
   if (!input->file)
     fatal("Failed to open input file");
 
+  if (!fseeko(input->file, 0, SEEK_END)) {
+    /* Input file is seekable. Figure out how long it is, so we can get
+     * progress info.
+     */
+    input->length = ftello(input->file);
+    rewind(input->file);
+  }
+
   /* For RAW input sources, these bytes will applied on the first frame
    *  in read_frame().
    */
@@ -2246,9 +2255,6 @@ static void get_cx_data(struct stream_state  *stream,
         if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) {
           stream->frames_out++;
         }
-        if (!global->quiet)
-          fprintf(stderr, " %6luF",
-                  (unsigned long)pkt->data.frame.sz);
 
         update_rate_histogram(&stream->rate_hist, cfg, pkt);
         if (stream->config.write_webm) {
@@ -2292,9 +2298,6 @@ static void get_cx_data(struct stream_state  *stream,
         break;
       case VPX_CODEC_STATS_PKT:
         stream->frames_out++;
-        if (!global->quiet)
-          fprintf(stderr, " %6luS",
-                  (unsigned long)pkt->data.twopass_stats.sz);
         stats_write(&stream->stats,
                     pkt->data.twopass_stats.buf,
                     pkt->data.twopass_stats.sz);
@@ -2308,8 +2311,6 @@ static void get_cx_data(struct stream_state  *stream,
           stream->psnr_sse_total += pkt->data.psnr.sse[0];
           stream->psnr_samples_total += pkt->data.psnr.samples[0];
           for (i = 0; i < 4; i++) {
-            if (!global->quiet)
-              fprintf(stderr, "%.3f ", pkt->data.psnr.psnr[i]);
             stream->psnr_totals[i] += pkt->data.psnr.psnr[i];
           }
           stream->psnr_count++;
@@ -2342,7 +2343,7 @@ static void show_psnr(struct stream_state  *stream) {
 }
 
 
-float usec_to_fps(uint64_t usec, unsigned int frames) {
+static float usec_to_fps(uint64_t usec, unsigned int frames) {
   return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0);
 }
 
@@ -2367,6 +2368,24 @@ static void test_decode(struct stream_state  *stream) {
   }
 }
 
+
+static void print_time(const char *label, int64_t etl) {
+  int hours, mins, secs;
+
+  if (etl >= 0) {
+    hours = etl / 3600;
+    etl -= hours * 3600;
+    mins = etl / 60;
+    etl -= mins * 60;
+    secs = etl;
+
+    fprintf(stderr, "[%3s %2d:%02d:%02d] ",
+            label, hours, mins, secs);
+  } else {
+    fprintf(stderr, "[%3s  unknown] ", label);
+  }
+}
+
 int main(int argc, const char **argv_) {
   int                    pass;
   vpx_image_t            raw;
@@ -2424,6 +2443,9 @@ int main(int argc, const char **argv_) {
 
   for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) {
     int frames_in = 0;
+    int64_t estimated_time_left = -1;
+    int64_t average_rate = -1;
+    off_t lagged_count = 0;
 
     open_input_file(&input);
 
@@ -2500,18 +2522,23 @@ int main(int argc, const char **argv_) {
           frames_in++;
 
         if (!global.quiet) {
+          float fps = usec_to_fps(cx_time, frames_in);
+          fprintf(stderr, "\rPass %d/%d ", pass + 1, global.passes);
+
           if (stream_cnt == 1)
             fprintf(stderr,
-                    "\rPass %d/%d frame %4d/%-4d %7"PRId64"B \033[K",
-                    pass + 1, global.passes, frames_in,
-                    streams->frames_out, (int64_t)streams->nbytes);
+                    "frame %4d/%-4d %7"PRId64"B ",
+                    frames_in, streams->frames_out, (int64_t)streams->nbytes);
           else
-            fprintf(stderr,
-                    "\rPass %d/%d frame %4d %7lu %s (%.2f fps)\033[K",
-                    pass + 1, global.passes, frames_in,
-                    cx_time > 9999999 ? cx_time / 1000 : cx_time,
-                    cx_time > 9999999 ? "ms" : "us",
-                    usec_to_fps(cx_time, frames_in));
+            fprintf(stderr, "frame %4d ", frames_in);
+
+          fprintf(stderr, "%7lu %s %.2f %s ",
+                  cx_time > 9999999 ? cx_time / 1000 : cx_time,
+                  cx_time > 9999999 ? "ms" : "us",
+                  fps >= 1.0 ? fps : 1000.0 / fps,
+                  fps >= 1.0 ? "fps" : "ms/f");
+          print_time("ETA", estimated_time_left);
+          fprintf(stderr, "\033[K");
         }
 
       } else
@@ -2530,6 +2557,32 @@ int main(int argc, const char **argv_) {
         got_data = 0;
         FOREACH_STREAM(get_cx_data(stream, &global, &got_data));
 
+        if (!got_data && input.length && !streams->frames_out) {
+          lagged_count = global.limit ? frames_in : ftello(input.file);
+        } else if (got_data && input.length) {
+          int64_t remaining;
+          int64_t rate;
+
+          if (global.limit) {
+            int frame_in_lagged = (frames_in - lagged_count) * 1000;
+
+            rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0;
+            remaining = 1000 * (global.limit - frames_in + lagged_count);
+          } else {
+            off_t input_pos = ftello(input.file);
+            off_t input_pos_lagged = input_pos - lagged_count;
+            int64_t limit = input.length;
+
+            rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0;
+            remaining = limit - input_pos + lagged_count;
+          }
+
+          average_rate = (average_rate <= 0)
+              ? rate
+              : (average_rate * 7 + rate) / 8;
+          estimated_time_left = average_rate ? remaining / average_rate : -1;
+        }
+
         if (got_data && global.test_decode)
           FOREACH_STREAM(test_decode(stream));
       }