lightfield_tile_list_decoder.c (8632B)
1 /* 2 * Copyright (c) 2018, Alliance for Open Media. All rights reserved. 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 // Lightfield Tile List Decoder 13 // ============================ 14 // 15 // This is a lightfield tile list decoder example. It takes an input file that 16 // contains the anchor frames that are references of the coded tiles, the camera 17 // frame header, and tile list OBUs that include the tile information and the 18 // compressed tile data. This input file is reconstructed from the encoded 19 // lightfield ivf file, and is decodable by AV1 decoder. num_references is 20 // the number of anchor frames coded at the beginning of the light field file. 21 // num_tile_lists is the number of tile lists need to be decoded. There is an 22 // optional parameter allowing to choose the output format, and the supported 23 // formats are YUV1D(default), YUV, and NV12. 24 // Run lightfield tile list decoder to decode an AV1 tile list file: 25 // examples/lightfield_tile_list_decoder vase_tile_list.ivf vase_tile_list.yuv 26 // 4 2 0(optional) 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <assert.h> 32 33 #include "aom/aom_decoder.h" 34 #include "aom/aomdx.h" 35 #include "aom_scale/yv12config.h" 36 #include "av1/common/enums.h" 37 #include "common/tools_common.h" 38 #include "common/video_reader.h" 39 40 enum { 41 YUV1D, // 1D tile output for conformance test. 42 YUV, // Tile output in YUV format. 43 NV12, // Tile output in NV12 format. 44 } UENUM1BYTE(OUTPUT_FORMAT); 45 46 static const char *exec_name; 47 48 void usage_exit(void) { 49 fprintf(stderr, 50 "Usage: %s <infile> <outfile> <num_references> <num_tile_lists> " 51 "<output format(optional)>\n", 52 exec_name); 53 exit(EXIT_FAILURE); 54 } 55 56 static void write_tile_yuv1d(aom_codec_ctx_t *codec, const aom_image_t *img, 57 FILE *file) { 58 // read out the tile size. 59 unsigned int tile_size = 0; 60 if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_SIZE, &tile_size)) 61 die_codec(codec, "Failed to get the tile size"); 62 const unsigned int tile_width = tile_size >> 16; 63 const unsigned int tile_height = tile_size & 65535; 64 const uint32_t output_frame_width_in_tiles = img->d_w / tile_width; 65 66 unsigned int tile_count = 0; 67 if (AOM_CODEC_CONTROL_TYPECHECKED(codec, AV1D_GET_TILE_COUNT, &tile_count)) 68 die_codec(codec, "Failed to get the tile size"); 69 70 // Write tile to file. 71 const int shift = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 1 : 0; 72 unsigned int tile_idx; 73 74 for (tile_idx = 0; tile_idx < tile_count; ++tile_idx) { 75 const int row_offset = 76 (tile_idx / output_frame_width_in_tiles) * tile_height; 77 const int col_offset = 78 (tile_idx % output_frame_width_in_tiles) * tile_width; 79 int plane; 80 81 for (plane = 0; plane < 3; ++plane) { 82 const unsigned char *buf = img->planes[plane]; 83 const int stride = img->stride[plane]; 84 const int roffset = 85 (plane > 0) ? row_offset >> img->y_chroma_shift : row_offset; 86 const int coffset = 87 (plane > 0) ? col_offset >> img->x_chroma_shift : col_offset; 88 const int w = (plane > 0) ? ((tile_width >> img->x_chroma_shift) << shift) 89 : (tile_width << shift); 90 const int h = 91 (plane > 0) ? (tile_height >> img->y_chroma_shift) : tile_height; 92 int y; 93 94 // col offset needs to be adjusted for HBD. 95 buf += roffset * stride + (coffset << shift); 96 97 for (y = 0; y < h; ++y) { 98 fwrite(buf, 1, w, file); 99 buf += stride; 100 } 101 } 102 } 103 } 104 105 int main(int argc, char **argv) { 106 FILE *outfile = NULL; 107 AvxVideoReader *reader = NULL; 108 const AvxVideoInfo *info = NULL; 109 int num_references; 110 int num_tile_lists; 111 aom_image_t reference_images[MAX_EXTERNAL_REFERENCES]; 112 size_t frame_size = 0; 113 const unsigned char *frame = NULL; 114 int output_format = YUV1D; 115 int i, j, n; 116 117 exec_name = argv[0]; 118 119 if (argc < 5) die("Invalid number of arguments."); 120 121 reader = aom_video_reader_open(argv[1]); 122 if (!reader) die("Failed to open %s for reading.", argv[1]); 123 124 if (!(outfile = fopen(argv[2], "wb"))) 125 die("Failed to open %s for writing.", argv[2]); 126 127 num_references = (int)strtol(argv[3], NULL, 0); 128 num_tile_lists = (int)strtol(argv[4], NULL, 0); 129 130 if (argc > 5) output_format = (int)strtol(argv[5], NULL, 0); 131 if (output_format < YUV1D || output_format > NV12) 132 die("Output format out of range [0, 2]"); 133 134 info = aom_video_reader_get_info(reader); 135 136 aom_codec_iface_t *decoder = get_aom_decoder_by_fourcc(info->codec_fourcc); 137 if (!decoder) die("Unknown input codec."); 138 printf("Using %s\n", aom_codec_iface_name(decoder)); 139 140 aom_codec_ctx_t codec; 141 if (aom_codec_dec_init(&codec, decoder, NULL, 0)) 142 die("Failed to initialize decoder."); 143 144 if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_IS_ANNEXB, 145 info->is_annexb)) { 146 die_codec(&codec, "Failed to set annex b status"); 147 } 148 149 // Decode anchor frames. 150 AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 0); 151 for (i = 0; i < num_references; ++i) { 152 aom_video_reader_read_frame(reader); 153 frame = aom_video_reader_get_frame(reader, &frame_size); 154 if (aom_codec_decode(&codec, frame, frame_size, NULL)) 155 die_codec(&codec, "Failed to decode frame."); 156 157 if (i == 0) { 158 aom_img_fmt_t ref_fmt = 0; 159 if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_IMG_FORMAT, &ref_fmt)) 160 die_codec(&codec, "Failed to get the image format"); 161 162 int frame_res[2]; 163 if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_GET_FRAME_SIZE, frame_res)) 164 die_codec(&codec, "Failed to get the image frame size"); 165 166 // Allocate memory to store decoded references. Allocate memory with the 167 // border so that it can be used as a reference. 168 for (j = 0; j < num_references; j++) { 169 unsigned int border = AOM_DEC_BORDER_IN_PIXELS; 170 if (!aom_img_alloc_with_border(&reference_images[j], ref_fmt, 171 frame_res[0], frame_res[1], 32, 8, 172 border)) { 173 fatal("Failed to allocate references."); 174 } 175 } 176 } 177 178 if (AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_COPY_NEW_FRAME_IMAGE, 179 &reference_images[i])) 180 die_codec(&codec, "Failed to copy decoded reference frame"); 181 182 aom_codec_iter_t iter = NULL; 183 aom_image_t *img = NULL; 184 while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) { 185 char name[1024]; 186 snprintf(name, sizeof(name), "ref_%d.yuv", i); 187 printf("writing ref image to %s, %u, %u\n", name, img->d_w, img->d_h); 188 FILE *ref_file = fopen(name, "wb"); 189 aom_img_write(img, ref_file); 190 fclose(ref_file); 191 } 192 } 193 194 // Decode the lightfield. 195 AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1_SET_TILE_MODE, 1); 196 197 // Set external references. 198 av1_ext_ref_frame_t set_ext_ref = { &reference_images[0], num_references }; 199 AOM_CODEC_CONTROL_TYPECHECKED(&codec, AV1D_SET_EXT_REF_PTR, &set_ext_ref); 200 // Must decode the camera frame header first. 201 aom_video_reader_read_frame(reader); 202 frame = aom_video_reader_get_frame(reader, &frame_size); 203 if (aom_codec_decode(&codec, frame, frame_size, NULL)) 204 die_codec(&codec, "Failed to decode the frame."); 205 // Decode tile lists one by one. 206 for (n = 0; n < num_tile_lists; n++) { 207 aom_video_reader_read_frame(reader); 208 frame = aom_video_reader_get_frame(reader, &frame_size); 209 210 if (aom_codec_decode(&codec, frame, frame_size, NULL)) 211 die_codec(&codec, "Failed to decode the tile list."); 212 aom_codec_iter_t iter = NULL; 213 aom_image_t *img = aom_codec_get_frame(&codec, &iter); 214 if (!img) die_codec(&codec, "Failed to get frame."); 215 216 if (output_format == YUV1D) 217 // write the tile to the output file in 1D format. 218 write_tile_yuv1d(&codec, img, outfile); 219 else if (output_format == YUV) 220 aom_img_write(img, outfile); 221 else 222 // NV12 output format 223 aom_img_write_nv12(img, outfile); 224 } 225 226 for (i = 0; i < num_references; i++) aom_img_free(&reference_images[i]); 227 if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); 228 aom_video_reader_close(reader); 229 fclose(outfile); 230 231 return EXIT_SUCCESS; 232 }