struct heif_error dav1d_decode_image()

in libheif/plugins/decoder_dav1d.cc [155:290]


struct heif_error dav1d_decode_image(void* decoder_raw, struct heif_image** out_img)
{
  auto* decoder = (struct dav1d_decoder*) decoder_raw;

  struct heif_error err;

  Dav1dPicture frame;
  memset(&frame, 0, sizeof(Dav1dPicture));

  bool flushed = false;

  for (;;) {

    int res = dav1d_send_data(decoder->context, &decoder->data);
    if ((res < 0) && (res != DAV1D_ERR(EAGAIN))) {
      err = {heif_error_Decoder_plugin_error,
             heif_suberror_Unspecified,
             kEmptyString};
      return err;
    }

    res = dav1d_get_picture(decoder->context, &frame);
    if (!flushed && res == DAV1D_ERR(EAGAIN)) {
      if (decoder->data.sz == 0) {
        flushed = true;
      }
      continue;
    }
    else if (res < 0) {
      err = {heif_error_Decoder_plugin_error,
             heif_suberror_Unspecified,
             kEmptyString};
      return err;
    }
    else {
      break;
    }
  }

  heif_chroma chroma;
  heif_colorspace colorspace;
  switch (frame.p.layout) {
    case DAV1D_PIXEL_LAYOUT_I420:
      chroma = heif_chroma_420;
      colorspace = heif_colorspace_YCbCr;
      break;
    case DAV1D_PIXEL_LAYOUT_I422:
      chroma = heif_chroma_422;
      colorspace = heif_colorspace_YCbCr;
      break;
    case DAV1D_PIXEL_LAYOUT_I444:
      chroma = heif_chroma_444;
      colorspace = heif_colorspace_YCbCr;
      break;
    case DAV1D_PIXEL_LAYOUT_I400:
      chroma = heif_chroma_monochrome;
      colorspace = heif_colorspace_monochrome;
      break;
    default: {
      err = {heif_error_Decoder_plugin_error,
             heif_suberror_Unspecified,
             kEmptyString};
      return err;
    }
  }


  struct heif_image* heif_img = nullptr;
  err = heif_image_create(frame.p.w, frame.p.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;
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_color_primaries(&nclx, static_cast<uint16_t>(frame.seq_hdr->pri)), {});
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_transfer_characteristics(&nclx, static_cast<uint16_t>(frame.seq_hdr->trc)), {});
  HEIF_WARN_OR_FAIL(decoder->strict_decoding, heif_img, heif_nclx_color_profile_set_matrix_coefficients(&nclx, static_cast<uint16_t>(frame.seq_hdr->mtrx)), {});
  nclx.full_range_flag = (frame.seq_hdr->color_range != 0);
  heif_image_set_nclx_color_profile(heif_img, &nclx);



  // --- transfer data from Dav1dPicture to HeifPixelImage

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


  // --- copy image data

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

  for (int c = 0; c < num_planes; c++) {
    int bpp = frame.p.bpc;

    const uint8_t* data = (uint8_t*) frame.data[c];
    int stride = (int) frame.stride[c > 0 ? 1 : 0];

    int w, h;
    get_subsampled_size(frame.p.w, frame.p.h,
                        channel2plane[c], chroma, &w, &h);

    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);
    }
  }

  dav1d_picture_unref(&frame);

  *out_img = heif_img;


  err = {heif_error_Ok, heif_suberror_Unspecified, kSuccess};
  return err;
}