struct heif_error aom_decode_image()

in libheif/plugins/decoder_aom.cc [155:274]


struct heif_error aom_decode_image(void* decoder_raw, struct heif_image** out_img)
{
  struct aom_decoder* decoder = (struct aom_decoder*) decoder_raw;

  aom_codec_iter_t iter = NULL;
  aom_image_t* img = NULL;

  img = aom_codec_get_frame(&decoder->codec, &iter);

  if (img == NULL) {
    struct heif_error err = {heif_error_Decoder_plugin_error,
                             heif_suberror_Unspecified,
                             kEmptyString};
    return err;
  }


  if (img->fmt != AOM_IMG_FMT_I420 &&
      img->fmt != AOM_IMG_FMT_I42016 &&
      img->fmt != AOM_IMG_FMT_I422 &&
      img->fmt != AOM_IMG_FMT_I42216 &&
      img->fmt != AOM_IMG_FMT_I444 &&
      img->fmt != AOM_IMG_FMT_I44416) {
    struct heif_error err = {heif_error_Decoder_plugin_error,
                             heif_suberror_Unsupported_image_type,
                             kEmptyString};
    return err;
  }

  heif_chroma chroma;
  heif_colorspace colorspace;

  if (img->monochrome) {
      chroma = heif_chroma_monochrome;
      colorspace = heif_colorspace_monochrome;
  }
  else {
    if (img->fmt == AOM_IMG_FMT_I444 ||
        img->fmt == AOM_IMG_FMT_I44416) {
      chroma = heif_chroma_444;
    }
    else if (img->fmt == AOM_IMG_FMT_I422 ||
             img->fmt == AOM_IMG_FMT_I42216) {
      chroma = heif_chroma_422;
    }
    else {
      chroma = heif_chroma_420;
    }
    colorspace = heif_colorspace_YCbCr;
  }

  struct heif_image* heif_img = nullptr;
  struct heif_error err = heif_image_create(img->d_w, img->d_h,
                                            colorspace,
                                            chroma,
                                            &heif_img);
  if (err.code != heif_error_Ok) {
    assert(heif_img==nullptr);
    return err;
  }


  // --- read nclx parameters from decoded AV1 bitstream

  heif_color_profile_nclx nclx;
  nclx.version = 1;
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_color_primaries(&nclx, static_cast<uint16_t>(img->cp)), { heif_image_release(heif_img); });
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_transfer_characteristics(&nclx, static_cast<uint16_t>(img->tc)), { heif_image_release(heif_img); });
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_matrix_coefficients(&nclx, static_cast<uint16_t>(img->mc)), { heif_image_release(heif_img); });
  nclx.full_range_flag = (img->range == AOM_CR_FULL_RANGE);
  heif_image_set_nclx_color_profile(heif_img, &nclx);


  // --- transfer data from aom_image_t to HeifPixelImage

  heif_channel channel2plane[3] = {
      heif_channel_Y,
      heif_channel_Cb,
      heif_channel_Cr
  };


  int num_planes = (chroma == heif_chroma_monochrome ? 1 : 3);

  for (int c = 0; c < num_planes; c++) {
    int bpp = img->bit_depth;

    const uint8_t* data = img->planes[c];
    int stride = img->stride[c];

    int w = img->d_w;
    int h = img->d_h;

    if (c > 0 && chroma == heif_chroma_420) {
      w = (w + 1) / 2;
      h = (h + 1) / 2;
    }
    else if (c > 0 && chroma == heif_chroma_422) {
      w = (w + 1) / 2;
    }

    err = heif_image_add_plane(heif_img, channel2plane[c], w, h, bpp);
    if (err.code != heif_error_Ok) {
      heif_image_release(heif_img);
      return err;
    }

    int dst_stride;
    uint8_t* dst_mem = heif_image_get_plane(heif_img, channel2plane[c], &dst_stride);

    int bytes_per_pixel = (bpp + 7) / 8;

    for (int y = 0; y < h; y++) {
      memcpy(dst_mem + y * dst_stride, data + y * stride, w * bytes_per_pixel);
    }
  }

  *out_img = heif_img;
  return err;
}