Commit f866287f for libheif
commit f866287f10a30c81fc98b2d13102908763740868
Author: Chris Scribner <scriby@gmail.com>
Date: Thu Mar 26 12:16:56 2026 -0700
Update decoder_webcodecs.cc to plugin API v5 & fix references to NAL constants.
Update code to fix use-after-free errors that cae up after moving to the v5 API.
diff --git a/libheif/plugins/decoder_webcodecs.cc b/libheif/plugins/decoder_webcodecs.cc
index a6b23880..39ad0135 100644
--- a/libheif/plugins/decoder_webcodecs.cc
+++ b/libheif/plugins/decoder_webcodecs.cc
@@ -37,8 +37,7 @@
struct NALUnit {
- void* data;
- size_t size;
+ std::vector<uint8_t> data;
};
struct webcodecs_decoder
@@ -405,12 +404,12 @@ static struct heif_error webcodecs_push_data(void* decoder_raw, const void* data
return err;
}
- NALUnit nal_unit = {(void*)(cdata + ptr), nal_size};
- decoder->data_queue.push(nal_unit);
+ NALUnit nal_unit;
+ nal_unit.data.assign(cdata + ptr, cdata + ptr + nal_size);
+ decoder->data_queue.push(std::move(nal_unit));
ptr += nal_size;
}
-
struct heif_error err = {heif_error_Ok, heif_suberror_Unspecified, kSuccess};
return err;
}
@@ -631,20 +630,19 @@ static void get_nal_units(struct webcodecs_decoder* decoder,
NALUnit nal_unit = decoder->data_queue.front();
decoder->data_queue.pop();
- if (nal_unit.size == 0) {
+ if (nal_unit.data.empty()) {
continue;
}
- const auto* nal_data = static_cast<const uint8_t*>(nal_unit.data);
- const uint8_t nal_type = (nal_data[0] >> 1) & 0x3F;
+ const uint8_t nal_type = (nal_unit.data[0] >> 1) & 0x3F;
- if (nal_type == NAL_UNIT_VPS_NUT) {
+ if (nal_type == HEVC_NAL_UNIT_VPS_NUT) {
vps_nal_unit = nal_unit;
- } else if (nal_type == NAL_UNIT_SPS_NUT) {
+ } else if (nal_type == HEVC_NAL_UNIT_SPS_NUT) {
sps_nal_unit = nal_unit;
- } else if (nal_type == NAL_UNIT_PPS_NUT) {
+ } else if (nal_type == HEVC_NAL_UNIT_PPS_NUT) {
pps_nal_unit = nal_unit;
- } else if (nal_type <= NAL_UNIT_MAX_VCL) {
+ } else if (nal_type <= HEVC_NAL_UNIT_MAX_VCL) {
// Assume the plugin will only receive one VCL NAL unit.
data_unit = nal_unit;
}
@@ -658,14 +656,14 @@ static struct heif_error webcodecs_decode_image(void* decoder_raw,
struct webcodecs_decoder* decoder = (struct webcodecs_decoder*) decoder_raw;
*out_img = nullptr;
- NALUnit vps_nal_unit = {nullptr, 0};
- NALUnit sps_nal_unit = {nullptr, 0};
- NALUnit pps_nal_unit = {nullptr, 0};
- NALUnit data_unit = {nullptr, 0};
+ NALUnit vps_nal_unit;
+ NALUnit sps_nal_unit;
+ NALUnit pps_nal_unit;
+ NALUnit data_unit;
get_nal_units(decoder, vps_nal_unit, sps_nal_unit, pps_nal_unit, data_unit);
- if (!vps_nal_unit.data || !sps_nal_unit.data || !pps_nal_unit.data || !data_unit.data) {
+ if (vps_nal_unit.data.empty() || sps_nal_unit.data.empty() || pps_nal_unit.data.empty() || data_unit.data.empty()) {
return {heif_error_Decoder_plugin_error,
heif_suberror_End_of_data,
"Missing required NAL units (VPS, SPS, PPS, or data)"};
@@ -673,23 +671,23 @@ static struct heif_error webcodecs_decode_image(void* decoder_raw,
HEVCDecoderConfigurationRecord config;
int w, h;
- Error err = parse_sps_for_hvcC_configuration2((const uint8_t*)sps_nal_unit.data, sps_nal_unit.size, &config, &w, &h);
+ Error err = parse_sps_for_hvcC_configuration2(sps_nal_unit.data.data(), sps_nal_unit.data.size(), &config, &w, &h);
if (err != Error::Ok) {
return {heif_error_Decoder_plugin_error,
heif_suberror_Unspecified,
"Failed to parse SPS"};
}
- config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, NAL_UNIT_VPS_NUT, {std::vector<uint8_t>((uint8_t*)vps_nal_unit.data, (uint8_t*)vps_nal_unit.data + vps_nal_unit.size)}});
- config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, NAL_UNIT_SPS_NUT, {std::vector<uint8_t>((uint8_t*)sps_nal_unit.data, (uint8_t*)sps_nal_unit.data + sps_nal_unit.size)}});
- config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, NAL_UNIT_PPS_NUT, {std::vector<uint8_t>((uint8_t*)pps_nal_unit.data, (uint8_t*)pps_nal_unit.data + pps_nal_unit.size)}});
+ config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, HEVC_NAL_UNIT_VPS_NUT, {vps_nal_unit.data}});
+ config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, HEVC_NAL_UNIT_SPS_NUT, {sps_nal_unit.data}});
+ config.m_nal_array.push_back(HEVCDecoderConfigurationRecord::NalArray{0, HEVC_NAL_UNIT_PPS_NUT, {pps_nal_unit.data}});
StreamWriter writer;
config.write(writer);
std::vector<uint8_t> hvcc_record = writer.get_data();
// The WebCodecs API expects the NAL unit to be prefixed with its size (4 bytes, big-endian).
- size_t nal_size = data_unit.size;
+ uint32_t nal_size = static_cast<uint32_t>(data_unit.data.size());
std::vector<uint8_t> data_with_size(4 + nal_size);
// Write length in Big Endian
data_with_size[0] = (nal_size >> 24) & 0xFF;
@@ -697,7 +695,7 @@ static struct heif_error webcodecs_decode_image(void* decoder_raw,
data_with_size[2] = (nal_size >> 8) & 0xFF;
data_with_size[3] = nal_size & 0xFF;
// Append NAL payload
- memcpy(data_with_size.data() + 4, data_unit.data, nal_size);
+ memcpy(data_with_size.data() + 4, data_unit.data.data(), nal_size);
std::string codec_string = get_hevc_codec_string(config);
@@ -875,13 +873,56 @@ static struct heif_error webcodecs_decode_image(void* decoder_raw,
void webcodecs_set_strict_decoding(void* decoder_raw, int flag)
{
+}
+
+
+static int webcodecs_does_support_format2(const heif_decoder_plugin_compressed_format_description* format)
+{
+ return webcodecs_does_support_format(format->format);
+}
+
+
+static struct heif_error webcodecs_new_decoder2(void** dec, const heif_decoder_plugin_options* options)
+{
+ return webcodecs_new_decoder(dec);
+}
+
+
+static struct heif_error webcodecs_push_data2(void* decoder_raw, const void* data, size_t size, uintptr_t user_data)
+{
+ return webcodecs_push_data(decoder_raw, data, size);
+}
+
+
+static struct heif_error webcodecs_flush_data(void* decoder_raw)
+{
+ return {heif_error_Ok, heif_suberror_Unspecified, kSuccess};
+}
+
+static struct heif_error webcodecs_decode_next_image(void* decoder_raw,
+ struct heif_image** out_img,
+ const heif_security_limits* limits)
+{
+ return webcodecs_decode_image(decoder_raw, out_img);
+}
+
+
+static struct heif_error webcodecs_decode_next_image2(void* decoder_raw,
+ struct heif_image** out_img,
+ uintptr_t* out_user_data,
+ const heif_security_limits* limits)
+{
+ if (out_user_data) {
+ *out_user_data = 0;
+ }
+ return webcodecs_decode_image(decoder_raw, out_img);
}
static const struct heif_decoder_plugin decoder_webcodecs
{
- 1,
+ 5,
webcodecs_plugin_name,
webcodecs_init_plugin,
webcodecs_deinit_plugin,
@@ -891,7 +932,14 @@ static const struct heif_decoder_plugin decoder_webcodecs
webcodecs_push_data,
webcodecs_decode_image,
webcodecs_set_strict_decoding,
- "webcodecs"
+ "webcodecs",
+ webcodecs_decode_next_image,
+ 0,
+ webcodecs_does_support_format2,
+ webcodecs_new_decoder2,
+ webcodecs_push_data2,
+ webcodecs_flush_data,
+ webcodecs_decode_next_image2
};