ext-tile: support NV12 output format
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 ef5e9a7..b74576b 100644
--- a/common/tools_common.c
+++ b/common/tools_common.c
@@ -465,3 +465,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 c981361..458ca99 100644
--- a/common/tools_common.h
+++ b/common/tools_common.h
@@ -159,6 +159,9 @@
aom_image_t **img_shifted_ptr);
void aom_img_truncate_16_to_8(aom_image_t *dst, const 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 b57accb..2796179 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>
@@ -46,8 +51,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);
}
@@ -134,6 +144,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;
@@ -149,9 +167,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]);
@@ -162,6 +181,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);
@@ -271,7 +292,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++;
}
@@ -304,7 +325,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);
@@ -321,3 +342,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 d8f244f..4307efe 100644
--- a/examples/lightfield_tile_list_decoder.c
+++ b/examples/lightfield_tile_list_decoder.c
@@ -18,10 +18,16 @@
// compressed tile data. This input file is reconstructed from the encoded
// 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.
+// 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
// 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>
@@ -37,13 +43,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;
@@ -55,11 +73,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]);
@@ -70,6 +89,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);
@@ -148,7 +169,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]);
@@ -158,3 +179,5 @@
return EXIT_SUCCESS;
}
+#undef I420
+#undef NV12