Add decoder controls for getting last quantizer.
Also adds --framestats=file.csv to aomdec that prints a CSV file with
frame size and frame QP.
Change-Id: I3b70c4b3df35d0b97bdd83cfc4631f096573b4a2
diff --git a/aom/aomdx.h b/aom/aomdx.h
index 834cdff..2a00ecb 100644
--- a/aom/aomdx.h
+++ b/aom/aomdx.h
@@ -115,7 +115,10 @@
*/
AV1_GET_ACCOUNTING,
- AOM_DECODER_CTRL_ID_MAX,
+ /** control function to get last decoded frame quantizer. Returned value uses
+ * internal quantizer scale defined by the codec.
+ */
+ AOMD_GET_LAST_QUANTIZER,
/** control function to set the range of tile decoding. A value that is
* greater and equal to zero indicates only the specific row/column is
@@ -124,7 +127,9 @@
* decoded.
*/
AV1_SET_DECODE_TILE_ROW,
- AV1_SET_DECODE_TILE_COL
+ AV1_SET_DECODE_TILE_COL,
+
+ AOM_DECODER_CTRL_ID_MAX,
};
/** Decrypt n bytes of data from input -> output, using the decrypt_state
@@ -159,6 +164,8 @@
#define AOM_CTRL_AOMD_GET_FRAME_CORRUPTED
AOM_CTRL_USE_TYPE(AOMD_GET_LAST_REF_USED, int *)
#define AOM_CTRL_AOMD_GET_LAST_REF_USED
+AOM_CTRL_USE_TYPE(AOMD_GET_LAST_QUANTIZER, int *)
+#define AOM_CTRL_AOMD_GET_LAST_QUANTIZER
AOM_CTRL_USE_TYPE(AOMD_SET_DECRYPTOR, aom_decrypt_init *)
#define AOM_CTRL_AOMD_SET_DECRYPTOR
// AOM_CTRL_USE_TYPE(AOMD_SET_DECRYPTOR, aom_decrypt_init *)
diff --git a/aomdec.c b/aomdec.c
index 026cb95..acfc7ce 100644
--- a/aomdec.c
+++ b/aomdec.c
@@ -97,6 +97,8 @@
ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use");
static const arg_def_t md5arg =
ARG_DEF(NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
+static const arg_def_t framestatsarg =
+ ARG_DEF(NULL, "framestats", 1, "Output per-frame stats (.csv format)");
#if CONFIG_AOM_HIGHBITDEPTH
static const arg_def_t outbitdeptharg =
ARG_DEF(NULL, "output-bit-depth", 1, "Output bit-depth for decoded frames");
@@ -128,6 +130,7 @@
&scalearg,
&fb_arg,
&md5arg,
+ &framestatsarg,
&error_concealment,
&continuearg,
#if CONFIG_AOM_HIGHBITDEPTH
@@ -541,6 +544,8 @@
char outfile_name[PATH_MAX] = { 0 };
FILE *outfile = NULL;
+ FILE *framestats_file = NULL;
+
MD5Context md5_ctx;
unsigned char md5_digest[16];
@@ -567,9 +572,9 @@
die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
} else if (arg_match(&arg, &looparg, argi)) {
// no-op
- } else if (arg_match(&arg, &outputfile, argi))
+ } else if (arg_match(&arg, &outputfile, argi)) {
outfile_pattern = arg.val;
- else if (arg_match(&arg, &use_yv12, argi)) {
+ } else if (arg_match(&arg, &use_yv12, argi)) {
use_y4m = 0;
flipuv = 1;
opt_yv12 = 1;
@@ -579,24 +584,31 @@
opt_i420 = 1;
} else if (arg_match(&arg, &rawvideo, argi)) {
use_y4m = 0;
- } else if (arg_match(&arg, &flipuvarg, argi))
+ } else if (arg_match(&arg, &flipuvarg, argi)) {
flipuv = 1;
- else if (arg_match(&arg, &noblitarg, argi))
+ } else if (arg_match(&arg, &noblitarg, argi)) {
noblit = 1;
- else if (arg_match(&arg, &progressarg, argi))
+ } else if (arg_match(&arg, &progressarg, argi)) {
progress = 1;
- else if (arg_match(&arg, &limitarg, argi))
+ } else if (arg_match(&arg, &limitarg, argi)) {
stop_after = arg_parse_uint(&arg);
- else if (arg_match(&arg, &skiparg, argi))
+ } else if (arg_match(&arg, &skiparg, argi)) {
arg_skip = arg_parse_uint(&arg);
- else if (arg_match(&arg, &postprocarg, argi))
+ } else if (arg_match(&arg, &postprocarg, argi)) {
postproc = 1;
- else if (arg_match(&arg, &md5arg, argi))
+ } else if (arg_match(&arg, &md5arg, argi)) {
do_md5 = 1;
- else if (arg_match(&arg, &summaryarg, argi))
+ } else if (arg_match(&arg, &framestatsarg, argi)) {
+ framestats_file = fopen(arg.val, "w");
+ if (!framestats_file) {
+ die("Error: Could not open --framestats file (%s) for writing.\n",
+ arg.val);
+ }
+ } else if (arg_match(&arg, &summaryarg, argi)) {
summary = 1;
- else if (arg_match(&arg, &threadsarg, argi))
+ } else if (arg_match(&arg, &threadsarg, argi)) {
cfg.threads = arg_parse_uint(&arg);
+ }
#if CONFIG_AV1_DECODER
else if (arg_match(&arg, &frameparallelarg, argi))
frame_parallel = 1;
@@ -756,6 +768,8 @@
frame_avail = 1;
got_data = 0;
+ if (framestats_file) fprintf(framestats_file, "bytes,qp\r\n");
+
/* Decode file */
while (frame_avail || got_data) {
aom_codec_iter_t iter = NULL;
@@ -781,6 +795,16 @@
if (!keep_going) goto fail;
}
+ if (framestats_file) {
+ int qp;
+ if (aom_codec_control(&decoder, AOMD_GET_LAST_QUANTIZER, &qp)) {
+ warn("Failed AOMD_GET_LAST_QUANTIZER: %s",
+ aom_codec_error(&decoder));
+ if (!keep_going) goto fail;
+ }
+ fprintf(framestats_file, "%d,%d\r\n", (int)bytes_in_buffer, qp);
+ }
+
aom_usec_timer_mark(&timer);
dx_time += aom_usec_timer_elapsed(&timer);
} else {
@@ -1017,6 +1041,8 @@
free(ext_fb_list.ext_fb);
fclose(infile);
+ if (framestats_file) fclose(framestats_file);
+
free(argv);
return ret;
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 644f31b..8b0637a 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -947,6 +947,15 @@
return AOM_CODEC_INVALID_PARAM;
}
+static aom_codec_err_t ctrl_get_last_quantizer(aom_codec_alg_priv_t *ctx,
+ va_list args) {
+ int *const arg = va_arg(args, int *);
+ if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
+ *arg =
+ ((FrameWorkerData *)ctx->frame_workers[0].data1)->pbi->common.base_qindex;
+ return AOM_CODEC_OK;
+}
+
static aom_codec_err_t ctrl_get_frame_corrupted(aom_codec_alg_priv_t *ctx,
va_list args) {
int *corrupted = va_arg(args, int *);
@@ -1142,14 +1151,15 @@
{ AV1_SET_DECODE_TILE_COL, ctrl_set_decode_tile_col },
// Getters
- { AOMD_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates },
{ AOMD_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted },
- { AV1_GET_REFERENCE, ctrl_get_reference },
- { AV1D_GET_DISPLAY_SIZE, ctrl_get_render_size },
+ { AOMD_GET_LAST_QUANTIZER, ctrl_get_last_quantizer },
+ { AOMD_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates },
{ AV1D_GET_BIT_DEPTH, ctrl_get_bit_depth },
+ { AV1D_GET_DISPLAY_SIZE, ctrl_get_render_size },
{ AV1D_GET_FRAME_SIZE, ctrl_get_frame_size },
{ AV1_GET_ACCOUNTING, ctrl_get_accounting },
{ AV1_GET_NEW_FRAME_IMAGE, ctrl_get_new_frame_image },
+ { AV1_GET_REFERENCE, ctrl_get_reference },
{ -1, NULL },
};