shithub: dav1d

Download patch

ref: 6fd4013ae95649c7cb40337cb2e9efa7dd2e404d
parent: 285d1b7641df768621b57787a7ae3c20d6f6794d
author: Janne Grunau <[email protected]>
date: Tue Oct 30 19:50:43 EDT 2018

dav1d: add --verify option to verify decoding results

Will be used for regression tests.

--- a/tools/dav1d.c
+++ b/tools/dav1d.c
@@ -167,7 +167,10 @@
     if (out) {
         if (!cli_settings.quiet && istty)
             fprintf(stderr, "\n");
-        output_close(out);
+        if (cli_settings.verify)
+            res |= output_verify(out, cli_settings.verify);
+        else
+            output_close(out);
     } else {
         fprintf(stderr, "No data decoded\n");
         res = 1;
--- a/tools/dav1d_cli_parse.c
+++ b/tools/dav1d_cli_parse.c
@@ -47,6 +47,7 @@
     ARG_MUXER,
     ARG_FRAME_THREADS,
     ARG_TILE_THREADS,
+    ARG_VERIFY,
 };
 
 static const struct option long_opts[] = {
@@ -60,6 +61,7 @@
     { "skip",           1, NULL, 's' },
     { "framethreads",   1, NULL, ARG_FRAME_THREADS },
     { "tilethreads",    1, NULL, ARG_TILE_THREADS },
+    { "verify",         1, NULL, ARG_VERIFY },
     { NULL,             0, NULL, 0 },
 };
 
@@ -83,7 +85,8 @@
             " --skip/-s $num:      skip decoding of the first $num frames\n"
             " --version/-v:        print version and exit\n"
             " --framethreads $num: number of frame threads (default: 1)\n"
-            " --tilethreads $num:  number of tile threads (default: 1)\n");
+            " --tilethreads $num:  number of tile threads (default: 1)\n"
+            " --verify $md5:       verify decoded md5. implies --muxer md5, no output\n");
     exit(1);
 }
 
@@ -153,6 +156,9 @@
             lib_settings->n_tile_threads =
                 parse_unsigned(optarg, ARG_TILE_THREADS, argv[0]);
             break;
+        case ARG_VERIFY:
+            cli_settings->verify = optarg;
+            break;
         case 'v':
             fprintf(stderr, "%s\n", dav1d_version());
             exit(0);
@@ -159,6 +165,17 @@
         default:
             break;
         }
+    }
+
+    if (cli_settings->verify) {
+        if (cli_settings->outputfile)
+            usage(argv[0], "Verification (--verify) requires output file (-o/--output) to not set");
+        if (cli_settings->muxer && !strcmp(cli_settings->muxer, "md5"))
+            usage(argv[0], "Verification (--verify) requires the md5 muxer (--muxer md5)");
+
+        cli_settings->outputfile = "-";
+        if (!cli_settings->muxer)
+            cli_settings->muxer = "md5";
     }
 
     if (!cli_settings->inputfile)
--- a/tools/dav1d_cli_parse.h
+++ b/tools/dav1d_cli_parse.h
@@ -35,6 +35,7 @@
     const char *inputfile;
     const char *demuxer;
     const char *muxer;
+    const char *verify;
     unsigned limit, skip;
     int quiet;
 } CLISettings;
--- a/tools/output/md5.c
+++ b/tools/output/md5.c
@@ -190,7 +190,7 @@
     return 0;
 }
 
-static void md5_close(MD5Context *const md5) {
+static void md5_finish(MD5Context *const md5) {
     static const uint8_t bit[2] = { 0x80, 0x00 };
     uint64_t len = md5->len << 3;
 
@@ -198,6 +198,10 @@
     while ((md5->len & 63) != 56)
         md5_update(md5, &bit[1], 1);
     md5_update(md5, (uint8_t *) &len, 8);
+}
+
+static void md5_close(MD5Context *const md5) {
+    md5_finish(md5);
     for (int i = 0; i < 4; i++)
         fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
                 md5->abcd[i] & 0xff,
@@ -210,6 +214,29 @@
         fclose(md5->f);
 }
 
+static int md5_verify(MD5Context *const md5, const char *const md5_str) {
+    md5_finish(md5);
+
+    if (strlen(md5_str) < 32)
+        return 0;
+
+    const char *p = md5_str;
+    unsigned abcd[4] = { 0 };
+    char t[3] = { 0 };
+    for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 4; j++) {
+            unsigned val;
+            char *ignore;
+            memcpy(t, p, 2);
+            p += 2;
+            val = strtoul(t, &ignore, 16);
+            abcd[i] |= val << (8 * j);
+        }
+    }
+
+    return memcmp(abcd, md5->abcd, sizeof(abcd));
+}
+
 const Muxer md5_muxer = {
     .priv_data_size = sizeof(MD5Context),
     .name = "md5",
@@ -217,4 +244,5 @@
     .write_header = md5_open,
     .write_picture = md5_write,
     .write_trailer = md5_close,
+    .verify = md5_verify,
 };
--- a/tools/output/muxer.h
+++ b/tools/output/muxer.h
@@ -39,6 +39,14 @@
                         const Dav1dPictureParameters *p, const unsigned fps[2]);
     int (*write_picture)(MuxerPriv *ctx, Dav1dPicture *p);
     void (*write_trailer)(MuxerPriv *ctx);
+    /**
+     * Verifies the muxed data (for example in the md5 muxer). Replaces write_trailer.
+     *
+     * @param  hash_string Muxer specific reference value.
+     *
+     * @return 0 on success.
+     */
+    int (*verify)(MuxerPriv *ctx, const char *hash_string);
 } Muxer;
 
 #endif /* __DAV1D_OUTPUT_MUXER_H__ */
--- a/tools/output/output.c
+++ b/tools/output/output.c
@@ -142,3 +142,11 @@
         ctx->impl->write_trailer(ctx->data);
     free(ctx);
 }
+
+int output_verify(MuxerContext *const ctx, const char *const md5_Str) {
+    int res = 0;
+    if (ctx->impl->verify)
+        res = ctx->impl->verify(ctx->data, md5_Str);
+    free(ctx);
+    return res;
+}
--- a/tools/output/output.h
+++ b/tools/output/output.h
@@ -37,5 +37,13 @@
                 const Dav1dPictureParameters *p, const unsigned fps[2]);
 int output_write(MuxerContext *ctx, Dav1dPicture *pic);
 void output_close(MuxerContext *ctx);
+/**
+ * Verifies the muxed data (for example in the md5 muxer). Replaces output_close.
+ *
+ * @param  hash_string Muxer specific reference value.
+ *
+ * @return 0 on success.
+ */
+int output_verify(MuxerContext *ctx, const char *hash_string);
 
 #endif /* __DAV1D_OUTPUT_OUTPUT_H__ */