Skip to content

Commit

Permalink
avcC: fix test, write extended avcC fields, error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Sep 10, 2024
1 parent 24a2435 commit 7b7ac8e
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 45 deletions.
159 changes: 116 additions & 43 deletions libheif/codecs/avc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
#include "context.h"


Error Box_avcC::parse(BitstreamRange &range) {
Error Box_avcC::parse(BitstreamRange& range)
{
m_configuration.configuration_version = range.read8();
m_configuration.AVCProfileIndication = range.read8();
m_configuration.profile_compatibility = range.read8();
Expand All @@ -52,10 +53,11 @@ Error Box_avcC::parse(BitstreamRange &range) {
m_pps.push_back(pps);
}

// See ISO/IEC 14496-15 2017 Section 5.3.3.1.2
if ((m_configuration.AVCProfileIndication != 66) &&
(m_configuration.AVCProfileIndication != 77) &&
(m_configuration.AVCProfileIndication != 88)) {
m_configuration.chroma_format = range.read8() & 0b00000011;
m_configuration.chroma_format = (heif_chroma) (range.read8() & 0b00000011);
m_configuration.bit_depth_luma = 8 + (range.read8() & 0b00000111);
m_configuration.bit_depth_chroma = 8 + (range.read8() & 0b00000111);
uint8_t numOfSequenceParameterSetExt = range.read8();
Expand All @@ -70,7 +72,8 @@ Error Box_avcC::parse(BitstreamRange &range) {
return range.get_error();
}

Error Box_avcC::write(StreamWriter &writer) const {
Error Box_avcC::write(StreamWriter& writer) const
{
size_t box_start = reserve_box_header_space(writer);

writer.write8(m_configuration.configuration_version);
Expand All @@ -79,55 +82,125 @@ Error Box_avcC::write(StreamWriter &writer) const {
writer.write8(m_configuration.AVCLevelIndication);
uint8_t lengthSizeMinusOneWithReserved = 0b11111100 | ((m_configuration.lengthSize - 1) & 0b11);
writer.write8(lengthSizeMinusOneWithReserved);

if (m_sps.size() > 0b00011111) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write more than 31 PPS into avcC box."};
}

uint8_t numSpsWithReserved = 0b11100000 | (m_sps.size() & 0b00011111);
writer.write8(numSpsWithReserved);
for (const auto &sps: m_sps) {
for (const auto& sps : m_sps) {
if (sps.size() > 0xFFFF) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write SPS larger than 65535 bytes into avcC box."};
}
writer.write16((uint16_t) sps.size());
writer.write(sps);
}

if (m_pps.size() > 0xFF) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write more than 255 PPS into avcC box."};
}

writer.write8(m_pps.size() & 0xFF);
for (const auto &pps: m_pps) {
for (const auto& pps : m_pps) {
if (pps.size() > 0xFFFF) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write PPS larger than 65535 bytes into avcC box."};
}
writer.write16((uint16_t) pps.size());
writer.write(pps);
}

if ((m_configuration.AVCProfileIndication != 66) &&
(m_configuration.AVCProfileIndication != 77) &&
(m_configuration.AVCProfileIndication != 88)) {
writer.write8(m_configuration.chroma_format);
writer.write8(m_configuration.bit_depth_luma - 8);
writer.write8(m_configuration.bit_depth_chroma - 8);

if (m_sps_ext.size() > 0xFF) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write more than 255 SPS-Ext into avcC box."};
}

writer.write8(m_sps_ext.size() & 0xFF);
for (const auto& spsext : m_sps_ext) {
if (spsext.size() > 0xFFFF) {
return {heif_error_Encoding_error,
heif_suberror_Unspecified,
"Cannot write SPS-Ext larger than 65535 bytes into avcC box."};
}
writer.write16((uint16_t) spsext.size());
writer.write(spsext);
}
}

prepend_header(writer, box_start);

return Error::Ok;
}

std::string Box_avcC::dump(Indent &indent) const {
std::string Box_avcC::dump(Indent& indent) const
{
std::ostringstream sstr;
sstr << Box::dump(indent);
sstr << indent << "configuration_version: " << ((int)m_configuration.configuration_version) << "\n"
<< indent << "AVCProfileIndication: " << ((int)m_configuration.AVCProfileIndication) << " (" << profileIndicationAsText() << ")\n"
<< indent << "profile_compatibility: " << ((int)m_configuration.profile_compatibility) << "\n"
<< indent << "AVCLevelIndication: " << ((int)m_configuration.AVCLevelIndication) << "\n"
<< indent << "Chroma format: " << ((int)m_configuration.chroma_format) << "\n"
<< indent << "Bit depth luma: " << ((int)m_configuration.bit_depth_luma) << "\n"
<< indent << "Bit depth chroma: " << ((int)m_configuration.bit_depth_chroma) << "\n";

for (const auto &sps : m_sps) {
sstr << indent << "configuration_version: " << ((int) m_configuration.configuration_version) << "\n"
<< indent << "AVCProfileIndication: " << ((int) m_configuration.AVCProfileIndication) << " (" << profileIndicationAsText() << ")\n"
<< indent << "profile_compatibility: " << ((int) m_configuration.profile_compatibility) << "\n"
<< indent << "AVCLevelIndication: " << ((int) m_configuration.AVCLevelIndication) << "\n"
<< indent << "Chroma format: ";

switch (m_configuration.chroma_format) {
case heif_chroma_monochrome:
sstr << "4:0:0\n";
break;
case heif_chroma_420:
sstr << "4:2:0\n";
break;
case heif_chroma_422:
sstr << "4:2:2\n";
break;
case heif_chroma_444:
sstr << "4:4:4\n";
break;
default:
sstr << "unsupported\n";
break;
}

sstr << indent << "Bit depth luma: " << ((int) m_configuration.bit_depth_luma) << "\n"
<< indent << "Bit depth chroma: " << ((int) m_configuration.bit_depth_chroma) << "\n";

for (const auto& sps : m_sps) {
sstr << indent << "SPS: ";
for (uint8_t b : sps) {
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int)b) << " ";
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
}
sstr << "\n";
sstr << std::dec;
}

for (const auto &spsext : m_sps_ext) {
for (const auto& spsext : m_sps_ext) {
sstr << indent << "SPS-EXT: ";
for (uint8_t b : spsext) {
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int)b) << " ";
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
}
sstr << "\n";
sstr << std::dec;
}

for (const auto &pps : m_pps) {
for (const auto& pps : m_pps) {
sstr << indent << "PPS: ";
for (uint8_t b : pps) {
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int)b) << " ";
sstr << std::setfill('0') << std::setw(2) << std::hex << ((int) b) << " ";
}
sstr << "\n";
sstr << std::dec;
Expand All @@ -136,27 +209,28 @@ std::string Box_avcC::dump(Indent &indent) const {
return sstr.str();
}

std::string Box_avcC::profileIndicationAsText() const {
std::string Box_avcC::profileIndicationAsText() const
{
// See ISO/IEC 14496-10:2022 Annex A
switch (m_configuration.AVCProfileIndication) {
case 44:
return "CALVC 4:4:4";
case 66:
return "Constrained Baseline";
case 77:
return "Main";
case 88:
return "Extended";
case 100:
return "High variant";
case 110:
return "High 10";
case 122:
return "High 4:2:2";
case 244:
return "High 4:4:4";
default:
return "Unknown";
case 44:
return "CALVC 4:4:4";
case 66:
return "Constrained Baseline";
case 77:
return "Main";
case 88:
return "Extended";
case 100:
return "High variant";
case 110:
return "High 10";
case 122:
return "High 4:2:2";
case 244:
return "High 4:4:4";
default:
return "Unknown";
}
}

Expand Down Expand Up @@ -192,11 +266,10 @@ void Box_avcC::get_header_nals(std::vector<uint8_t>& data) const
}



Result<ImageItem::CodedImageData> ImageItem_AVC::encode(const std::shared_ptr<HeifPixelImage>& image,
struct heif_encoder* encoder,
const struct heif_encoding_options& options,
enum heif_image_input_class input_class)
struct heif_encoder* encoder,
const struct heif_encoding_options& options,
enum heif_image_input_class input_class)
{
#if 0
CodedImageData codedImage;
Expand Down
2 changes: 1 addition & 1 deletion libheif/codecs/avc.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Box_avcC : public Box {
uint8_t profile_compatibility; // constraint set flags
uint8_t AVCLevelIndication; // level_idc
uint8_t lengthSize;
uint8_t chroma_format;
heif_chroma chroma_format = heif_chroma_420; // Note: avcC integer value can be cast to heif_chroma enum
uint8_t bit_depth_luma = 8;
uint8_t bit_depth_chroma = 8;
};
Expand Down
2 changes: 1 addition & 1 deletion tests/avc_box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ TEST_CASE("avcC") {
"AVCProfileIndication: 66 (Constrained Baseline)\n"
"profile_compatibility: 128\n"
"AVCLevelIndication: 30\n"
"Chroma format: 32\n"
"Chroma format: 4:2:0\n"
"Bit depth luma: 8\n"
"Bit depth chroma: 8\n"
"SPS: 67 64 00 28 ac 72 04 40 40 04 1a 10 00 00 03 00 "
Expand Down

0 comments on commit 7b7ac8e

Please sign in to comment.