ext-tile: add back the 1D tile output format
This patch added back the 1D tile output format. Now, the supported tile
output formats are YUV1D(default), YUV, and NV12.
BUG=aomedia:2047
Change-Id: I1b02c34ea3137a1239405bb72aaf4789470702b9
diff --git a/aom/aomdx.h b/aom/aomdx.h
index 54372a7..c71eaf9 100644
--- a/aom/aomdx.h
+++ b/aom/aomdx.h
@@ -141,6 +141,9 @@
/** control function to get the size of the tile. */
AV1D_GET_TILE_SIZE,
+ /** control function to get the tile count in a tile list. */
+ AV1D_GET_TILE_COUNT,
+
/** control function to set the byte alignment of the planes in the reference
* buffers. Valid values are power of 2, from 32 to 1024. A value of 0 sets
* legacy alignment. I.e. Y plane is aligned to 32 bytes, U plane directly
@@ -276,6 +279,8 @@
#define AOM_CTRL_AV1D_GET_IMG_FORMAT
AOM_CTRL_USE_TYPE(AV1D_GET_TILE_SIZE, unsigned int *)
#define AOM_CTRL_AV1D_GET_TILE_SIZE
+AOM_CTRL_USE_TYPE(AV1D_GET_TILE_COUNT, unsigned int *)
+#define AOM_CTRL_AV1D_GET_TILE_COUNT
AOM_CTRL_USE_TYPE(AV1D_GET_FRAME_SIZE, int *)
#define AOM_CTRL_AV1D_GET_FRAME_SIZE
AOM_CTRL_USE_TYPE(AV1_INVERT_TILE_DECODE_ORDER, int)
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index 2b8ed7b..ff77289 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -1133,6 +1133,24 @@
return AOM_CODEC_INVALID_PARAM;
}
+static aom_codec_err_t ctrl_get_tile_count(aom_codec_alg_priv_t *ctx,
+ va_list args) {
+ unsigned int *const tile_count = va_arg(args, unsigned int *);
+
+ if (tile_count) {
+ AVxWorker *const worker = &ctx->frame_workers[ctx->next_output_worker_id];
+ if (worker) {
+ FrameWorkerData *const frame_worker_data =
+ (FrameWorkerData *)worker->data1;
+ *tile_count = frame_worker_data->pbi->tile_count_minus_1 + 1;
+ return AOM_CODEC_OK;
+ } else {
+ return AOM_CODEC_ERROR;
+ }
+ }
+ return AOM_CODEC_INVALID_PARAM;
+}
+
static aom_codec_err_t ctrl_set_invert_tile_order(aom_codec_alg_priv_t *ctx,
va_list args) {
ctx->invert_tile_order = va_arg(args, int);
@@ -1299,6 +1317,7 @@
{ AV1D_GET_BIT_DEPTH, ctrl_get_bit_depth },
{ AV1D_GET_IMG_FORMAT, ctrl_get_img_format },
{ AV1D_GET_TILE_SIZE, ctrl_get_tile_size },
+ { AV1D_GET_TILE_COUNT, ctrl_get_tile_count },
{ AV1D_GET_DISPLAY_SIZE, ctrl_get_render_size },
{ AV1D_GET_FRAME_SIZE, ctrl_get_frame_size },
{ AV1_GET_ACCOUNTING, ctrl_get_accounting },
diff --git a/common/tools_common.c b/common/tools_common.c
index b74576b..2e32f61 100644
--- a/common/tools_common.c
+++ b/common/tools_common.c
@@ -485,17 +485,19 @@
// Interleaved U and V plane
const unsigned char *ubuf = img->planes[1];
const unsigned char *vbuf = img->planes[2];
+ const size_t size = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
stride = img->stride[1];
- w = aom_img_plane_width(img, 1) *
- ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
+ w = aom_img_plane_width(img, 1);
h = aom_img_plane_height(img, 1);
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
- fputc(ubuf[x], file);
- fputc(vbuf[x], file);
+ fwrite(ubuf, size, 1, file);
+ fwrite(vbuf, size, 1, file);
+ ubuf += size;
+ vbuf += size;
}
- ubuf += stride;
- vbuf += stride;
+ ubuf += (stride - w * size);
+ vbuf += (stride - w * size);
}
}
diff --git a/common/tools_common.h b/common/tools_common.h
index 458ca99..df3b62b 100644
--- a/common/tools_common.h
+++ b/common/tools_common.h
@@ -77,6 +77,13 @@
FILE_TYPE_WEBM
};
+// Used in lightfield example.
+typedef enum OUTPUT_FORMAT {
+ YUV1D, // 1D tile output for conformance test.
+ YUV, // Tile output in YUV format.
+ NV12, // Tile output in NV12 format.
+} OUTPUT_FORMAT;
+
struct FileTypeDetectionBuffer {
char buf[4];
size_t buf_read;
diff --git a/examples/lightfield_decoder.c b/examples/lightfield_decoder.c
index 2796179..23dac98 100644
--- a/examples/lightfield_decoder.c
+++ b/examples/lightfield_decoder.c
@@ -15,16 +15,13 @@
// This is an example of a simple lightfield decoder. It builds upon the
// simple_decoder.c example. It takes an input file containing the compressed
// data (in ivf format), treating it as a lightfield instead of a video; and a
-// text file with a list of tiles to decode. There is an option allowing to
-// choose the output format, and the supported formats are i420(default) and
-// nv12.
+// text file with a list of tiles to decode. There is an optional parameter
+// allowing to choose the output format, and the supported formats are
+// YUV1D(default), YUV, and NV12.
// After running the lightfield encoder, run lightfield decoder to decode a
// batch of tiles:
// examples/lightfield_decoder vase10x10.ivf vase_reference.yuv 4 tile_list.txt
-// or
-// examples/lightfield_decoder vase10x10.ivf vase_reference.yuv 4 tile_list.txt
-// 1
-// if nv12 output format is preferred.
+// 0(optional)
// The tile_list.txt is expected to be of the form:
// Frame <frame_index0>
// <image_index0> <anchor_index0> <tile_col0> <tile_row0>
@@ -51,9 +48,6 @@
static const char *exec_name;
-#define I420 0
-#define NV12 1
-
void usage_exit(void) {
fprintf(stderr,
"Usage: %s <infile> <outfile> <num_references> <tile_list> <output "
@@ -99,7 +93,8 @@
void decode_tile(aom_codec_ctx_t *codec, const unsigned char *frame,
size_t frame_size, int tr, int tc, int ref_idx,
aom_image_t *reference_images, aom_image_t *output,
- int *tile_idx, unsigned int *output_bit_depth) {
+ int *tile_idx, unsigned int *output_bit_depth,
+ aom_image_t **img_ptr, int output_format) {
aom_codec_control_(codec, AV1_SET_TILE_MODE, 1);
aom_codec_control_(codec, AV1D_EXT_TILE_DEBUG, 1);
aom_codec_control_(codec, AV1_SET_DECODE_TILE_ROW, tr);
@@ -119,6 +114,7 @@
aom_codec_iter_t iter = NULL;
aom_image_t *img = aom_codec_get_frame(codec, &iter);
if (!img) die_codec(codec, "Failed to get frame.");
+ *img_ptr = img;
// aom_img_alloc() sets bit_depth as follows:
// output->bit_depth = (fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
@@ -127,29 +123,34 @@
output->bit_depth = img->bit_depth;
*output_bit_depth = img->bit_depth;
- // read out the tile size.
- unsigned int tile_size = 0;
- if (aom_codec_control(codec, AV1D_GET_TILE_SIZE, &tile_size))
- die_codec(codec, "Failed to get the tile size");
- const unsigned int tile_width = tile_size >> 16;
- const unsigned int tile_height = tile_size & 65535;
- const uint8_t output_frame_width_in_tiles = output_frame_width / tile_width;
+ if (output_format != YUV1D) {
+ // read out the tile size.
+ unsigned int tile_size = 0;
+ if (aom_codec_control(codec, AV1D_GET_TILE_SIZE, &tile_size))
+ die_codec(codec, "Failed to get the tile size");
+ const unsigned int tile_width = tile_size >> 16;
+ const unsigned int tile_height = tile_size & 65535;
+ const uint8_t output_frame_width_in_tiles = output_frame_width / tile_width;
- // Copy the tile to the output frame.
- const int row_offset =
- (*tile_idx / output_frame_width_in_tiles) * tile_height;
- const int col_offset = (*tile_idx % output_frame_width_in_tiles) * tile_width;
+ // Copy the tile to the output frame.
+ const int row_offset =
+ (*tile_idx / output_frame_width_in_tiles) * tile_height;
+ const int col_offset =
+ (*tile_idx % output_frame_width_in_tiles) * tile_width;
- aom_img_copy_tile(img, output, row_offset, col_offset);
- (*tile_idx)++;
+ aom_img_copy_tile(img, output, row_offset, col_offset);
+ (*tile_idx)++;
+ }
}
static void img_write_to_file(const aom_image_t *img, FILE *file,
int output_format) {
- if (output_format == I420)
+ if (output_format == YUV)
aom_img_write(img, file);
- else // NV12
+ else if (output_format == NV12)
aom_img_write_nv12(img, file);
+ else
+ die("Invalid output format");
}
int main(int argc, char **argv) {
@@ -167,7 +168,7 @@
const unsigned char *frame = NULL;
int i, j;
const char *tile_list_file = NULL;
- int output_format = I420;
+ int output_format = YUV1D;
exec_name = argv[0];
if (argc < 5) die("Invalid number of arguments.");
@@ -182,6 +183,8 @@
tile_list_file = argv[4];
if (argc > 5) output_format = (int)strtol(argv[5], NULL, 0);
+ if (output_format < YUV1D || output_format > NV12)
+ die("Output format out of range [0, 2]");
info = aom_video_reader_get_info(reader);
@@ -268,12 +271,14 @@
}
printf("Read %d frames.\n", num_frames);
- // Allocate the output frame.
- aom_img_fmt_t out_fmt = ref_fmt;
- if (!CONFIG_LOWBITDEPTH) out_fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
- if (!aom_img_alloc(&output, out_fmt, output_frame_width, output_frame_height,
- 32))
- die("Failed to allocate output image.");
+ if (output_format != YUV1D) {
+ // Allocate the output frame.
+ aom_img_fmt_t out_fmt = ref_fmt;
+ if (!CONFIG_LOWBITDEPTH) out_fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
+ if (!aom_img_alloc(&output, out_fmt, output_frame_width,
+ output_frame_height, 32))
+ die("Failed to allocate output image.");
+ }
printf("Decoding tile list from file.\n");
char line[1024];
@@ -286,20 +291,21 @@
while ((fgets(line, 1024, tile_list_fptr)) != NULL) {
if (line[0] == 'F') {
- // Write out the tile list.
- if (tile_list_cnt) {
- out = &output;
- // Shift up or down if necessary
- if (output_bit_depth != 0)
- aom_shift_img(output_bit_depth, &out, &output_shifted);
- img_write_to_file(out, outfile, output_format);
- tile_list_writes++;
- }
+ if (output_format != YUV1D) {
+ // Write out the tile list.
+ if (tile_list_cnt) {
+ out = &output;
+ if (output_bit_depth != 0)
+ aom_shift_img(output_bit_depth, &out, &output_shifted);
+ img_write_to_file(out, outfile, output_format);
+ tile_list_writes++;
+ }
- tile_list_cnt++;
- tile_idx = 0;
- // Then memset the frame.
- memset(output.img_data, 0, output.sz);
+ tile_list_cnt++;
+ tile_idx = 0;
+ // Then memset the frame.
+ memset(output.img_data, 0, output.sz);
+ }
continue;
}
@@ -315,21 +321,30 @@
}
frame = frames[image_idx];
frame_size = frame_sizes[image_idx];
+
+ aom_image_t *img = NULL;
decode_tile(&codec, frame, frame_size, tr, tc, ref_idx, reference_images,
- &output, &tile_idx, &output_bit_depth);
+ &output, &tile_idx, &output_bit_depth, &img, output_format);
+ if (output_format == YUV1D) {
+ out = img;
+ if (output_bit_depth != 0)
+ aom_shift_img(output_bit_depth, &out, &output_shifted);
+ aom_img_write(out, outfile);
+ }
}
- // Write out the last tile list.
- if (tile_list_writes < tile_list_cnt) {
- out = &output;
- // Shift up or down if necessary
- if (output_bit_depth != 0)
- aom_shift_img(output_bit_depth, &out, &output_shifted);
- img_write_to_file(out, outfile, output_format);
+ if (output_format != YUV1D) {
+ // Write out the last tile list.
+ if (tile_list_writes < tile_list_cnt) {
+ out = &output;
+ if (output_bit_depth != 0)
+ aom_shift_img(output_bit_depth, &out, &output_shifted);
+ img_write_to_file(out, outfile, output_format);
+ }
}
if (output_shifted) aom_img_free(output_shifted);
- aom_img_free(&output);
+ if (output_format != YUV1D) aom_img_free(&output);
for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]);
for (int f = 0; f < num_frames; ++f) {
free(frames[f]);
@@ -342,5 +357,3 @@
return EXIT_SUCCESS;
}
-#undef I420
-#undef NV12
diff --git a/examples/lightfield_tile_list_decoder.c b/examples/lightfield_tile_list_decoder.c
index 4307efe..4aabde1 100644
--- a/examples/lightfield_tile_list_decoder.c
+++ b/examples/lightfield_tile_list_decoder.c
@@ -19,15 +19,11 @@
// lightfield ivf file, and is decodable by AV1 decoder. num_references is
// the number of anchor frames coded at the beginning of the light field file.
// num_tile_lists is the number of tile lists need to be decoded. There is an
-// option allowing to choose the output format, and the supported formats are
-// i420(default) and nv12.
+// optional parameter allowing to choose the output format, and the supported
+// formats are YUV1D(default), YUV, and NV12.
// Run lightfield tile list decoder to decode an AV1 tile list file:
// examples/lightfield_tile_list_decoder vase_tile_list.ivf vase_tile_list.yuv
-// 4 2
-// or
-// examples/lightfield_tile_list_decoder vase_tile_list.ivf vase_tile_list.yuv
-// 4 2 1
-// if nv12 output format is preferred.
+// 4 2 0(optional)
#include <stdio.h>
#include <stdlib.h>
@@ -43,9 +39,6 @@
static const char *exec_name;
-#define I420 0
-#define NV12 1
-
void usage_exit(void) {
fprintf(stderr,
"Usage: %s <infile> <outfile> <num_references> <num_tile_lists> "
@@ -54,12 +47,53 @@
exit(EXIT_FAILURE);
}
-static void img_write_to_file(const aom_image_t *img, FILE *file,
- int output_format) {
- if (output_format == I420)
- aom_img_write(img, file);
- else // NV12
- aom_img_write_nv12(img, file);
+static void write_tile_yuv1d(aom_codec_ctx_t *codec, const aom_image_t *img,
+ FILE *file) {
+ // read out the tile size.
+ unsigned int tile_size = 0;
+ if (aom_codec_control(codec, AV1D_GET_TILE_SIZE, &tile_size))
+ die_codec(codec, "Failed to get the tile size");
+ const unsigned int tile_width = tile_size >> 16;
+ const unsigned int tile_height = tile_size & 65535;
+ const uint8_t output_frame_width_in_tiles = img->d_w / tile_width;
+
+ unsigned int tile_count = 0;
+ if (aom_codec_control(codec, AV1D_GET_TILE_COUNT, &tile_count))
+ die_codec(codec, "Failed to get the tile size");
+
+ // Write tile to file.
+ const int shift = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 1 : 0;
+ unsigned int tile_idx;
+
+ for (tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
+ const int row_offset =
+ (tile_idx / output_frame_width_in_tiles) * tile_height;
+ const int col_offset =
+ (tile_idx % output_frame_width_in_tiles) * tile_width;
+ int plane;
+
+ for (plane = 0; plane < 3; ++plane) {
+ const unsigned char *buf = img->planes[plane];
+ const int stride = img->stride[plane];
+ const int roffset =
+ (plane > 0) ? row_offset >> img->y_chroma_shift : row_offset;
+ const int coffset =
+ (plane > 0) ? col_offset >> img->x_chroma_shift : col_offset;
+ const int w = (plane > 0) ? ((tile_width >> img->x_chroma_shift) << shift)
+ : (tile_width << shift);
+ const int h =
+ (plane > 0) ? (tile_height >> img->y_chroma_shift) : tile_height;
+ int y;
+
+ // col offset needs to be adjusted for HBD.
+ buf += roffset * stride + (coffset << shift);
+
+ for (y = 0; y < h; ++y) {
+ fwrite(buf, 1, w, file);
+ buf += stride;
+ }
+ }
+ }
}
int main(int argc, char **argv) {
@@ -73,7 +107,7 @@
aom_image_t reference_images[MAX_EXTERNAL_REFERENCES];
size_t frame_size = 0;
const unsigned char *frame = NULL;
- int output_format = I420;
+ int output_format = YUV1D;
int i, j, n;
exec_name = argv[0];
@@ -90,6 +124,8 @@
num_tile_lists = (int)strtol(argv[4], NULL, 0);
if (argc > 5) output_format = (int)strtol(argv[5], NULL, 0);
+ if (output_format < YUV1D || output_format > NV12)
+ die("Output format out of range [0, 2]");
info = aom_video_reader_get_info(reader);
@@ -169,7 +205,16 @@
die_codec(&codec, "Failed to decode the tile list.");
aom_codec_iter_t iter = NULL;
aom_image_t *img = aom_codec_get_frame(&codec, &iter);
- img_write_to_file(img, outfile, output_format);
+ if (!img) die_codec(&codec, "Failed to get frame.");
+
+ if (output_format == YUV1D)
+ // write the tile to the output file in 1D format.
+ write_tile_yuv1d(&codec, img, outfile);
+ else if (output_format == YUV)
+ aom_img_write(img, outfile);
+ else
+ // NV12 output format
+ aom_img_write_nv12(img, outfile);
}
for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]);
@@ -179,5 +224,3 @@
return EXIT_SUCCESS;
}
-#undef I420
-#undef NV12