ext-tile: add back the 1D tile output format cherry-pick of 2ff32c1c66ffb5efd02630464ee99294aacae427 from master 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 ed17b73..a6448e1 100644 --- a/aom/aomdx.h +++ b/aom/aomdx.h
@@ -125,6 +125,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 @@ -254,6 +257,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 62649d7..0ce82ff 100644 --- a/av1/av1_dx_iface.c +++ b/av1/av1_dx_iface.c
@@ -1088,6 +1088,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); @@ -1247,6 +1265,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 5de19dc..419513c 100644 --- a/common/tools_common.c +++ b/common/tools_common.c
@@ -482,17 +482,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 d862bb04..da53ecc 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 b2bf5dc..1036790 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> @@ -52,9 +49,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 " @@ -100,7 +94,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); @@ -120,6 +115,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; @@ -128,29 +124,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) { @@ -168,7 +169,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."); @@ -183,6 +184,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); @@ -269,12 +272,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]; @@ -287,20 +292,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; } @@ -316,21 +322,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]); @@ -343,5 +358,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 d51c0d1..688415a 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> @@ -44,9 +40,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> " @@ -55,12 +48,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) { @@ -74,7 +108,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]; @@ -91,6 +125,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); @@ -170,7 +206,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]); @@ -180,5 +225,3 @@ return EXIT_SUCCESS; } -#undef I420 -#undef NV12