shithub: libvpx

Download patch

ref: 9837bf4d407db9db9148e9c142ebd1b5cf371d35
parent: 8c16dee4f2b36238abdaa8d55bb8e572b4108ed7
author: Ronald S. Bultje <rbultje@google.com>
date: Fri Feb 15 11:31:02 EST 2013

Don't exit on decode errors in vpxenc.

Allows the user to specify whether decode errors should be fatal or not.
Also makes mismatches optionally fatal.

Change-Id: I58cff4a82f3d42f5653b91cf348a7f669377e632

--- a/vpxenc.c
+++ b/vpxenc.c
@@ -139,10 +139,8 @@
 }
 
 
-static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
-  va_list ap;
-
-  va_start(ap, s);
+static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal,
+                                   const char *s, va_list ap) {
   if (ctx->err) {
     const char *detail = vpx_codec_error_detail(ctx);
 
@@ -152,10 +150,28 @@
     if (detail)
       fprintf(stderr, "    %s\n", detail);
 
-    exit(EXIT_FAILURE);
+    if (fatal)
+      exit(EXIT_FAILURE);
   }
 }
 
+static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
+  va_list ap;
+
+  va_start(ap, s);
+  warn_or_exit_on_errorv(ctx, 1, s, ap);
+  va_end(ap);
+}
+
+static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal,
+                                  const char *s, ...) {
+  va_list ap;
+
+  va_start(ap, s);
+  warn_or_exit_on_errorv(ctx, fatal, s, ap);
+  va_end(ap);
+}
+
 /* This structure is used to abstract the different ways of handling
  * first pass statistics.
  */
@@ -950,8 +966,20 @@
                                                   "Show encoder parameters");
 static const arg_def_t psnrarg          = ARG_DEF(NULL, "psnr", 0,
                                                   "Show PSNR in status line");
