AOMedia Codec SDK
lightfield_bitstream_parsing
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 Bitstream Parsing
13 // ============================
14 //
15 // This is an lightfield bitstream parsing example. It takes an input file
16 // containing the whole compressed lightfield bitstream(ivf file), and parses it
17 // and constructs and outputs a new bitstream that can be decoded by an AV1
18 // decoder. The output bitstream contains tile list OBUs. The lf_width and
19 // lf_height arguments are the number of lightfield images in each dimension.
20 // The lf_blocksize determines the number of reference images used.
21 // After running the lightfield encoder, run lightfield bitstream parsing:
22 // examples/lightfield_bitstream_parsing vase10x10.ivf vase_tile_list.ivf 10 10
23 // 5
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "aom/aom_decoder.h"
30 #include "aom/aom_encoder.h"
31 #include "aom/aom_integer.h"
32 #include "aom/aomdx.h"
33 #include "aom_dsp/bitwriter_buffer.h"
34 #include "common/tools_common.h"
35 #include "common/video_reader.h"
36 #include "common/video_writer.h"
37 
38 static const char *exec_name;
39 
40 void usage_exit(void) {
41  fprintf(
42  stderr,
43  "Usage: %s <infile> <outfile> <lf_width> <lf_height> <lf_blocksize> \n",
44  exec_name);
45  exit(EXIT_FAILURE);
46 }
47 
48 #define ALIGN_POWER_OF_TWO(value, n) \
49  (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
50 
51 // SB size: 64x64
52 const uint8_t output_frame_width_in_tiles_minus_1 = 512 / 64 - 1;
53 const uint8_t output_frame_height_in_tiles_minus_1 = 512 / 64 - 1;
54 
55 // Spec:
56 // typedef struct {
57 // uint8_t anchor_frame_idx;
58 // uint8_t tile_row;
59 // uint8_t tile_col;
60 // uint16_t coded_tile_data_size_minus_1;
61 // uint8_t *coded_tile_data;
62 // } TILE_LIST_ENTRY;
63 
64 // Tile list entry provided by the application
65 typedef struct {
66  int image_idx;
67  int reference_idx;
68  int tile_col;
69  int tile_row;
70 } TILE_LIST_INFO;
71 
72 // M references: 0 - M-1; N images(including references): 0 - N-1;
73 // Note: order the image index incrementally, so that we only go through the
74 // bitstream once to construct the tile list.
75 const int num_tile_lists = 2;
76 const uint16_t tile_count_minus_1 = 9 - 1;
77 const TILE_LIST_INFO tile_list[2][9] = {
78  { { 16, 0, 4, 5 },
79  { 83, 3, 13, 2 },
80  { 57, 2, 2, 6 },
81  { 31, 1, 11, 5 },
82  { 2, 0, 7, 4 },
83  { 77, 3, 9, 9 },
84  { 49, 1, 0, 1 },
85  { 6, 0, 3, 10 },
86  { 63, 2, 5, 8 } },
87  { { 65, 2, 11, 1 },
88  { 42, 1, 3, 7 },
89  { 88, 3, 8, 4 },
90  { 76, 3, 1, 15 },
91  { 1, 0, 2, 2 },
92  { 19, 0, 5, 6 },
93  { 60, 2, 4, 0 },
94  { 25, 1, 11, 15 },
95  { 50, 2, 5, 4 } },
96 };
97 
98 int main(int argc, char **argv) {
99  aom_codec_ctx_t codec;
100  AvxVideoReader *reader = NULL;
101  AvxVideoWriter *writer = NULL;
102  const AvxInterface *decoder = NULL;
103  const AvxVideoInfo *info = NULL;
104  const char *lf_width_arg;
105  const char *lf_height_arg;
106  const char *lf_blocksize_arg;
107  int width, height;
108  int lf_width, lf_height;
109  int lf_blocksize;
110  int u_blocks, v_blocks;
111  int n, i;
112  aom_codec_pts_t pts;
113 
114  exec_name = argv[0];
115  if (argc != 6) die("Invalid number of arguments.");
116 
117  reader = aom_video_reader_open(argv[1]);
118  if (!reader) die("Failed to open %s for reading.", argv[1]);
119 
120  lf_width_arg = argv[3];
121  lf_height_arg = argv[4];
122  lf_blocksize_arg = argv[5];
123 
124  lf_width = (int)strtol(lf_width_arg, NULL, 0);
125  lf_height = (int)strtol(lf_height_arg, NULL, 0);
126  lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0);
127 
128  info = aom_video_reader_get_info(reader);
129  width = info->frame_width;
130  height = info->frame_height;
131 
132  // The writer to write out ivf file in tile list OBU, which can be decoded by
133  // AV1 decoder.
134  writer = aom_video_writer_open(argv[2], kContainerIVF, info);
135  if (!writer) die("Failed to open %s for writing", argv[2]);
136 
137  decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
138  if (!decoder) die("Unknown input codec.");
139  printf("Using %s\n", aom_codec_iface_name(decoder->codec_interface()));
140 
141  if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
142  die_codec(&codec, "Failed to initialize decoder.");
143 
144  // Decode anchor frames.
146 
147  // How many anchor frames we have.
148  u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize;
149  v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize;
150 
151  int num_references = v_blocks * u_blocks;
152  for (i = 0; i < num_references; ++i) {
153  aom_video_reader_read_frame(reader);
154 
155  size_t frame_size = 0;
156  const unsigned char *frame =
157  aom_video_reader_get_frame(reader, &frame_size);
158  pts = (aom_codec_pts_t)aom_video_reader_get_frame_pts(reader);
159 
160  // Copy references bitstream directly.
161  if (!aom_video_writer_write_frame(writer, frame, frame_size, pts))
162  die_codec(&codec, "Failed to copy compressed anchor frame.");
163 
164  if (aom_codec_decode(&codec, frame, frame_size, NULL))
165  die_codec(&codec, "Failed to decode frame.");
166  }
167 
168  // Decode camera frames.
171 
172  FILE *infile = aom_video_reader_get_file(reader);
173  // Record the offset of the first camera image.
174  const FileOffset camera_frame_pos = ftello(infile);
175 
176  // Read out the first camera frame.
177  aom_video_reader_read_frame(reader);
178 
179  // Copy first camera frame for getting camera frame header. This is done
180  // only once.
181  {
182  size_t frame_size = 0;
183  const unsigned char *frame =
184  aom_video_reader_get_frame(reader, &frame_size);
185  pts = (aom_codec_pts_t)aom_video_reader_get_frame_pts(reader);
186  aom_tile_data frame_header_info = { 0, NULL, 0 };
187 
188  // Need to decode frame header to get camera frame header info. So, here
189  // decoding 1 tile is enough.
191  aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, 0);
192 
193  aom_codec_err_t aom_status =
194  aom_codec_decode(&codec, frame, frame_size, NULL);
195  if (aom_status) die_codec(&codec, "Failed to decode tile.");
196 
197  aom_codec_control_(&codec, AV1D_GET_FRAME_HEADER_INFO, &frame_header_info);
198 
199  size_t obu_size_offset =
200  (uint8_t *)frame_header_info.coded_tile_data - frame;
201  size_t length_field_size = frame_header_info.coded_tile_data_size;
202  // Remove ext-tile tile info.
203  uint32_t frame_header_size = (uint32_t)frame_header_info.extra_size - 1;
204  size_t bytes_to_copy =
205  obu_size_offset + length_field_size + frame_header_size;
206 
207  unsigned char *frame_hdr_buf = (unsigned char *)malloc(bytes_to_copy);
208  if (frame_hdr_buf == NULL)
209  die_codec(&codec, "Failed to allocate frame header buffer.");
210 
211  memcpy(frame_hdr_buf, frame, bytes_to_copy);
212 
213  // Update frame header OBU size.
214  size_t bytes_written = 0;
215  if (aom_uleb_encode_fixed_size(
216  frame_header_size, length_field_size, length_field_size,
217  frame_hdr_buf + obu_size_offset, &bytes_written))
218  die_codec(&codec, "Failed to encode the tile list obu size.");
219 
220  // Copy camera frame header bitstream.
221  if (!aom_video_writer_write_frame(writer, frame_hdr_buf, bytes_to_copy,
222  pts))
223  die_codec(&codec, "Failed to copy compressed camera frame header.");
224  }
225 
226  // Allocate a buffer to store tile list bitstream. Image format
227  // AOM_IMG_FMT_I420.
228  size_t data_sz =
229  ALIGN_POWER_OF_TWO(width, 5) * ALIGN_POWER_OF_TWO(height, 5) * 12 / 8;
230  unsigned char *tl_buf = (unsigned char *)malloc(data_sz);
231  if (tl_buf == NULL) die_codec(&codec, "Failed to allocate tile list buffer.");
232 
233  aom_codec_pts_t tl_pts = pts;
234 
235  // Process 1 tile list.
236  for (n = 0; n < num_tile_lists; n++) {
237  unsigned char *tl = tl_buf;
238  struct aom_write_bit_buffer wb = { tl, 0 };
239  unsigned char *saved_obu_size_loc = NULL;
240  uint32_t tile_list_obu_header_size = 0;
241  uint32_t tile_list_obu_size = 0;
242 
243  // Write the tile list OBU header that is 1 byte long.
244  aom_wb_write_literal(&wb, 0, 1); // forbidden bit.
245  aom_wb_write_literal(&wb, 8, 4); // tile list OBU: "1000"
246  aom_wb_write_literal(&wb, 0, 1); // obu_extension = 0
247  aom_wb_write_literal(&wb, 1, 1); // obu_has_size_field
248  aom_wb_write_literal(&wb, 0, 1); // reserved
249  tl++;
250  tile_list_obu_header_size++;
251 
252  // Write the OBU size using a fixed length_field_size of 4 bytes.
253  saved_obu_size_loc = tl;
254  aom_wb_write_literal(&wb, 0, 32);
255  tl += 4;
256  tile_list_obu_header_size += 4;
257 
258  // write_tile_list_obu()
259  aom_wb_write_literal(&wb, output_frame_width_in_tiles_minus_1, 8);
260  aom_wb_write_literal(&wb, output_frame_height_in_tiles_minus_1, 8);
261  aom_wb_write_literal(&wb, tile_count_minus_1, 16);
262  tl += 4;
263  tile_list_obu_size += 4;
264 
265  // Write each tile's data
266  for (i = 0; i <= tile_count_minus_1; i++) {
267  aom_tile_data tile_data = { 0, NULL, 0 };
268 
269  int image_idx = tile_list[n][i].image_idx;
270  int ref_idx = tile_list[n][i].reference_idx;
271  int tc = tile_list[n][i].tile_col;
272  int tr = tile_list[n][i].tile_row;
273  int frame_cnt = -1;
274 
275  // Reset bit writer to the right location.
276  wb.bit_buffer = tl;
277  wb.bit_offset = 0;
278 
279  // Seek to the first camera image.
280  fseeko(infile, camera_frame_pos, SEEK_SET);
281 
282  // Read out the camera image
283  while (frame_cnt != image_idx) {
284  aom_video_reader_read_frame(reader);
285  frame_cnt++;
286  }
287 
288  size_t frame_size = 0;
289  const unsigned char *frame =
290  aom_video_reader_get_frame(reader, &frame_size);
291 
293  aom_codec_control_(&codec, AV1_SET_DECODE_TILE_COL, tc);
294 
295  aom_codec_err_t aom_status =
296  aom_codec_decode(&codec, frame, frame_size, NULL);
297  if (aom_status) die_codec(&codec, "Failed to decode tile.");
298 
299  aom_codec_control_(&codec, AV1D_GET_TILE_DATA, &tile_data);
300 
301  // Copy over tile info.
302  // uint8_t anchor_frame_idx;
303  // uint8_t tile_row;
304  // uint8_t tile_col;
305  // uint16_t coded_tile_data_size_minus_1;
306  // uint8_t *coded_tile_data;
307  uint32_t tile_info_bytes = 5;
308  aom_wb_write_literal(&wb, ref_idx, 8);
309  aom_wb_write_literal(&wb, tr, 8);
310  aom_wb_write_literal(&wb, tc, 8);
311  aom_wb_write_literal(&wb, (int)tile_data.coded_tile_data_size - 1, 16);
312  tl += tile_info_bytes;
313 
314  memcpy(tl, (uint8_t *)tile_data.coded_tile_data,
315  tile_data.coded_tile_data_size);
316  tl += tile_data.coded_tile_data_size;
317 
318  tile_list_obu_size +=
319  tile_info_bytes + (uint32_t)tile_data.coded_tile_data_size;
320  }
321 
322  // Write tile list OBU size.
323  size_t bytes_written = 0;
324  if (aom_uleb_encode_fixed_size(tile_list_obu_size, 4, 4, saved_obu_size_loc,
325  &bytes_written))
326  die_codec(&codec, "Failed to encode the tile list obu size.");
327 
328  // Copy the tile list.
329  if (!aom_video_writer_write_frame(
330  writer, tl_buf, tile_list_obu_header_size + tile_list_obu_size,
331  tl_pts))
332  die_codec(&codec, "Failed to copy compressed tile list.");
333 
334  tl_pts++;
335  }
336 
337  free(tl_buf);
338  if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
339  aom_video_writer_close(writer);
340  aom_video_reader_close(reader);
341 
342  return EXIT_SUCCESS;
343 }
Definition: aomdx.h:175
Describes the encoder algorithm interface to applications.
int64_t aom_codec_pts_t
Time Stamp Type.
Definition: aom_encoder.h:94
Definition: aomdx.h:179
Codec context structure.
Definition: aom_codec.h:204
Describes the decoder algorithm interface to applications.
Structure to hold a tile's start address and size in the bitstream.
Definition: aomdx.h:67
aom_codec_err_t aom_codec_decode(aom_codec_ctx_t *ctx, const uint8_t *data, size_t data_sz, void *user_priv)
Decode data.
aom_codec_err_t aom_codec_control_(aom_codec_ctx_t *ctx, int ctrl_id,...)
Control algorithm.
#define aom_codec_dec_init(ctx, iface, cfg, flags)
Convenience macro for aom_codec_dec_init_ver()
Definition: aom_decoder.h:142
const char * aom_codec_iface_name(aom_codec_iface_t *iface)
Return the name for a given interface.
aom_codec_err_t aom_codec_destroy(aom_codec_ctx_t *ctx)
Destroy a codec instance.
Definition: aomdx.h:188
size_t extra_size
Definition: aomdx.h:73
Definition: aomdx.h:165
size_t coded_tile_data_size
Definition: aomdx.h:69
Definition: aomdx.h:171
const void * coded_tile_data
Definition: aomdx.h:71
aom_codec_err_t
Algorithm return codes.
Definition: aom_codec.h:101
Provides definitions for using AOM or AV1 within the aom Decoder interface.