diff --git a/libheif/context.cc b/libheif/context.cc index ee0a722360..faf0f1b02b 100644 --- a/libheif/context.cc +++ b/libheif/context.cc @@ -2777,20 +2777,25 @@ Error HeifContext::encode_image_as_vvc(const std::shared_ptr& im } - const uint8_t NAL_SPS = 33; + const uint8_t NAL_SPS = 15; - if ((data[0] >> 1) == NAL_SPS) { + uint8_t nal_type = 0; + if (size>=2) { + nal_type = (data[1] >> 3) & 0x1F; + } + + if (nal_type == NAL_SPS) { Box_vvcC::configuration config; - //parse_sps_for_vvcC_configuration(data, size, &config, &encoded_width, &encoded_height); + parse_sps_for_vvcC_configuration(data, size, &config, &encoded_width, &encoded_height); m_heif_file->set_vvcC_configuration(image_id, config); } switch (data[0] >> 1) { - case 0x20: - case 0x21: - case 0x22: + case 14: // VPS + case 15: // SPS + case 16: // PPS m_heif_file->append_vvcC_nal_data(image_id, data, size); break; diff --git a/libheif/plugins/encoder_uvg266.cc b/libheif/plugins/encoder_uvg266.cc index 262ae2dc3d..101743728d 100644 --- a/libheif/plugins/encoder_uvg266.cc +++ b/libheif/plugins/encoder_uvg266.cc @@ -32,6 +32,9 @@ extern "C" { #include } +#include +#include + static const char* kError_unspecified_error = "Unspecified encoder error"; static const char* kError_unsupported_bit_depth = "Bit depth not supported by uvg266"; @@ -339,6 +342,12 @@ static void append_chunk_data(uvg_data_chunk* data, std::vector& out) return; } +#if 0 + std::cout << "DATA\n"; + std::cout << write_raw_data_as_hex(data->data, data->len, {}, {}); + std::cout << "---\n"; +#endif + size_t old_size = out.size(); out.resize(old_size + data->len); memcpy(out.data() + old_size, data->data, data->len); @@ -616,7 +625,8 @@ static struct heif_error uvg266_encode_image(void* encoder_raw, const struct hei }; } - append_chunk_data(data, encoder->output_data); + // If we write this, the data is twice in the output + //append_chunk_data(data, encoder->output_data); success = api->encoder_encode(kvzencoder, pic, diff --git a/libheif/vvc.cc b/libheif/vvc.cc index a1e86a9b8b..9bdb79aef4 100644 --- a/libheif/vvc.cc +++ b/libheif/vvc.cc @@ -40,7 +40,7 @@ Error Box_vvcC::parse(BitstreamRange& range) byte = range.read8(); c.constantFrameRate = (byte & 0xc0) >> 6; c.numTemporalLayers = (byte & 0x38) >> 3; - c.lengthSize = uint8_t((byte & 0x06) + 1); + c.lengthSize = uint8_t(((byte & 0x06) >> 1) + 1); c.ptl_present_flag = (byte & 0x01); // assert(c.ptl_present_flag == false); // TODO (removed the assert since it will trigger the fuzzers) @@ -133,6 +133,8 @@ Error Box_vvcC::write(StreamWriter& writer) const writer.write8(c.configurationVersion); writer.write16(c.avgFrameRate_times_256); + assert(c.lengthSize == 1 || c.lengthSize == 2 || c.lengthSize == 4); + uint8_t v = ((c.constantFrameRate << 6) | (c.numTemporalLayers << 3) | ((c.lengthSize - 1) << 1) | @@ -218,7 +220,7 @@ std::string Box_vvcC::dump(Indent& indent) const sstr << indent << "num of arrays: " << m_nal_array.size() << "\n"; - sstr << indent << "config OBUs:"; + sstr << indent << "config NALs:"; for (size_t i = 0; i < m_nal_array.size(); i++) { indent++; sstr << indent << "array completeness: " << ((int)m_nal_array[i].m_array_completeness) << "\n"; @@ -234,3 +236,135 @@ std::string Box_vvcC::dump(Indent& indent) const return sstr.str(); } + +static std::vector remove_start_code_emulation(const uint8_t* sps, size_t size) +{ + std::vector out_data; + + for (size_t i = 0; i < size; i++) { + if (i + 2 < size && + sps[i] == 0 && + sps[i + 1] == 0 && + sps[i + 2] == 3) { + out_data.push_back(0); + out_data.push_back(0); + i += 2; + } + else { + out_data.push_back(sps[i]); + } + } + + return out_data; +} + + + +Error parse_sps_for_vvcC_configuration(const uint8_t* sps, size_t size, + Box_vvcC::configuration* config, + int* width, int* height) +{ + // remove start-code emulation bytes from SPS header stream + + std::vector sps_no_emul = remove_start_code_emulation(sps, size); + + sps = sps_no_emul.data(); + size = sps_no_emul.size(); + + BitReader reader(sps, (int) size); + + // skip NAL header + reader.skip_bits(2 * 8); + + // skip SPS ID + reader.skip_bits(4); + + // skip VPS ID + reader.skip_bits(4); + + config->numTemporalLayers = reader.get_bits(3) + 1; + config->chroma_format_idc = reader.get_bits(2); + config->chroma_format_present_flag = true; + reader.skip_bits(2); + + bool sps_ptl_dpb_hrd_params_present_flag = reader.get_bits(1); + if (sps_ptl_dpb_hrd_params_present_flag) { + // profile_tier_level( 1, sps_max_sublayers_minus1 ) + + if (true /*profileTierPresentFlag*/) { + //general_profile_idc + //general_tier_flag + reader.skip_bits(8); + } + reader.skip_bits(8); // general_level_idc + reader.skip_bits(1); //ptl_frame_only_constraint_flag + reader.skip_bits(1); //ptl_multilayer_enabled_flag + if (true /* profileTierPresentFlag*/ ) { + // general_constraints_info() + + bool gci_present_flag = reader.get_bits(1); + if (gci_present_flag) { + assert(false); + } + + reader.skip_to_byte_boundary(); + } + + std::vector ptl_sublayer_level_present_flag(config->numTemporalLayers); + for (int i = config->numTemporalLayers-2; i >= 0; i--) { + ptl_sublayer_level_present_flag[i] = reader.get_bits(1); + } + + reader.skip_to_byte_boundary(); + + for (int i = config->numTemporalLayers-2; i >= 0; i--) { + if (ptl_sublayer_level_present_flag[i]) { + reader.skip_bits(8); // sublayer_level_idc[i] + } + } + + if (true /*profileTierPresentFlag*/) { + int ptl_num_sub_profiles = reader.get_bits(8); + for (int i = 0; i < ptl_num_sub_profiles; i++) { + uint32_t idc = reader.get_bits(32); //general_sub_profile_idc[i] + (void) idc; + } + } + } + + reader.skip_bits(1); // sps_gdr_enabled_flag + bool sps_ref_pic_resampling_enabled_flag = reader.get_bits(1); + if (sps_ref_pic_resampling_enabled_flag) { + reader.skip_bits(1); // sps_res_change_in_clvs_allowed_flag + } + + int sps_pic_width_max_in_luma_samples; + int sps_pic_height_max_in_luma_samples; + + bool success; + success = reader.get_uvlc(&sps_pic_width_max_in_luma_samples); + success = reader.get_uvlc(&sps_pic_height_max_in_luma_samples); + (void)success; + + *width = sps_pic_width_max_in_luma_samples; + *height = sps_pic_height_max_in_luma_samples; + + int sps_conformance_window_flag = reader.get_bits(1); + if (sps_conformance_window_flag) { + assert(false); // TODO + } + + bool sps_subpic_info_present_flag = reader.get_bits(1); + if (sps_subpic_info_present_flag) { + assert(false); // TODO + } + + int bitDepth_minus8; + success = reader.get_uvlc(&bitDepth_minus8); + (void)success; + + config->bit_depth = bitDepth_minus8 + 8; + config->bit_depth_present_flag = true; + + return Error::Ok; +} diff --git a/libheif/vvc.h b/libheif/vvc.h index a41a7c4ae7..443009c5c5 100644 --- a/libheif/vvc.h +++ b/libheif/vvc.h @@ -37,19 +37,19 @@ class Box_vvcC : public Box struct configuration { uint8_t configurationVersion = 1; - uint16_t avgFrameRate_times_256; - uint8_t constantFrameRate; // 2 bits - uint8_t numTemporalLayers; // 3 bits - uint8_t lengthSize; // 2 bits - bool ptl_present_flag; + uint16_t avgFrameRate_times_256 = 0; + uint8_t constantFrameRate = 1; // 2 bits + uint8_t numTemporalLayers = 1; // 3 bits + uint8_t lengthSize = 1; // 2 bits + bool ptl_present_flag = false; //if (ptl_present_flag) { // VvcPTLRecord(numTemporalLayers) track_ptl; // uint16_t output_layer_set_idx; //} - bool chroma_format_present_flag; + bool chroma_format_present_flag = false; uint8_t chroma_format_idc; - bool bit_depth_present_flag; + bool bit_depth_present_flag = false; uint8_t bit_depth; }; @@ -95,4 +95,9 @@ class Box_vvcC : public Box }; +Error parse_sps_for_vvcC_configuration(const uint8_t* sps, size_t size, + Box_vvcC::configuration* inout_config, + int* width, int* height); + + #endif // LIBHEIF_VVC_H