tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lightfield_encoder.c (21204B)


      1 /*
      2 * Copyright (c) 2017, 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 Encoder
     13 // ==================
     14 //
     15 // This is an example of a simple lightfield encoder.  It builds upon the
     16 // twopass_encoder.c example. It takes an input file in YV12 format,
     17 // treating it as a planar lightfield instead of a video. The img_width
     18 // and img_height arguments are the dimensions of the lightfield images,
     19 // while the lf_width and lf_height arguments are the number of
     20 // lightfield images in each dimension. The lf_blocksize determines the
     21 // number of reference images used for MCP. For example, 5 means that there
     22 // is a reference image for every 5x5 lightfield image block. All images
     23 // within a block will use the center image in that block as the reference
     24 // image for MCP.
     25 // Run "make test" to download lightfield test data: vase10x10.yuv.
     26 // Run lightfield encoder to encode whole lightfield:
     27 // examples/lightfield_encoder 1024 1024 vase10x10.yuv vase10x10.ivf 10 10 5
     28 
     29 // Note: In bitstream.c and encoder.c, define EXT_TILE_DEBUG as 1 will print
     30 // out the uncompressed header and the frame contexts, which can be used to
     31 // test the bit exactness of the headers and the frame contexts for large scale
     32 // tile coded frames.
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 
     38 #include "aom/aom_encoder.h"
     39 #include "aom/aomcx.h"
     40 #include "aom_scale/yv12config.h"
     41 #include "av1/common/enums.h"
     42 #include "av1/encoder/encoder_utils.h"
     43 #include "common/tools_common.h"
     44 #include "common/video_writer.h"
     45 
     46 static const char *exec_name;
     47 
     48 void usage_exit(void) {
     49  fprintf(stderr,
     50          "Usage: %s <img_width> <img_height> <infile> <outfile> "
     51          "<lf_width> <lf_height> <lf_blocksize>\n",
     52          exec_name);
     53  exit(EXIT_FAILURE);
     54 }
     55 
     56 static int img_size_bytes(aom_image_t *img) {
     57  int image_size_bytes = 0;
     58  int plane;
     59  for (plane = 0; plane < 3; ++plane) {
     60    const int w = aom_img_plane_width(img, plane) *
     61                  ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
     62    const int h = aom_img_plane_height(img, plane);
     63    image_size_bytes += w * h;
     64  }
     65  return image_size_bytes;
     66 }
     67 
     68 static int get_frame_stats(aom_codec_ctx_t *ctx, const aom_image_t *img,
     69                           aom_codec_pts_t pts, unsigned int duration,
     70                           aom_enc_frame_flags_t flags,
     71                           aom_fixed_buf_t *stats) {
     72  int got_pkts = 0;
     73  aom_codec_iter_t iter = NULL;
     74  const aom_codec_cx_pkt_t *pkt = NULL;
     75  const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags);
     76  if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to get frame stats.");
     77 
     78  while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) {
     79    got_pkts = 1;
     80 
     81    if (pkt->kind == AOM_CODEC_STATS_PKT) {
     82      const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
     83      const size_t pkt_size = pkt->data.twopass_stats.sz;
     84      stats->buf = realloc(stats->buf, stats->sz + pkt_size);
     85      if (!stats->buf) die("Failed to allocate frame stats buffer.");
     86      memcpy((uint8_t *)stats->buf + stats->sz, pkt_buf, pkt_size);
     87      stats->sz += pkt_size;
     88    }
     89  }
     90 
     91  return got_pkts;
     92 }
     93 
     94 static int encode_frame(aom_codec_ctx_t *ctx, const aom_image_t *img,
     95                        aom_codec_pts_t pts, unsigned int duration,
     96                        aom_enc_frame_flags_t flags, AvxVideoWriter *writer) {
     97  int got_pkts = 0;
     98  aom_codec_iter_t iter = NULL;
     99  const aom_codec_cx_pkt_t *pkt = NULL;
    100  const aom_codec_err_t res = aom_codec_encode(ctx, img, pts, duration, flags);
    101  if (res != AOM_CODEC_OK) die_codec(ctx, "Failed to encode frame.");
    102 
    103  while ((pkt = aom_codec_get_cx_data(ctx, &iter)) != NULL) {
    104    got_pkts = 1;
    105    if (pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
    106      const int keyframe = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
    107 
    108      if (!aom_video_writer_write_frame(writer, pkt->data.frame.buf,
    109                                        pkt->data.frame.sz,
    110                                        pkt->data.frame.pts))
    111        die_codec(ctx, "Failed to write compressed frame.");
    112      printf(keyframe ? "K" : ".");
    113      fflush(stdout);
    114    }
    115  }
    116 
    117  return got_pkts;
    118 }
    119 
    120 static void get_raw_image(aom_image_t **frame_to_encode, aom_image_t *raw,
    121                          aom_image_t *raw_shift) {
    122  if (FORCE_HIGHBITDEPTH_DECODING) {
    123    // Need to allocate larger buffer to use hbd internal.
    124    int input_shift = 0;
    125    aom_img_upshift(raw_shift, raw, input_shift);
    126    *frame_to_encode = raw_shift;
    127  } else {
    128    *frame_to_encode = raw;
    129  }
    130 }
    131 
    132 static aom_fixed_buf_t pass0(aom_image_t *raw, FILE *infile,
    133                             aom_codec_iface_t *encoder,
    134                             const aom_codec_enc_cfg_t *cfg, int lf_width,
    135                             int lf_height, int lf_blocksize, int flags,
    136                             aom_image_t *raw_shift) {
    137  aom_codec_ctx_t codec;
    138  int frame_count = 0;
    139  int image_size_bytes = img_size_bytes(raw);
    140  int u_blocks, v_blocks;
    141  int bu, bv;
    142  aom_fixed_buf_t stats = { NULL, 0 };
    143  aom_image_t *frame_to_encode;
    144 
    145  if (aom_codec_enc_init(&codec, encoder, cfg, flags))
    146    die("Failed to initialize encoder");
    147  if (aom_codec_control(&codec, AOME_SET_ENABLEAUTOALTREF, 0))
    148    die_codec(&codec, "Failed to turn off auto altref");
    149  if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 0))
    150    die_codec(&codec, "Failed to set frame parallel decoding");
    151 
    152  // How many reference images we need to encode.
    153  u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize;
    154  v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize;
    155 
    156  printf("\n First pass: ");
    157 
    158  for (bv = 0; bv < v_blocks; ++bv) {
    159    for (bu = 0; bu < u_blocks; ++bu) {
    160      const int block_u_min = bu * lf_blocksize;
    161      const int block_v_min = bv * lf_blocksize;
    162      int block_u_end = (bu + 1) * lf_blocksize;
    163      int block_v_end = (bv + 1) * lf_blocksize;
    164      int u_block_size, v_block_size;
    165      int block_ref_u, block_ref_v;
    166 
    167      block_u_end = block_u_end < lf_width ? block_u_end : lf_width;
    168      block_v_end = block_v_end < lf_height ? block_v_end : lf_height;
    169      u_block_size = block_u_end - block_u_min;
    170      v_block_size = block_v_end - block_v_min;
    171      block_ref_u = block_u_min + u_block_size / 2;
    172      block_ref_v = block_v_min + v_block_size / 2;
    173 
    174      printf("A%d, ", (block_ref_u + block_ref_v * lf_width));
    175      fseek(infile, (block_ref_u + block_ref_v * lf_width) * image_size_bytes,
    176            SEEK_SET);
    177      aom_img_read(raw, infile);
    178      get_raw_image(&frame_to_encode, raw, raw_shift);
    179 
    180      // Reference frames can be encoded encoded without tiles.
    181      ++frame_count;
    182      get_frame_stats(&codec, frame_to_encode, frame_count, 1,
    183                      AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
    184                          AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
    185                          AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
    186                          AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
    187                          AOM_EFLAG_NO_UPD_ARF,
    188                      &stats);
    189    }
    190  }
    191 
    192  if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1))
    193    die_codec(&codec, "Failed to set frame parallel decoding");
    194 
    195  for (bv = 0; bv < v_blocks; ++bv) {
    196    for (bu = 0; bu < u_blocks; ++bu) {
    197      const int block_u_min = bu * lf_blocksize;
    198      const int block_v_min = bv * lf_blocksize;
    199      int block_u_end = (bu + 1) * lf_blocksize;
    200      int block_v_end = (bv + 1) * lf_blocksize;
    201      int u, v;
    202      block_u_end = block_u_end < lf_width ? block_u_end : lf_width;
    203      block_v_end = block_v_end < lf_height ? block_v_end : lf_height;
    204      for (v = block_v_min; v < block_v_end; ++v) {
    205        for (u = block_u_min; u < block_u_end; ++u) {
    206          printf("C%d, ", (u + v * lf_width));
    207          fseek(infile, (u + v * lf_width) * image_size_bytes, SEEK_SET);
    208          aom_img_read(raw, infile);
    209          get_raw_image(&frame_to_encode, raw, raw_shift);
    210 
    211          ++frame_count;
    212          get_frame_stats(&codec, frame_to_encode, frame_count, 1,
    213                          AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
    214                              AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
    215                              AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
    216                              AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
    217                              AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY,
    218                          &stats);
    219        }
    220      }
    221    }
    222  }
    223  // Flush encoder.
    224  // No ARF, this should not be needed.
    225  while (get_frame_stats(&codec, NULL, frame_count, 1, 0, &stats)) {
    226  }
    227 
    228  if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
    229 
    230  printf("\nFirst pass complete. Processed %d frames.\n", frame_count);
    231 
    232  return stats;
    233 }
    234 
    235 static void pass1(aom_image_t *raw, FILE *infile, const char *outfile_name,
    236                  aom_codec_iface_t *encoder, aom_codec_enc_cfg_t *cfg,
    237                  int lf_width, int lf_height, int lf_blocksize, int flags,
    238                  aom_image_t *raw_shift) {
    239  AvxVideoInfo info = { get_fourcc_by_aom_encoder(encoder),
    240                        cfg->g_w,
    241                        cfg->g_h,
    242                        { cfg->g_timebase.num, cfg->g_timebase.den },
    243                        0 };
    244  AvxVideoWriter *writer = NULL;
    245  aom_codec_ctx_t codec;
    246  int frame_count = 0;
    247  int image_size_bytes = img_size_bytes(raw);
    248  int bu, bv;
    249  int u_blocks, v_blocks;
    250  aom_image_t *frame_to_encode;
    251  aom_image_t reference_images[MAX_EXTERNAL_REFERENCES];
    252  int reference_image_num = 0;
    253  int i;
    254 
    255  writer = aom_video_writer_open(outfile_name, kContainerIVF, &info);
    256  if (!writer) die("Failed to open %s for writing", outfile_name);
    257 
    258  if (aom_codec_enc_init(&codec, encoder, cfg, flags))
    259    die("Failed to initialize encoder");
    260  if (aom_codec_control(&codec, AOME_SET_ENABLEAUTOALTREF, 0))
    261    die_codec(&codec, "Failed to turn off auto altref");
    262  if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 0))
    263    die_codec(&codec, "Failed to set frame parallel decoding");
    264  if (aom_codec_control(&codec, AV1E_ENABLE_EXT_TILE_DEBUG, 1))
    265    die_codec(&codec, "Failed to enable encoder ext_tile debug");
    266  if (aom_codec_control(&codec, AOME_SET_CPUUSED, 3))
    267    die_codec(&codec, "Failed to set cpu-used");
    268 
    269  // Note: The superblock is a sequence parameter and has to be the same for 1
    270  // sequence. In lightfield application, must choose the superblock size(either
    271  // 64x64 or 128x128) before the encoding starts. Otherwise, the default is
    272  // AOM_SUPERBLOCK_SIZE_DYNAMIC, and the superblock size will be set to 64x64
    273  // internally.
    274  if (aom_codec_control(&codec, AV1E_SET_SUPERBLOCK_SIZE,
    275                        AOM_SUPERBLOCK_SIZE_64X64))
    276    die_codec(&codec, "Failed to set SB size");
    277 
    278  u_blocks = (lf_width + lf_blocksize - 1) / lf_blocksize;
    279  v_blocks = (lf_height + lf_blocksize - 1) / lf_blocksize;
    280 
    281  reference_image_num = u_blocks * v_blocks;
    282  // Set the max gf group length so the references are guaranteed to be in
    283  // a different gf group than any of the regular frames. This avoids using
    284  // both vbr and constant quality mode in a single group. The number of
    285  // references now cannot surpass 17 because of the enforced MAX_GF_INTERVAL of
    286  // 16. If it is necessary to exceed this reference frame limit, one will have
    287  // to do some additional handling to ensure references are in separate gf
    288  // groups from the regular frames.
    289  if (aom_codec_control(&codec, AV1E_SET_MAX_GF_INTERVAL,
    290                        reference_image_num - 1))
    291    die_codec(&codec, "Failed to set max gf interval");
    292  aom_img_fmt_t ref_fmt = AOM_IMG_FMT_I420;
    293  if (FORCE_HIGHBITDEPTH_DECODING) ref_fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
    294  // Allocate memory with the border so that it can be used as a reference.
    295  const bool resize =
    296      codec.config.enc->rc_resize_mode || codec.config.enc->rc_superres_mode;
    297  const bool all_intra = reference_image_num - 1 == 0;
    298  int border_in_pixels =
    299      av1_get_enc_border_size(resize, all_intra, BLOCK_64X64);
    300 
    301  for (i = 0; i < reference_image_num; i++) {
    302    if (!aom_img_alloc_with_border(&reference_images[i], ref_fmt, cfg->g_w,
    303                                   cfg->g_h, 32, 8, border_in_pixels)) {
    304      die("Failed to allocate image.");
    305    }
    306  }
    307 
    308  printf("\n Second pass: ");
    309 
    310  // Encode reference images first.
    311  printf("Encoding Reference Images\n");
    312  for (bv = 0; bv < v_blocks; ++bv) {
    313    for (bu = 0; bu < u_blocks; ++bu) {
    314      const int block_u_min = bu * lf_blocksize;
    315      const int block_v_min = bv * lf_blocksize;
    316      int block_u_end = (bu + 1) * lf_blocksize;
    317      int block_v_end = (bv + 1) * lf_blocksize;
    318      int u_block_size, v_block_size;
    319      int block_ref_u, block_ref_v;
    320 
    321      block_u_end = block_u_end < lf_width ? block_u_end : lf_width;
    322      block_v_end = block_v_end < lf_height ? block_v_end : lf_height;
    323      u_block_size = block_u_end - block_u_min;
    324      v_block_size = block_v_end - block_v_min;
    325      block_ref_u = block_u_min + u_block_size / 2;
    326      block_ref_v = block_v_min + v_block_size / 2;
    327 
    328      printf("A%d, ", (block_ref_u + block_ref_v * lf_width));
    329      fseek(infile, (block_ref_u + block_ref_v * lf_width) * image_size_bytes,
    330            SEEK_SET);
    331      aom_img_read(raw, infile);
    332 
    333      get_raw_image(&frame_to_encode, raw, raw_shift);
    334 
    335      // Reference frames may be encoded without tiles.
    336      ++frame_count;
    337      printf("Encoding reference image %d of %d\n", bv * u_blocks + bu,
    338             u_blocks * v_blocks);
    339      encode_frame(&codec, frame_to_encode, frame_count, 1,
    340                   AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
    341                       AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
    342                       AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
    343                       AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
    344                       AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY,
    345                   writer);
    346 
    347      if (aom_codec_control(&codec, AV1_COPY_NEW_FRAME_IMAGE,
    348                            &reference_images[frame_count - 1]))
    349        die_codec(&codec, "Failed to copy decoder reference frame");
    350    }
    351  }
    352 
    353  cfg->large_scale_tile = 1;
    354  // Fixed q encoding for camera frames.
    355  cfg->rc_end_usage = AOM_Q;
    356  if (aom_codec_enc_config_set(&codec, cfg))
    357    die_codec(&codec, "Failed to configure encoder");
    358 
    359  // The fixed q value used in encoding.
    360  if (aom_codec_control(&codec, AOME_SET_CQ_LEVEL, 36))
    361    die_codec(&codec, "Failed to set cq level");
    362  if (aom_codec_control(&codec, AV1E_SET_FRAME_PARALLEL_DECODING, 1))
    363    die_codec(&codec, "Failed to set frame parallel decoding");
    364  if (aom_codec_control(&codec, AV1E_SET_SINGLE_TILE_DECODING, 1))
    365    die_codec(&codec, "Failed to turn on single tile decoding");
    366  // Set tile_columns and tile_rows to MAX values, which guarantees the tile
    367  // size of 64 x 64 pixels(i.e. 1 SB) for <= 4k resolution.
    368  if (aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, 6))
    369    die_codec(&codec, "Failed to set tile width");
    370  if (aom_codec_control(&codec, AV1E_SET_TILE_ROWS, 6))
    371    die_codec(&codec, "Failed to set tile height");
    372 
    373  for (bv = 0; bv < v_blocks; ++bv) {
    374    for (bu = 0; bu < u_blocks; ++bu) {
    375      const int block_u_min = bu * lf_blocksize;
    376      const int block_v_min = bv * lf_blocksize;
    377      int block_u_end = (bu + 1) * lf_blocksize;
    378      int block_v_end = (bv + 1) * lf_blocksize;
    379      int u, v;
    380      block_u_end = block_u_end < lf_width ? block_u_end : lf_width;
    381      block_v_end = block_v_end < lf_height ? block_v_end : lf_height;
    382      for (v = block_v_min; v < block_v_end; ++v) {
    383        for (u = block_u_min; u < block_u_end; ++u) {
    384          av1_ref_frame_t ref;
    385          ref.idx = 0;
    386          ref.use_external_ref = 1;
    387          ref.img = reference_images[bv * u_blocks + bu];
    388          if (aom_codec_control(&codec, AV1_SET_REFERENCE, &ref))
    389            die_codec(&codec, "Failed to set reference frame");
    390 
    391          printf("C%d, ", (u + v * lf_width));
    392          fseek(infile, (u + v * lf_width) * image_size_bytes, SEEK_SET);
    393          aom_img_read(raw, infile);
    394          get_raw_image(&frame_to_encode, raw, raw_shift);
    395 
    396          ++frame_count;
    397          printf("Encoding image %d of %d\n",
    398                 frame_count - (u_blocks * v_blocks), lf_width * lf_height);
    399          encode_frame(&codec, frame_to_encode, frame_count, 1,
    400                       AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
    401                           AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
    402                           AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
    403                           AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
    404                           AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY,
    405                       writer);
    406        }
    407      }
    408    }
    409  }
    410 
    411  // Flush encoder.
    412  // No ARF, this should not be needed.
    413  while (encode_frame(&codec, NULL, -1, 1, 0, writer)) {
    414  }
    415 
    416  for (i = 0; i < reference_image_num; i++) aom_img_free(&reference_images[i]);
    417 
    418  if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec.");
    419 
    420  // Modify large_scale_file fourcc.
    421  if (cfg->large_scale_tile == 1)
    422    aom_video_writer_set_fourcc(writer, LST_FOURCC);
    423  aom_video_writer_close(writer);
    424 
    425  printf("\nSecond pass complete. Processed %d frames.\n", frame_count);
    426 }
    427 
    428 int main(int argc, char **argv) {
    429  FILE *infile = NULL;
    430  int w, h;
    431  // The number of lightfield images in the u and v dimensions.
    432  int lf_width, lf_height;
    433  // Defines how many images refer to the same reference image for MCP.
    434  // lf_blocksize X lf_blocksize images will all use the reference image
    435  // in the middle of the block of images.
    436  int lf_blocksize;
    437  aom_codec_ctx_t codec;
    438  aom_codec_enc_cfg_t cfg;
    439  aom_image_t raw;
    440  aom_image_t raw_shift;
    441  aom_codec_err_t res;
    442  aom_fixed_buf_t stats;
    443  int flags = 0;
    444 
    445  const int fps = 30;
    446  const int bitrate = 200;  // kbit/s
    447  const char *const width_arg = argv[1];
    448  const char *const height_arg = argv[2];
    449  const char *const infile_arg = argv[3];
    450  const char *const outfile_arg = argv[4];
    451  const char *const lf_width_arg = argv[5];
    452  const char *const lf_height_arg = argv[6];
    453  const char *lf_blocksize_arg = argv[7];
    454  exec_name = argv[0];
    455 
    456  if (argc < 8) die("Invalid number of arguments");
    457 
    458  aom_codec_iface_t *encoder = get_aom_encoder_by_short_name("av1");
    459  if (!encoder) die("Unsupported codec.");
    460 
    461  w = (int)strtol(width_arg, NULL, 0);
    462  h = (int)strtol(height_arg, NULL, 0);
    463  lf_width = (int)strtol(lf_width_arg, NULL, 0);
    464  lf_height = (int)strtol(lf_height_arg, NULL, 0);
    465  lf_blocksize = (int)strtol(lf_blocksize_arg, NULL, 0);
    466  lf_blocksize = lf_blocksize < lf_width ? lf_blocksize : lf_width;
    467  lf_blocksize = lf_blocksize < lf_height ? lf_blocksize : lf_height;
    468 
    469  if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0)
    470    die("Invalid frame size: %dx%d", w, h);
    471  if (lf_width <= 0 || lf_height <= 0)
    472    die("Invalid lf_width and/or lf_height: %dx%d", lf_width, lf_height);
    473  if (lf_blocksize <= 0) die("Invalid lf_blocksize: %d", lf_blocksize);
    474 
    475  if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, w, h, 32)) {
    476    die("Failed to allocate image.");
    477  }
    478  if (FORCE_HIGHBITDEPTH_DECODING) {
    479    // Need to allocate larger buffer to use hbd internal.
    480    aom_img_alloc(&raw_shift, AOM_IMG_FMT_I420 | AOM_IMG_FMT_HIGHBITDEPTH, w, h,
    481                  32);
    482  }
    483 
    484  printf("Using %s\n", aom_codec_iface_name(encoder));
    485 
    486  // Configuration
    487  res = aom_codec_enc_config_default(encoder, &cfg, 0);
    488  if (res) die_codec(&codec, "Failed to get default codec config.");
    489 
    490  cfg.g_w = w;
    491  cfg.g_h = h;
    492  cfg.g_timebase.num = 1;
    493  cfg.g_timebase.den = fps;
    494  cfg.rc_target_bitrate = bitrate;
    495  cfg.g_error_resilient = 0;  // This is required.
    496  cfg.g_lag_in_frames = 0;    // need to set this since default is 19.
    497  cfg.kf_mode = AOM_KF_DISABLED;
    498  cfg.large_scale_tile = 0;  // Only set it to 1 for camera frame encoding.
    499  cfg.g_bit_depth = AOM_BITS_8;
    500  flags |= (cfg.g_bit_depth > AOM_BITS_8 || FORCE_HIGHBITDEPTH_DECODING)
    501               ? AOM_CODEC_USE_HIGHBITDEPTH
    502               : 0;
    503 
    504  if (!(infile = fopen(infile_arg, "rb")))
    505    die("Failed to open %s for reading", infile_arg);
    506 
    507  // Pass 0
    508  cfg.g_pass = AOM_RC_FIRST_PASS;
    509  stats = pass0(&raw, infile, encoder, &cfg, lf_width, lf_height, lf_blocksize,
    510                flags, &raw_shift);
    511 
    512  // Pass 1
    513  rewind(infile);
    514  cfg.g_pass = AOM_RC_LAST_PASS;
    515  cfg.rc_twopass_stats_in = stats;
    516  pass1(&raw, infile, outfile_arg, encoder, &cfg, lf_width, lf_height,
    517        lf_blocksize, flags, &raw_shift);
    518  free(stats.buf);
    519 
    520  if (FORCE_HIGHBITDEPTH_DECODING) aom_img_free(&raw_shift);
    521  aom_img_free(&raw);
    522  fclose(infile);
    523 
    524  return EXIT_SUCCESS;
    525 }