Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timestamp Properties #1011

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
59ebd8e
API Draft
dukesook Oct 24, 2023
e6c6af1
minor cleanup
dukesook Oct 24, 2023
109869a
Condensed Comments
dukesook Oct 27, 2023
7de6e25
In progress: heif_property_add_timestamp()
dukesook Oct 27, 2023
10e8306
Merge branch 'master' of https://github.com/strukturag/libheif into t…
dukesook Oct 27, 2023
e3a5950
Update libheif/heif_properties.h
dukesook Oct 27, 2023
fe5add9
add box definitions
dukesook Oct 27, 2023
3f61d3a
Merge branch 'timestamp_boxes' of https://github.com/dukesook/libheif…
dukesook Oct 27, 2023
bd5de49
Move comments to box.h to make a clean api
dukesook Oct 27, 2023
1d43250
implemented heif_property_add_clock_info()
dukesook Oct 27, 2023
99fe7f1
Improved Comments
dukesook Oct 27, 2023
c845ffa
Fix a small bug
kleisauke Oct 29, 2023
89ddc1c
nclx: use default values that match sRGB
kleisauke Oct 29, 2023
8cacd4d
Merge pull request #1015 from kleisauke/srgb-default
farindk Oct 30, 2023
127c1ca
alternative implementation of PR #1015
farindk Oct 30, 2023
136cf01
turn off macOS_compatibility_workaround_no_nclx_profile by default
farindk Oct 30, 2023
36326c5
fix heif_transfer_characteristic_unspecified
farindk Oct 30, 2023
2698eef
use matrix_coefficients=5 for sRGB
farindk Oct 30, 2023
d5a5559
Merge pull request #1017 from strukturag/unspecified-nclx-handling
farindk Oct 30, 2023
4809d30
use MC=6 for sRGB because of potential incompatibility of Safari/iOS …
farindk Oct 30, 2023
7cd873f
use MC=6 for sRGB because of potential incompatibility of Safari/iOS …
farindk Oct 30, 2023
30d9ead
limit maximum colr box size
farindk Oct 30, 2023
c431edb
fix integer overflow
farindk Oct 30, 2023
01e4f63
fix decoding of uncompressed greyscale
farindk Oct 31, 2023
8ff8227
fix reading images with unspecified jpgC box
farindk Oct 31, 2023
e547b74
show correct compression format name (not just AV1/HEVC)
farindk Oct 31, 2023
7e427d7
return 'unknown' encoder name
farindk Oct 31, 2023
3746885
jpeg2000: use chroma444 if nothing is specified explicitly
farindk Oct 31, 2023
b93a437
jpeg: fix encoding several images successively
farindk Oct 31, 2023
ca74385
jpeg2000: add encoding of alpha channel
farindk Oct 31, 2023
06f13d1
add heif_context_add_generic_uri_metadata()
farindk Oct 31, 2023
230baa7
Merge branch 'master' into timestamp_boxes
dukesook Nov 1, 2023
42395cd
verify if the two timestamp boxes truly need to be paired together
dukesook Nov 1, 2023
2289041
Revert "add heif_context_add_generic_uri_metadata()"
farindk Nov 1, 2023
3b1f465
check whether libpng supports iTXt chunks (#1020)
farindk Nov 2, 2023
c469dcb
increase version to v1.17.2
farindk Nov 2, 2023
d23cca4
Merge branch 'master' of https://github.com/strukturag/libheif into t…
dukesook Nov 2, 2023
47265d3
Use standard name for JPEG 2000
kmilos Nov 2, 2023
ab48741
Merge pull request #1022 from kmilos/kmilos/jp2_label
farindk Nov 2, 2023
e29fcc7
fix returning version number parts (#1023)
farindk Nov 2, 2023
3d09f49
Merge branch 'master' of https://github.com/strukturag/libheif into t…
dukesook Nov 2, 2023
4a6e47c
Cleaned up timestamp api
dukesook Nov 2, 2023
f3ef516
If the taic is missing, add it
dukesook Nov 3, 2023
b2f46d7
set default values for itai
dukesook Nov 3, 2023
d5308a1
Do not use designated initializers
dukesook Nov 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 3.16.3) # Oldest Ubuntu LTS (20.04 currently)

project(libheif LANGUAGES C CXX VERSION 1.17.1)
project(libheif LANGUAGES C CXX VERSION 1.17.2)

# compatibility_version is never allowed to be decreased for any specific SONAME.
# Libtool in the libheif-1.15.1 release had set it to 17.0.0, so we have to use this for the v1.x.y versions.
Expand Down
2 changes: 2 additions & 0 deletions examples/decoder_png.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ InputImage loadPNG(const char* filename, int output_bit_depth)

// --- read XMP data

#ifdef PNG_iTXt_SUPPORTED
png_textp textPtr = nullptr;
const png_uint_32 nTextChunks = png_get_text(png_ptr, info_ptr, &textPtr, nullptr);
for (png_uint_32 i = 0; i < nTextChunks; i++, textPtr++) {
Expand All @@ -231,6 +232,7 @@ InputImage loadPNG(const char* filename, int output_bit_depth)
}
}
}
#endif