-static const arg_def_t recontest        = ARG_DEF(NULL, "test-decode", 0,
-                                                  "Test encode/decode mismatch");
+enum TestDecodeFatality {
+  TEST_DECODE_OFF,
+  TEST_DECODE_FATAL,
+  TEST_DECODE_WARN,
+};
+static const struct arg_enum_list test_decode_enum[] = {
+  {"off",   TEST_DECODE_OFF},
+  {"fatal", TEST_DECODE_FATAL},
+  {"warn",  TEST_DECODE_WARN},
+  {NULL, 0}
+};
+static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1,
+                                                "Test encode/decode mismatch",
+                                                test_decode_enum);
 static const arg_def_t framerate        = ARG_DEF(NULL, "fps", 1,
                                                   "Stream frame rate (rate/scale)");
 static const arg_def_t use_ivf          = ARG_DEF(NULL, "ivf", 0,
@@ -1573,7 +1601,7 @@
   int                       limit;
   int                       skip_frames;
   int                       show_psnr;
-  int                       test_decode;
+  enum TestDecodeFatality   test_decode;
   int                       have_framerate;
   struct vpx_rational       framerate;
   int                       out_part;
@@ -1698,7 +1726,7 @@
     else if (arg_match(&arg, &psnrarg, argi))
       global->show_psnr = 1;
     else if (arg_match(&arg, &recontest, argi))
-      global->test_decode = 1;
+      global->test_decode = arg_parse_enum_or_int(&arg);
     else if (arg_match(&arg, &framerate, argi)) {
       global->framerate = arg_parse_rational(&arg);
       validate_positive_rational(arg.name, &global->framerate);
@@ -2200,7 +2228,7 @@
   }
 
 #if CONFIG_DECODERS
-  if (global->test_decode) {
+  if (global->test_decode != TEST_DECODE_OFF) {
     int width, height;
 
     vpx_codec_dec_init(&stream->decoder, global->codec->dx_iface(), NULL, 0);
@@ -2303,10 +2331,16 @@
 
         *got_data = 1;
 #if CONFIG_DECODERS
-        if (global->test_decode) {
+        if (global->test_decode != TEST_DECODE_OFF && !stream->mismatch_seen) {
           vpx_codec_decode(&stream->decoder, pkt->data.frame.buf,
                            pkt->data.frame.sz, NULL, 0);
-          ctx_exit_on_error(&stream->decoder, "Failed to decode frame");
+          if (stream->decoder.err) {
+            warn_or_exit_on_error(&stream->decoder,
+                                  global->test_decode == TEST_DECODE_FATAL,
+                                  "Failed to decode frame %d in stream %d",
+                                  stream->frames_out + 1, stream->index);
+            stream->mismatch_seen = stream->frames_out + 1;
+          }
         }
 #endif
         break;
@@ -2362,22 +2396,25 @@
 }
 
 
-static void test_decode(struct stream_state  *stream) {
+static void test_decode(struct stream_state  *stream,
+                        enum TestDecodeFatality fatal) {
+  if (stream->mismatch_seen)
+    return;
+
   vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &stream->ref_enc);
   ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame");
   vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &stream->ref_dec);
   ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame");
 
-  if (!stream->mismatch_seen
-      && !compare_img(&stream->ref_enc.img, &stream->ref_dec.img)) {
-    /* TODO(jkoleszar): make fatal. */
+  if (!compare_img(&stream->ref_enc.img, &stream->ref_dec.img)) {
     int y[2], u[2], v[2];
     find_mismatch(&stream->ref_enc.img, &stream->ref_dec.img,
                   y, u, v);
-    warn("Stream %d: Encode/decode mismatch on frame %d"
-         " at Y[%d, %d], U[%d, %d], V[%d, %d]",
-         stream->index, stream->frames_out,
-         y[0], y[1], u[0], u[1], v[0], v[1]);
+    warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL,
+                          "Stream %d: Encode/decode mismatch on frame %d"
+                          " at Y[%d, %d], U[%d, %d], V[%d, %d]",
+                          stream->index, stream->frames_out,
+                          y[0], y[1], u[0], u[1], v[0], v[1]);
     stream->mismatch_seen = stream->frames_out;
   }
 }
@@ -2411,6 +2448,7 @@
   char                   **argv, **argi;
   unsigned long            cx_time = 0;
   int                      stream_cnt = 0;
+  int                      res = 0;
 
   exec_name = argv_[0];
 
@@ -2596,8 +2634,8 @@
           estimated_time_left = average_rate ? remaining / average_rate : -1;
         }
 
-        if (got_data && global.test_decode)
-          FOREACH_STREAM(test_decode(stream));
+        if (got_data && global.test_decode != TEST_DECODE_OFF)
+          FOREACH_STREAM(test_decode(stream, global.test_decode));
       }
 
       fflush(stdout);
@@ -2627,7 +2665,7 @@
 
     FOREACH_STREAM(vpx_codec_destroy(&stream->encoder));
 
-    if (global.test_decode) {
+    if (global.test_decode != TEST_DECODE_OFF) {
       FOREACH_STREAM(vpx_codec_destroy(&stream->decoder));
       FOREACH_STREAM(vpx_img_free(&stream->ref_enc.img));
       FOREACH_STREAM(vpx_img_free(&stream->ref_dec.img));
@@ -2635,6 +2673,9 @@
 
     close_input_file(&input);
 
+    if (global.test_decode == TEST_DECODE_FATAL) {
+      FOREACH_STREAM(res |= stream->mismatch_seen);
+    }
     FOREACH_STREAM(close_output_file(stream, global.codec->fourcc));
 
     FOREACH_STREAM(stats_close(&stream->stats, global.passes - 1));
@@ -2672,5 +2713,5 @@
   vpx_img_free(&raw);
   free(argv);
   free(streams);
-  return EXIT_SUCCESS;
+  return res ? EXIT_FAILURE : EXIT_SUCCESS;
 }