Skip to content

Commit

Permalink
VVC: parse SPS, fill and write vvcC (#1108)
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Jun 22, 2024
1 parent b647913 commit c03caf6
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 16 deletions.
17 changes: 11 additions & 6 deletions libheif/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2777,20 +2777,25 @@ Error HeifContext::encode_image_as_vvc(const std::shared_ptr<HeifPixelImage>& 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;

Expand Down
12 changes: 11 additions & 1 deletion libheif/plugins/encoder_uvg266.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ extern "C" {
#include <uvg266.h>
}

#include <libheif/logging.h>
#include <iostream>


static const char* kError_unspecified_error = "Unspecified encoder error";
static const char* kError_unsupported_bit_depth = "Bit depth not supported by uvg266";
Expand Down Expand Up @@ -339,6 +342,12 @@ static void append_chunk_data(uvg_data_chunk* data, std::vector<uint8_t>& 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);
Expand Down Expand Up @@ -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,
Expand Down
138 changes: 136 additions & 2 deletions libheif/vvc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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) |
Expand Down Expand Up @@ -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";
Expand All @@ -234,3 +236,135 @@ std::string Box_vvcC::dump(Indent& indent) const
return sstr.str();
}


static std::vector<uint8_t> remove_start_code_emulation(const uint8_t* sps, size_t size)
{
std::vector<uint8_t> 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<uint8_t> 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<bool> 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;
}
19 changes: 12 additions & 7 deletions libheif/vvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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

0 comments on commit c03caf6

Please sign in to comment.