int band = png_get_channels(png_ptr, info_ptr);

Expand Down
2 changes: 2 additions & 0 deletions examples/encoder_png.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ bool PngEncoder::Encode(const struct heif_image_handle* handle,

// --- write XMP metadata

#ifdef PNG_iTXt_SUPPORTED
// spec: https://raw.githubusercontent.com/adobe/xmp-docs/master/XMPSpecifications/XMPSpecificationPart3.pdf
std::vector<uint8_t> xmp = get_xmp_metadata(handle);
if (!xmp.empty()) {
Expand All @@ -156,6 +157,7 @@ bool PngEncoder::Encode(const struct heif_image_handle* handle,
xmp_text.itxt_length = text_length;
png_set_text(png_ptr, info_ptr, &xmp_text, 1);
}
#endif

png_write_info(png_ptr, info_ptr);

Expand Down
2 changes: 1 addition & 1 deletion examples/heif_convert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ void list_all_decoders()
std::cout << "JPEG decoders:\n";
list_decoders(heif_compression_JPEG);

std::cout << "JPEG-2000 decoders:\n";
std::cout << "JPEG 2000 decoders:\n";
list_decoders(heif_compression_JPEG2000);

#if WITH_UNCOMPRESSED_CODEC
Expand Down
34 changes: 29 additions & 5 deletions examples/heif_enc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ int metadata_compression = 0;
const char* encoderId = nullptr;
std::string chroma_downsampling;

uint16_t nclx_colour_primaries = 1;
uint16_t nclx_transfer_characteristic = 13;
uint16_t nclx_matrix_coefficients = 6;
uint16_t nclx_colour_primaries = 2;
uint16_t nclx_transfer_characteristic = 2;
int nclx_full_range = true;

std::string property_pitm_description;
Expand Down Expand Up @@ -160,7 +160,7 @@ void show_help(const char* argv0)
<< " -p set encoder parameter (NAME=VALUE)\n"
<< " -A, --avif encode as AVIF (not needed if output filename with .avif suffix is provided)\n"
<< " --jpeg encode as JPEG\n"
<< " --jpeg2000 encode as JPEG-2000 (experimental)\n"
<< " --jpeg2000 encode as JPEG 2000 (experimental)\n"
#if WITH_UNCOMPRESSED_CODEC
<< " -U, --uncompressed encode as uncompressed image (according to ISO 23001-17) (EXPERIMENTAL)\n"
#endif
Expand Down Expand Up @@ -349,6 +349,30 @@ static void show_list_of_encoders(const heif_encoder_descriptor* const* encoder_
}


static const char* get_compression_format_name(heif_compression_format format)
{
switch (format) {
case heif_compression_AV1:
return "AV1";
break;
case heif_compression_HEVC:
return "HEVC";
break;
case heif_compression_JPEG:
return "JPEG";
break;
case heif_compression_JPEG2000:
return "JPEG 2000";
break;
case heif_compression_uncompressed:
return "Uncompressed";
break;
default:
assert(false);
return "unknown";
}
}

static void show_list_of_all_encoders()
{
for (auto compression_format : {heif_compression_HEVC, heif_compression_AV1, heif_compression_JPEG, heif_compression_JPEG2000
Expand All @@ -368,7 +392,7 @@ static void show_list_of_all_encoders()
std::cout << "JPEG";
break;
case heif_compression_JPEG2000:
std::cout << "JPEG-2000";
std::cout << "JPEG 2000";
break;
case heif_compression_uncompressed:
std::cout << "Uncompressed";
Expand Down Expand Up @@ -687,7 +711,7 @@ int main(int argc, char** argv)
active_encoder_descriptor = encoder_descriptors[idx];
}
else {
std::cerr << "No " << (compressionFormat == heif_compression_AV1 ? "AV1" : "HEVC") << " encoder available.\n";
std::cerr << "No " << get_compression_format_name(compressionFormat) << " encoder available.\n";
return 5;
}

Expand Down
75 changes: 73 additions & 2 deletions libheif/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Fraction::Fraction(int64_t num, int64_t den)
Fraction Fraction::operator+(const Fraction& b) const
{
if (denominator == b.denominator) {
int64_t n = numerator + b.numerator;
int64_t n = int64_t{numerator} + b.numerator;
int64_t d = denominator;
return Fraction{n,d};
}
Expand All @@ -99,7 +99,7 @@ Fraction Fraction::operator+(const Fraction& b) const
Fraction Fraction::operator-(const Fraction& b) const
{
if (denominator == b.denominator) {
int64_t n = numerator - b.numerator;
int64_t n = int64_t{numerator} - b.numerator;
int64_t d = denominator;
return Fraction{n,d};
}
Expand Down Expand Up @@ -3087,3 +3087,74 @@ Error Box_udes::write(StreamWriter& writer) const
prepend_header(writer, box_start);
return Error::Ok;
}



std::string Box_taic::dump(Indent& indent) const {
std::ostringstream sstr;
sstr << Box::dump(indent);
sstr << indent << "time_uncertainty: " << m_time_uncertainty << "\n";
sstr << indent << "correction_offset: " << m_correction_offset << "\n";
sstr << indent << "clock_drift_rate: " << m_clock_drift_rate << "\n";
sstr << indent << "clock_source: " << m_clock_source << "\n";
return sstr.str();
}

Error Box_taic::write(StreamWriter& writer) const {
uint32_t cdr_uint32;
std::memcpy(&cdr_uint32, &m_clock_drift_rate, sizeof(float));

size_t box_start = reserve_box_header_space(writer);
writer.write64(m_time_uncertainty);
writer.write64(m_correction_offset);
writer.write32(cdr_uint32);
writer.write8(m_clock_source);

prepend_header(writer, box_start);

return Error::Ok;
}

Error Box_taic::parse(BitstreamRange& range) {
parse_full_box_header(range);

uint64_t high = range.read32();
uint64_t low = range.read32();
m_time_uncertainty = (high << 32) | low;

high = range.read32();
low = range.read32();
m_correction_offset = (high << 32) | low;

m_clock_drift_rate = (float) range.read32();
m_clock_source = range.read8();
return range.get_error();
}

std::string Box_itai::dump(Indent& indent) const {
std::ostringstream sstr;
sstr << Box::dump(indent);
sstr << indent << "TAI_timestamp: " << m_TAI_timestamp << "\n";
sstr << indent << "status_bits: " << m_status_bits << "\n";
return sstr.str();
}

Error Box_itai::write(StreamWriter& writer) const {
size_t box_start = reserve_box_header_space(writer);
writer.write64(m_TAI_timestamp);
writer.write8(m_status_bits);

prepend_header(writer, box_start);
return Error::Ok;
}

Error Box_itai::parse(BitstreamRange& range) {
parse_full_box_header(range);

uint64_t high = range.read32();
uint64_t low = range.read32();
m_TAI_timestamp = (high << 32) | low;

m_status_bits = range.read8();
return range.get_error();
}
108 changes: 108 additions & 0 deletions libheif/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -1058,4 +1058,112 @@ class Box_udes : public FullBox
std::string m_tags;
};



class Box_taic : public FullBox
{
public:
Box_taic()
{
set_short_type(fourcc("taic"));
}

std::string dump(Indent&) const override;

Error write(StreamWriter& writer) const override;

/**
* time_uncertainty.
*
* The standard deviation measurement uncertainty in nanoseconds
* for the timestamp generation process.
*/
void set_time_uncertainty(uint64_t time_uncertainty) { m_time_uncertainty = time_uncertainty;}

/**
* correction_offset.
*
* The difference in nanoseconds between the clock’s reported
* timestamp and true time value of the measurement event.
*/
void set_correction_offset(int64_t correction_offset) { m_correction_offset = correction_offset; }

/**
* clock_drift_rate.
*
* The difference between the synchronized and unsynchronized
* time, over a period of one second.
*/
void set_clock_drift_rate(float clock_drift_rate) { m_clock_drift_rate = clock_drift_rate; }

/**
* clock_source.
*
* 0 = Clock type is unkown
* 1 = The clock does not synchronize to an atomic source of absolute TAI time
* 2 = The clock can synchronize to an atomic source of absolute TAI time
*/
void set_clock_source(uint8_t clock_source) { m_clock_source = clock_source; }

uint64_t get_time_uncertainty() const { return m_time_uncertainty; }

int64_t get_correction_offset() const { return m_correction_offset; }

float get_clock_drift_rate() const { return m_clock_drift_rate; }

uint8_t get_clock_source() const { return m_clock_source; }

protected:
Error parse(BitstreamRange& range) override;

private:
// Initialized to "unknown"
uint64_t m_time_uncertainty = 0xFFFFFFFFFFFFFFFF;
int64_t m_correction_offset = 0x7FFFFFFFFFFFFFFF;
float m_clock_drift_rate = std::numeric_limits<float>::quiet_NaN();
uint8_t m_clock_source = 0;
};


class Box_itai : public FullBox
{
public:
Box_itai()
{
set_short_type(fourcc("itai"));
}

std::string dump(Indent&) const override;

Error write(StreamWriter& writer) const override;

/**
* timestamp.
*
* The number of nanoseconds since the TAI epoch of 1958-01-01T00:00:00.0Z.
*/
void set_TAI_timestamp(uint64_t timestamp) { m_TAI_timestamp = timestamp; }

/**
* status_bits.
*
* Bit 0: Synchronization Status (0=unsynchronized, 1=synchronized)
* Bit 1: Timestamp validity (0=invalid, 1=valid)
* Bits 2-7: Reserved
*/
void set_status_bits(uint8_t status_bits) { m_status_bits = status_bits; }

uint64_t get_TAI_timestamp() const { return m_TAI_timestamp; }

uint8_t get_status_bits() const { return m_status_bits; }

protected:
Error parse(BitstreamRange& range) override;

private:
// Initialized to "unknown"
uint64_t m_TAI_timestamp = 0xFFFFFFFFFFFFFFFF;
uint8_t m_status_bits = 0;
};

#endif
21 changes: 4 additions & 17 deletions libheif/color-conversion/colorconversion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,7 @@ std::shared_ptr<HeifPixelImage> ColorConversionPipeline::convert_image(const std

// --- pass the color profiles to the new image

auto output_nclx = std::make_shared<color_profile_nclx>();
*output_nclx = step.output_state.nclx_profile;
auto output_nclx = std::make_shared<color_profile_nclx>(step.output_state.nclx_profile);
out->set_color_profile_nclx(output_nclx);
out->set_color_profile_icc(in->get_color_profile_icc());

Expand Down Expand Up @@ -521,19 +520,7 @@ std::shared_ptr<HeifPixelImage> convert_colorspace(const std::shared_ptr<HeifPix
input_state.nclx_profile = *input->get_color_profile_nclx();
}

// If some input nclx values are unspecified, use CCIR-601 values as default.

if (input_state.nclx_profile.get_matrix_coefficients() == heif_matrix_coefficients_unspecified) {
input_state.nclx_profile.set_matrix_coefficients(heif_matrix_coefficients_ITU_R_BT_601_6);
}

if (input_state.nclx_profile.get_colour_primaries() == heif_color_primaries_unspecified) {
input_state.nclx_profile.set_colour_primaries(heif_color_primaries_ITU_R_BT_601_6);
}

if (input_state.nclx_profile.get_transfer_characteristics() == heif_color_primaries_unspecified) {
input_state.nclx_profile.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_601_6);
}
input_state.nclx_profile.replace_undefined_values_with_sRGB_defaults();

std::set<enum heif_channel> channels = input->get_channel_set();
assert(!channels.empty());
Expand All @@ -546,7 +533,7 @@ std::shared_ptr<HeifPixelImage> convert_colorspace(const std::shared_ptr<HeifPix
output_state.nclx_profile = *target_profile;
}

// If some output nclx values are unspecified, set the to the same as the input.
// If some output nclx values are unspecified, set them to the same as the input.

if (output_state.nclx_profile.get_matrix_coefficients() == heif_matrix_coefficients_unspecified) {
output_state.nclx_profile.set_matrix_coefficients(input_state.nclx_profile.get_matrix_coefficients());
Expand All @@ -556,7 +543,7 @@ std::shared_ptr<HeifPixelImage> convert_colorspace(const std::shared_ptr<HeifPix
output_state.nclx_profile.set_colour_primaries(input_state.nclx_profile.get_colour_primaries());
}

if (output_state.nclx_profile.get_transfer_characteristics() == heif_color_primaries_unspecified) {
if (output_state.nclx_profile.get_transfer_characteristics() == heif_transfer_characteristic_unspecified) {
output_state.nclx_profile.set_transfer_characteristics(input_state.nclx_profile.get_transfer_characteristics());
}

Expand Down
Loading