ext-tile: support NV12 output format cherry-pick of ba7dfd5d37936d2a0fce94973325b41e3a6ecc15 from master As approved in WG meeting, this patch added support for NV12 output format. BUG=aomedia:2047 Change-Id: Ie38315cdcf6426cb222c53401f7e007bafb4d013
diff --git a/common/tools_common.c b/common/tools_common.c index 11d343b..5de19dc 100644 --- a/common/tools_common.c +++ b/common/tools_common.c
@@ -462,3 +462,37 @@ *img_ptr = img_shifted; } } + +// Related to I420, NV12 format has one luma "luminance" plane Y and one plane +// with U and V values interleaved. +void aom_img_write_nv12(const aom_image_t *img, FILE *file) { + // Y plane + const unsigned char *buf = img->planes[0]; + int stride = img->stride[0]; + int w = aom_img_plane_width(img, 0) * + ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); + int h = aom_img_plane_height(img, 0); + int x, y; + + for (y = 0; y < h; ++y) { + fwrite(buf, 1, w, file); + buf += stride; + } + + // Interleaved U and V plane + const unsigned char *ubuf = img->planes[1]; + const unsigned char *vbuf = img->planes[2]; + stride = img->stride[1]; + w = aom_img_plane_width(img, 1) * + ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 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); + } + ubuf += stride; + vbuf += stride; + } +}
diff --git a/common/tools_common.h b/common/tools_common.h index 31b1322..d862bb04 100644 --- a/common/tools_common.h +++ b/common/tools_common.h
@@ -158,6 +158,9 @@ aom_image_t **img_shifted_ptr); void aom_img_truncate_16_to_8(aom_image_t *dst, aom_image_t *src); +// Output in NV12 format. +void aom_img_write_nv12(const aom_image_t *img, FILE *file); + #ifdef __cplusplus } /* extern "C" */ #endif
diff --git a/examples/lightfield_decoder.c b/examples/lightfield_decoder.c index 8cc29de..b2bf5dc 100644 --- a/examples/lightfield_decoder.c +++ b/examples/lightfield_decoder.c
@@ -15,11 +15,16 @@ // 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. +// 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. // 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. // The tile_list.txt is expected to be of the form: // Frame <frame_index0> // <image_index0> <anchor_index0> <tile_col0> <tile_row0> @@ -47,8 +52,13 @@ 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>\n", + fprintf(stderr, + "Usage: %s <infile> <outfile> <num_references> <tile_list> <output " + "format(optional)>\n", exec_name); exit(EXIT_FAILURE); } @@ -135,6 +145,14 @@ (*tile_idx)++; } +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); +} + int main(int argc, char **argv) { FILE *outfile = NULL; aom_codec_ctx_t codec; @@ -150,9 +168,10 @@ const unsigned char *frame = NULL; int i, j; const char *tile_list_file = NULL; + int output_format = I420; exec_name = argv[0]; - if (argc != 5) die("Invalid number of arguments."); + if (argc < 5) die("Invalid number of arguments."); reader = aom_video_reader_open(argv[1]); if (!reader) die("Failed to open %s for reading.", argv[1]); @@ -163,6 +182,8 @@ num_references = (int)strtol(argv[3], NULL, 0); tile_list_file = argv[4]; + if (argc > 5) output_format = (int)strtol(argv[5], NULL, 0); + info = aom_video_reader_get_info(reader); decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); @@ -272,7 +293,7 @@ // Shift up or down if necessary if (output_bit_depth != 0) aom_shift_img(output_bit_depth, &out, &output_shifted); - aom_img_write(out, outfile); + img_write_to_file(out, outfile, output_format); tile_list_writes++; } @@ -305,7 +326,7 @@ // Shift up or down if necessary if (output_bit_depth != 0) aom_shift_img(output_bit_depth, &out, &output_shifted); - aom_img_write(out, outfile); + img_write_to_file(out, outfile, output_format); } if (output_shifted) aom_img_free(output_shifted); @@ -322,3 +343,5 @@ return EXIT_SUCCESS; } +#undef I420 +#undef NV12
diff --git a/examples/lightfield_tile_list_decoder.c b/examples/lightfield_tile_list_decoder.c index 4b5ed39..d51c0d1 100644 --- a/examples/lightfield_tile_list_decoder.c +++ b/examples/lightfield_tile_list_decoder.c
@@ -16,12 +16,18 @@ // contains the anchor frames that are references of the coded tiles, the camera // frame header, and tile list OBUs that include the tile information and the // compressed tile data. This input file is reconstructed from the encoded -// lightfield ivf file, and is decodable by AV1 decoder. The lf_width and -// lf_height arguments are the number of lightfield images in each dimension. -// The lf_blocksize determines the number of reference images used. +// 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. // 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 -// 10 10 5 2 +// 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. #include <stdio.h> #include <stdlib.h> @@ -38,13 +44,25 @@ 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>\n", + "Usage: %s <infile> <outfile> <num_references> <num_tile_lists> " + "<output format(optional)>\n", exec_name); 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); +} + int main(int argc, char **argv) { FILE *outfile = NULL; aom_codec_ctx_t codec; @@ -56,11 +74,12 @@ aom_image_t reference_images[MAX_EXTERNAL_REFERENCES]; size_t frame_size = 0; const unsigned char *frame = NULL; + int output_format = I420; int i, j, n; exec_name = argv[0]; - if (argc != 5) die("Invalid number of arguments."); + if (argc < 5) die("Invalid number of arguments."); reader = aom_video_reader_open(argv[1]); if (!reader) die("Failed to open %s for reading.", argv[1]); @@ -71,6 +90,8 @@ num_references = (int)strtol(argv[3], NULL, 0); num_tile_lists = (int)strtol(argv[4], NULL, 0); + if (argc > 5) output_format = (int)strtol(argv[5], NULL, 0); + info = aom_video_reader_get_info(reader); decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); @@ -149,7 +170,7 @@ 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); - aom_img_write(img, outfile); + img_write_to_file(img, outfile, output_format); } for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]); @@ -159,3 +180,5 @@ return EXIT_SUCCESS; } +#undef I420 +#undef NV12