Commit 6fd4013a authored by Janne Grunau's avatar Janne Grunau Committed by Jean-Baptiste Kempf

dav1d: add --verify option to verify decoding results

Will be used for regression tests.
parent 285d1b76
...@@ -167,7 +167,10 @@ int main(const int argc, char *const *const argv) { ...@@ -167,7 +167,10 @@ int main(const int argc, char *const *const argv) {
if (out) { if (out) {
if (!cli_settings.quiet && istty) if (!cli_settings.quiet && istty)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
output_close(out); if (cli_settings.verify)
res |= output_verify(out, cli_settings.verify);
else
output_close(out);
} else { } else {
fprintf(stderr, "No data decoded\n"); fprintf(stderr, "No data decoded\n");
res = 1; res = 1;
......
...@@ -47,6 +47,7 @@ enum { ...@@ -47,6 +47,7 @@ enum {
ARG_MUXER, ARG_MUXER,
ARG_FRAME_THREADS, ARG_FRAME_THREADS,
ARG_TILE_THREADS, ARG_TILE_THREADS,
ARG_VERIFY,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
...@@ -60,6 +61,7 @@ static const struct option long_opts[] = { ...@@ -60,6 +61,7 @@ static const struct option long_opts[] = {
{ "skip", 1, NULL, 's' }, { "skip", 1, NULL, 's' },
{ "framethreads", 1, NULL, ARG_FRAME_THREADS }, { "framethreads", 1, NULL, ARG_FRAME_THREADS },
{ "tilethreads", 1, NULL, ARG_TILE_THREADS }, { "tilethreads", 1, NULL, ARG_TILE_THREADS },
{ "verify", 1, NULL, ARG_VERIFY },
{ NULL, 0, NULL, 0 }, { NULL, 0, NULL, 0 },
}; };
...@@ -83,7 +85,8 @@ static void usage(const char *const app, const char *const reason, ...) { ...@@ -83,7 +85,8 @@ static void usage(const char *const app, const char *const reason, ...) {
" --skip/-s $num: skip decoding of the first $num frames\n" " --skip/-s $num: skip decoding of the first $num frames\n"
" --version/-v: print version and exit\n" " --version/-v: print version and exit\n"
" --framethreads $num: number of frame threads (default: 1)\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); exit(1);
} }
...@@ -153,6 +156,9 @@ void parse(const int argc, char *const *const argv, ...@@ -153,6 +156,9 @@ void parse(const int argc, char *const *const argv,
lib_settings->n_tile_threads = lib_settings->n_tile_threads =
parse_unsigned(optarg, ARG_TILE_THREADS, argv[0]); parse_unsigned(optarg, ARG_TILE_THREADS, argv[0]);
break; break;
case ARG_VERIFY:
cli_settings->verify = optarg;
break;
case 'v': case 'v':
fprintf(stderr, "%s\n", dav1d_version()); fprintf(stderr, "%s\n", dav1d_version());
exit(0); exit(0);
...@@ -161,6 +167,17 @@ void parse(const int argc, char *const *const argv, ...@@ -161,6 +167,17 @@ void parse(const int argc, char *const *const argv,
} }
} }
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) if (!cli_settings->inputfile)
usage(argv[0], "Input file (-i/--input) is required"); usage(argv[0], "Input file (-i/--input) is required");
if (!cli_settings->outputfile) if (!cli_settings->outputfile)
......
...@@ -35,6 +35,7 @@ typedef struct { ...@@ -35,6 +35,7 @@ typedef struct {
const char *inputfile; const char *inputfile;
const char *demuxer; const char *demuxer;
const char *muxer; const char *muxer;
const char *verify;
unsigned limit, skip; unsigned limit, skip;
int quiet; int quiet;
} CLISettings; } CLISettings;
......
...@@ -190,7 +190,7 @@ static int md5_write(MD5Context *const md5, Dav1dPicture *const p) { ...@@ -190,7 +190,7 @@ static int md5_write(MD5Context *const md5, Dav1dPicture *const p) {
return 0; return 0;
} }
static void md5_close(MD5Context *const md5) { static void md5_finish(MD5Context *const md5) {
static const uint8_t bit[2] = { 0x80, 0x00 }; static const uint8_t bit[2] = { 0x80, 0x00 };
uint64_t len = md5->len << 3; uint64_t len = md5->len << 3;
...@@ -198,6 +198,10 @@ static void md5_close(MD5Context *const md5) { ...@@ -198,6 +198,10 @@ static void md5_close(MD5Context *const md5) {
while ((md5->len & 63) != 56) while ((md5->len & 63) != 56)
md5_update(md5, &bit[1], 1); md5_update(md5, &bit[1], 1);
md5_update(md5, (uint8_t *) &len, 8); md5_update(md5, (uint8_t *) &len, 8);
}
static void md5_close(MD5Context *const md5) {
md5_finish(md5);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x", fprintf(md5->f, "%2.2x%2.2x%2.2x%2.2x",
md5->abcd[i] & 0xff, md5->abcd[i] & 0xff,
...@@ -210,6 +214,29 @@ static void md5_close(MD5Context *const md5) { ...@@ -210,6 +214,29 @@ static void md5_close(MD5Context *const md5) {
fclose(md5->f); 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 = { const Muxer md5_muxer = {
.priv_data_size = sizeof(MD5Context), .priv_data_size = sizeof(MD5Context),
.name = "md5", .name = "md5",
...@@ -217,4 +244,5 @@ const Muxer md5_muxer = { ...@@ -217,4 +244,5 @@ const Muxer md5_muxer = {
.write_header = md5_open, .write_header = md5_open,
.write_picture = md5_write, .write_picture = md5_write,
.write_trailer = md5_close, .write_trailer = md5_close,
.verify = md5_verify,
}; };
...@@ -39,6 +39,14 @@ typedef struct Muxer { ...@@ -39,6 +39,14 @@ typedef struct Muxer {
const Dav1dPictureParameters *p, const unsigned fps[2]); const Dav1dPictureParameters *p, const unsigned fps[2]);
int (*write_picture)(MuxerPriv *ctx, Dav1dPicture *p); int (*write_picture)(MuxerPriv *ctx, Dav1dPicture *p);
void (*write_trailer)(MuxerPriv *ctx); 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; } Muxer;
#endif /* __DAV1D_OUTPUT_MUXER_H__ */ #endif /* __DAV1D_OUTPUT_MUXER_H__ */
...@@ -142,3 +142,11 @@ void output_close(MuxerContext *const ctx) { ...@@ -142,3 +142,11 @@ void output_close(MuxerContext *const ctx) {
ctx->impl->write_trailer(ctx->data); ctx->impl->write_trailer(ctx->data);
free(ctx); 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;
}
...@@ -37,5 +37,13 @@ int output_open(MuxerContext **c, const char *name, const char *filename, ...@@ -37,5 +37,13 @@ int output_open(MuxerContext **c, const char *name, const char *filename,
const Dav1dPictureParameters *p, const unsigned fps[2]); const Dav1dPictureParameters *p, const unsigned fps[2]);
int output_write(MuxerContext *ctx, Dav1dPicture *pic); int output_write(MuxerContext *ctx, Dav1dPicture *pic);
void output_close(MuxerContext *ctx); 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__ */ #endif /* __DAV1D_OUTPUT_OUTPUT_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment