Error HeifContext::decode_image_planar_for_moov()

in libheif/context.cc [1603:1727]


Error HeifContext::decode_image_planar_for_moov(heif_item_id ID,
                                                std::shared_ptr<HeifPixelImage>& img,
                                                heif_colorspace out_colorspace,
                                                heif_chroma  out_chroma,
                                                const struct heif_decoding_options& options, bool alphaImage) const
{
  std::shared_ptr<Image> imginfo;
  if (m_all_images.find(ID) != m_all_images.end()) {
    imginfo = m_all_images.find(ID)->second;
  }

  assert(imginfo);

  Error error;

  if(m_heif_file->get_hvc1_box())
  {
    heif_compression_format compression = heif_compression_undefined;
    compression = heif_compression_HEVC;
    const struct heif_decoder_plugin* decoder_plugin = get_decoder(compression, options.decoder_id);
    if (!decoder_plugin) {
      return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_codec);
    }
    
    std::vector<uint8_t> data;
    error = m_heif_file->get_compressed_image_data_for_moov(ID, &data);
    if (error) {
      return error;
    }

    void* decoder;
    struct heif_error err = decoder_plugin->new_decoder(&decoder, m_max_decoder_threads);
    if (err.code != heif_error_Ok) {
      return Error(err.code, err.subcode, err.message);
    }

    if (decoder_plugin->plugin_api_version >= 2) {
      if (decoder_plugin->set_strict_decoding) {
        decoder_plugin->set_strict_decoding(decoder, options.strict_decoding );
      }
    }

    err = decoder_plugin->push_data(decoder, data.data(), data.size());
    if (err.code != heif_error_Ok) {
      decoder_plugin->free_decoder(decoder);
      return Error(err.code, err.subcode, err.message);
    }

    heif_image* decoded_img = nullptr;

    err = decoder_plugin->decode_image(decoder, &decoded_img);
    if (err.code != heif_error_Ok) {
      decoder_plugin->free_decoder(decoder);
      return Error(err.code, err.subcode, err.message);
    }

    if (!decoded_img) {
      // TODO(farindk): The plugin should return an error in this case.
      decoder_plugin->free_decoder(decoder);
      return Error(heif_error_Decoder_plugin_error, heif_suberror_Unspecified);
    }

    img = std::move(decoded_img->image);
    heif_image_release(decoded_img);

    decoder_plugin->free_decoder(decoder);

    // --- convert to output chroma format

    // If there is an NCLX profile in the HEIF/AVIF metadata, use this for the color conversion.
    // Otherwise, use the profile that is stored in the image stream itself and then set the
    // (non-NCLX) profile later.
    auto nclx = imginfo->get_color_profile_nclx();
    if (nclx) {
      img->set_color_profile_nclx(nclx);
    }

    auto icc = imginfo->get_color_profile_icc();
    if (icc) {
      img->set_color_profile_icc(icc);
    }

    if (alphaImage) {
      // no color conversion required
    }
    else 
    {
      heif_colorspace target_colorspace = (out_colorspace == heif_colorspace_undefined ?
                                           img->get_colorspace() :
                                           out_colorspace);

//      if (!alphaImage && target_colorspace == heif_colorspace_YCbCr) {
//        target_colorspace = heif_colorspace_RGB;
//      }

//      heif_chroma target_chroma = (target_colorspace == heif_colorspace_monochrome ?
//                                   heif_chroma_monochrome : heif_chroma_444);
      heif_chroma target_chroma = out_chroma == heif_chroma_undefined ? img->get_chroma_format() :
                                   (target_colorspace == heif_colorspace_monochrome ? heif_chroma_monochrome : heif_chroma_444);

      bool different_chroma = (target_chroma != img->get_chroma_format());
      bool different_colorspace = (target_colorspace != img->get_colorspace());

      int bpp = options.convert_hdr_to_8bit ? 8 : 0;
      if (different_chroma || different_colorspace) {
        if(options.ext_dst && options.ext_dst_enable) {
          img->set_image_external_info(true, options.ext_dst, options.ext_dst_len, options.ext_dst_stride);
        }

        img = convert_colorspace(img, target_colorspace, target_chroma, nullptr, bpp, options.color_conversion_options);
        if (!img) {
          return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_color_conversion);
        }
      }
    }        
  }
  else
  {
    // Should not reach this, was already rejected by "get_image_data".
    return Error(heif_error_Unsupported_feature,
                 heif_suberror_Unsupported_image_type);
  }

  return Error::Ok;
}