Message ID | 725ad573-5e22-84a3-b12f-e68baa2b3980@vimeo.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,1/2] avcodec/avutil: move dynamic HDR metadata parsing to libavutil | expand |
Context | Check | Description |
---|---|---|
yinshiyou/make_loongarch64 | success | Make finished |
yinshiyou/make_fate_loongarch64 | success | Make fate finished |
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
On 27/02/2023 12.34, Raphaël Zumer wrote: > Resent due to my mail client incorrectly re-wrapping lines in the version I sent earlier. > See the previous patch for context. > > Signed-off-by: Raphaël Zumer<rzumer@tebako.net> > --- > libavutil/hdr_dynamic_metadata.c | 147 +++++++++++++++++++++++++++++++ > libavutil/hdr_dynamic_metadata.h | 10 +++ > libavutil/version.h | 2 +- > 3 files changed, 158 insertions(+), 1 deletion(-) > > diff --git a/libavutil/hdr_dynamic_metadata.c b/libavutil/hdr_dynamic_metadata.c > index 98f399b032..72d310e633 100644 > --- a/libavutil/hdr_dynamic_metadata.c > +++ b/libavutil/hdr_dynamic_metadata.c > @@ -225,3 +225,150 @@ int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, > > return 0; > } > + > +AVBufferRef *av_dynamic_hdr_plus_to_t35(AVDynamicHDRPlus *s) > +{ > + AVBufferRef *buf; > + size_t size_bits, size_bytes; > + PutBitContext pbc, *pb = &pbc; > + > + if (!s) > + return NULL; > + > + // Buffer size per CTA-861-H p.253-254: > + size_bits = > + // 56 bits for the header > + 58 + > + // 2 bits for num_windows > + 2 + > + // 937 bits for window geometry for each window above 1 > + FFMAX((s->num_windows - 1), 0) * 937 + > + // 27 bits for targeted_system_display_maximum_luminance > + 27 + > + // 1-3855 bits for targeted system display peak luminance information > + 1 + (s->targeted_system_display_actual_peak_luminance_flag ? 10 + > + s->num_rows_targeted_system_display_actual_peak_luminance * > + s->num_cols_targeted_system_display_actual_peak_luminance * 4 : 0) + > + // 0-442 bits for intra-window pixel distribution information > + s->num_windows * 82; > + for (int w = 0; w < s->num_windows; w++) { > + size_bits += s->params[w].num_distribution_maxrgb_percentiles * 24; > + } > + // 1-3855 bits for mastering display peak luminance information > + size_bits += 1 + (s->mastering_display_actual_peak_luminance_flag ? 10 + > + s->num_rows_mastering_display_actual_peak_luminance * > + s->num_cols_mastering_display_actual_peak_luminance * 4 : 0) + > + // 0-537 bits for per-window tonemapping information > + s->num_windows * 1; > + for (int w = 0; w < s->num_windows; w++) { > + if (s->params[w].tone_mapping_flag) { > + size_bits += 28 + s->params[w].num_bezier_curve_anchors * 10; > + } > + } > + // 0-21 bits for per-window color saturation mapping information > + size_bits += s->num_windows * 1; > + for (int w = 0; w < s->num_windows; w++) { > + if (s->params[w].color_saturation_mapping_flag) { > + size_bits += 6; > + } > + } > + > + size_bytes = (size_bits + 7) / 8; > + > + buf = av_buffer_alloc(size_bytes); > + if (!buf) { > + return NULL; > + } > + > + init_put_bits(pb, buf->data, size_bytes); > + > + // itu_t_t35_country_code shall be 0xB5 (USA) > + put_bits(pb, 8, 0xB5); This patch series mentions that it would be used for AV1, however the AV1 specification is clear that the payload does not contain the country code. https://aomediacodec.github.io/av1-hdr10plus/#hdr10plus-metadata, Figure 1. So far all the AV1 HDR10+ conformance samples also respect this. There would probably be a need to specify which behaviour is wanted. The SEI for HEVC does keep the country code in the payload, but not AV1. > + // itu_t_t35_terminal_provider_code shall be 0x003C > + put_bits(pb, 16, 0x003C); > + // itu_t_t35_terminal_provider_oriented_code is set to ST 2094-40 > + put_bits(pb, 16, 0x0001); > + // application_identifier shall be set to 4 > + put_bits(pb, 8, 4); > + // application_mode is set to Application Version 1 > + put_bits(pb, 8, 1); > + > + // Payload as per CTA-861-H p.253-254 > + put_bits(pb, 2, s->num_windows); > + > + for (int w = 1; w < s->num_windows; w++) { > + put_bits(pb, 16, s->params[w].window_upper_left_corner_x.num / s->params[w].window_upper_left_corner_x.den); > + put_bits(pb, 16, s->params[w].window_upper_left_corner_y.num / s->params[w].window_upper_left_corner_y.den); > + put_bits(pb, 16, s->params[w].window_lower_right_corner_x.num / s->params[w].window_lower_right_corner_x.den); > + put_bits(pb, 16, s->params[w].window_lower_right_corner_y.num / s->params[w].window_lower_right_corner_y.den); > + put_bits(pb, 16, s->params[w].center_of_ellipse_x); > + put_bits(pb, 16, s->params[w].center_of_ellipse_y); > + put_bits(pb, 8, s->params[w].rotation_angle); > + put_bits(pb, 16, s->params[w].semimajor_axis_internal_ellipse); > + put_bits(pb, 16, s->params[w].semimajor_axis_external_ellipse); > + put_bits(pb, 16, s->params[w].semiminor_axis_external_ellipse); > + put_bits(pb, 1, s->params[w].overlap_process_option); > + } > + > + put_bits(pb, 27, s->targeted_system_display_maximum_luminance.num * luminance_den / > + s->targeted_system_display_maximum_luminance.den); > + put_bits(pb, 1, s->targeted_system_display_actual_peak_luminance_flag); > + if (s->targeted_system_display_actual_peak_luminance_flag) { > + put_bits(pb, 5, s->num_rows_targeted_system_display_actual_peak_luminance); > + put_bits(pb, 5, s->num_cols_targeted_system_display_actual_peak_luminance); > + for (int i = 0; i < s->num_rows_targeted_system_display_actual_peak_luminance; i++) { > + for (int j = 0; j < s->num_cols_targeted_system_display_actual_peak_luminance; j++) { > + put_bits(pb, 4, s->targeted_system_display_actual_peak_luminance[i][j].num * peak_luminance_den / > + s->targeted_system_display_actual_peak_luminance[i][j].den); > + } > + } > + } > + > + for (int w = 0; w < s->num_windows; w++) { > + for (int i = 0; i < 3; i++) { > + put_bits(pb, 17, s->params[w].maxscl[i].num * rgb_den / s->params[w].maxscl[i].den); > + } > + put_bits(pb, 17, s->params[w].average_maxrgb.num * rgb_den / s->params[w].average_maxrgb.den); > + put_bits(pb, 4, s->params[w].num_distribution_maxrgb_percentiles); > + for (int i = 0; i < s->params[w].num_distribution_maxrgb_percentiles; i++) { > + put_bits(pb, 7, s->params[w].distribution_maxrgb[i].percentage); > + put_bits(pb, 17, s->params[w].distribution_maxrgb[i].percentile.num * rgb_den / > + s->params[w].distribution_maxrgb[i].percentile.den); > + } > + put_bits(pb, 10, s->params[w].fraction_bright_pixels.num * fraction_pixel_den / > + s->params[w].fraction_bright_pixels.den); > + } > + > + put_bits(pb, 1, s->mastering_display_actual_peak_luminance_flag); > + if (s->mastering_display_actual_peak_luminance_flag) { > + put_bits(pb, 5, s->num_rows_mastering_display_actual_peak_luminance); > + put_bits(pb, 5, s->num_cols_mastering_display_actual_peak_luminance); > + for (int i = 0; i < s->num_rows_mastering_display_actual_peak_luminance; i++) { > + for (int j = 0; j < s->num_cols_mastering_display_actual_peak_luminance; j++) { > + put_bits(pb, 4, s->mastering_display_actual_peak_luminance[i][j].num * peak_luminance_den / > + s->mastering_display_actual_peak_luminance[i][j].den); > + } > + } > + } > + > + for (int w = 0; w < s->num_windows; w++) { > + put_bits(pb, 1, s->params[w].tone_mapping_flag); > + if (s->params[w].tone_mapping_flag) { > + put_bits(pb, 12, s->params[w].knee_point_x.num * knee_point_den / s->params[w].knee_point_x.den); > + put_bits(pb, 12, s->params[w].knee_point_y.num * knee_point_den / s->params[w].knee_point_y.den); > + put_bits(pb, 4, s->params[w].num_bezier_curve_anchors); > + for (int i = 0; i < s->params[w].num_bezier_curve_anchors; i++) { > + put_bits(pb, 10, s->params[w].bezier_curve_anchors[i].num * bezier_anchor_den / > + s->params[w].bezier_curve_anchors[i].den); > + } > + put_bits(pb, 1, s->params[w].color_saturation_mapping_flag); > + if (s->params[w].color_saturation_mapping_flag) { > + put_bits(pb, 6, s->params[w].color_saturation_weight.num * saturation_weight_den / > + s->params[w].color_saturation_weight.den); > + } > + } > + } > + > + flush_put_bits(pb); > + return buf; > +} > diff --git a/libavutil/hdr_dynamic_metadata.h b/libavutil/hdr_dynamic_metadata.h > index 1f953ef1f5..f75d3e0739 100644 > --- a/libavutil/hdr_dynamic_metadata.h > +++ b/libavutil/hdr_dynamic_metadata.h > @@ -21,6 +21,7 @@ > #ifndef AVUTIL_HDR_DYNAMIC_METADATA_H > #define AVUTIL_HDR_DYNAMIC_METADATA_H > > +#include "buffer.h" > #include "frame.h" > #include "rational.h" > > @@ -351,4 +352,13 @@ AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame); > int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, > int size); > > +/** > + * Serialize dynamic HDR10+ metadata to a user data registered ITU-T T.35 buffer. > + * @param s A pointer containing the decoded AVDynamicHDRPlus structure. > + * > + * @return Pointer to an AVBufferRef containing the raw ITU-T T.35 representation > + * of the HDR10+ metadata if succeed, or NULL if buffer allocation fails. > + */ > +AVBufferRef *av_dynamic_hdr_plus_to_t35(AVDynamicHDRPlus *s); > + > #endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ > diff --git a/libavutil/version.h b/libavutil/version.h > index 900b798971..7635672985 100644 > --- a/libavutil/version.h > +++ b/libavutil/version.h > @@ -79,7 +79,7 @@ > */ > > #define LIBAVUTIL_VERSION_MAJOR 58 > -#define LIBAVUTIL_VERSION_MINOR 3 > +#define LIBAVUTIL_VERSION_MINOR 4 > #define LIBAVUTIL_VERSION_MICRO 100 > > #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
On 3/2/23 13:33, quietvoid wrote: > This patch series mentions that it would be used for AV1, however the AV1 > specification is clear that the payload does not contain the country code. > https://aomediacodec.github.io/av1-hdr10plus/#hdr10plus-metadata, Figure 1. > > So far all the AV1 HDR10+ conformance samples also respect this. > There would probably be a need to specify which behaviour is wanted. > The SEI for HEVC does keep the country code in the payload, but not AV1. As you pointed out, HEVC does include the country code in the payload, so either approach can be seen as reasonable. There are a few reasons why I don't think it makes sense to reproduce the AV1 specification: - it does not make sense to exclude the country code from the payload while including other static headers like the terminal provider codes and the application identifier, so there is no particular advantage or logic that I can see in splitting the payload in that way. - pragmatically, it is much less inconvenient to deal with a 1-byte offset in the payload for AV1 than it is to insert that byte into the payload for HEVC and other applications that expect the country code to be included in the header. For the same reason, I think that an option to include or exclude the country code byte would be more trouble than it's worth. - perhaps most importantly, the payload syntax is standardized in ANSI/CTA-861-H, which does not make any distinction between the header (country code, terminal provider code, etc.) and the remainder of the payload, so the AV1 specification does not conform either to other implementations nor to the standard. Following the most authoritative document is the safest route in my opinion. Raphaël Zumer
On 3/2/2023 3:33 PM, quietvoid wrote:> On 27/02/2023 12.34, Raphaël Zumer wrote: > >> Resent due to my mail client incorrectly re-wrapping lines in the >> version I sent earlier. >> See the previous patch for context. >> >> Signed-off-by: Raphaël Zumer<rzumer@tebako.net> >> --- >> libavutil/hdr_dynamic_metadata.c | 147 +++++++++++++++++++++++++++++++ >> libavutil/hdr_dynamic_metadata.h | 10 +++ >> libavutil/version.h | 2 +- >> 3 files changed, 158 insertions(+), 1 deletion(-) >> >> diff --git a/libavutil/hdr_dynamic_metadata.c >> b/libavutil/hdr_dynamic_metadata.c >> index 98f399b032..72d310e633 100644 >> --- a/libavutil/hdr_dynamic_metadata.c >> +++ b/libavutil/hdr_dynamic_metadata.c >> @@ -225,3 +225,150 @@ int >> av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, >> return 0; >> } >> + >> +AVBufferRef *av_dynamic_hdr_plus_to_t35(AVDynamicHDRPlus *s) >> +{ >> + AVBufferRef *buf; >> + size_t size_bits, size_bytes; >> + PutBitContext pbc, *pb = &pbc; >> + >> + if (!s) >> + return NULL; >> + >> + // Buffer size per CTA-861-H p.253-254: >> + size_bits = >> + // 56 bits for the header >> + 58 + >> + // 2 bits for num_windows >> + 2 + >> + // 937 bits for window geometry for each window above 1 >> + FFMAX((s->num_windows - 1), 0) * 937 + >> + // 27 bits for targeted_system_display_maximum_luminance >> + 27 + >> + // 1-3855 bits for targeted system display peak luminance >> information >> + 1 + (s->targeted_system_display_actual_peak_luminance_flag ? 10 + >> + s->num_rows_targeted_system_display_actual_peak_luminance * >> + s->num_cols_targeted_system_display_actual_peak_luminance * 4 >> : 0) + >> + // 0-442 bits for intra-window pixel distribution information >> + s->num_windows * 82; >> + for (int w = 0; w < s->num_windows; w++) { >> + size_bits += s->params[w].num_distribution_maxrgb_percentiles >> * 24; >> + } >> + // 1-3855 bits for mastering display peak luminance information >> + size_bits += 1 + (s->mastering_display_actual_peak_luminance_flag >> ? 10 + >> + s->num_rows_mastering_display_actual_peak_luminance * >> + s->num_cols_mastering_display_actual_peak_luminance * 4 : 0) + >> + // 0-537 bits for per-window tonemapping information >> + s->num_windows * 1; >> + for (int w = 0; w < s->num_windows; w++) { >> + if (s->params[w].tone_mapping_flag) { >> + size_bits += 28 + s->params[w].num_bezier_curve_anchors * >> 10; >> + } >> + } >> + // 0-21 bits for per-window color saturation mapping information >> + size_bits += s->num_windows * 1; >> + for (int w = 0; w < s->num_windows; w++) { >> + if (s->params[w].color_saturation_mapping_flag) { >> + size_bits += 6; >> + } >> + } >> + >> + size_bytes = (size_bits + 7) / 8; >> + >> + buf = av_buffer_alloc(size_bytes); >> + if (!buf) { >> + return NULL; >> + } >> + >> + init_put_bits(pb, buf->data, size_bytes); >> + >> + // itu_t_t35_country_code shall be 0xB5 (USA) >> + put_bits(pb, 8, 0xB5); > > This patch series mentions that it would be used for AV1, however the AV1 > specification is clear that the payload does not contain the country code. > https://aomediacodec.github.io/av1-hdr10plus/#hdr10plus-metadata, Figure 1. > > So far all the AV1 HDR10+ conformance samples also respect this. > There would probably be a need to specify which behaviour is wanted. > The SEI for HEVC does keep the country code in the payload, but not AV1. Are you sure about HEVC? I just checked a sample and trace_headers reported this: [trace_headers] Prefix Supplemental Enhancement Information [trace_headers] 0 forbidden_zero_bit 0 = 0 [trace_headers] 1 nal_unit_type 100111 = 39 [trace_headers] 7 nuh_layer_id 000000 = 0 [trace_headers] 13 nuh_temporal_id_plus1 001 = 1 [trace_headers] 16 last_payload_type_byte 00000100 = 4 [trace_headers] 24 last_payload_size_byte 01000000 = 64 [trace_headers] User Data Registered ITU-T T.35 [trace_headers] 32 itu_t_t35_country_code 10110101 = 181 [trace_headers] 40 itu_t_t35_payload_byte[1] 00000000 = 0 [trace_headers] 48 itu_t_t35_payload_byte[2] 00111100 = 60 [trace_headers] 56 itu_t_t35_payload_byte[3] 00000000 = 0 [trace_headers] 64 itu_t_t35_payload_byte[4] 00000001 = 1 [trace_headers] 72 itu_t_t35_payload_byte[5] 00000100 = 4 [trace_headers] 80 itu_t_t35_payload_byte[6] 00000001 = 1 Which is in line with section 8.3.1 of ITU-T Rec. H.274 as well as section D.2.6 of ITU-T Rec. H.265. So i think this function should not set the country code at all as part of the payload, and start with itu_t_t35_terminal_provider_code.
On 3/2/23 13:57, James Almer wrote: > > The SEI for HEVC does keep the country code in the payload, but not AV1. > Are you sure about HEVC? I just checked a sample and trace_headers > reported this: > > [trace_headers] Prefix Supplemental Enhancement Information > [trace_headers] 0 forbidden_zero_bit 0 = 0 > [trace_headers] 1 nal_unit_type 100111 = 39 > [trace_headers] 7 nuh_layer_id 000000 = 0 > [trace_headers] 13 nuh_temporal_id_plus1 001 = 1 > [trace_headers] 16 last_payload_type_byte 00000100 = 4 > [trace_headers] 24 last_payload_size_byte 01000000 = 64 > [trace_headers] User Data Registered ITU-T T.35 > [trace_headers] 32 itu_t_t35_country_code 10110101 = 181 > [trace_headers] 40 itu_t_t35_payload_byte[1] 00000000 = 0 > [trace_headers] 48 itu_t_t35_payload_byte[2] 00111100 = 60 > [trace_headers] 56 itu_t_t35_payload_byte[3] 00000000 = 0 > [trace_headers] 64 itu_t_t35_payload_byte[4] 00000001 = 1 > [trace_headers] 72 itu_t_t35_payload_byte[5] 00000100 = 4 > [trace_headers] 80 itu_t_t35_payload_byte[6] 00000001 = 1 > > Which is in line with section 8.3.1 of ITU-T Rec. H.274 as well as > section D.2.6 of ITU-T Rec. H.265. > > So i think this function should not set the country code at all as part > of the payload, and start with itu_t_t35_terminal_provider_code. OK, I will make that change since both HEVC and AV1 implementations seem to match. Thanks Raphaël Zumer
diff --git a/libavutil/hdr_dynamic_metadata.c b/libavutil/hdr_dynamic_metadata.c index 98f399b032..72d310e633 100644 --- a/libavutil/hdr_dynamic_metadata.c +++ b/libavutil/hdr_dynamic_metadata.c @@ -225,3 +225,150 @@ int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, return 0; } + +AVBufferRef *av_dynamic_hdr_plus_to_t35(AVDynamicHDRPlus *s) +{ + AVBufferRef *buf; + size_t size_bits, size_bytes; + PutBitContext pbc, *pb = &pbc; + + if (!s) + return NULL; + + // Buffer size per CTA-861-H p.253-254: + size_bits = + // 56 bits for the header + 58 + + // 2 bits for num_windows + 2 + + // 937 bits for window geometry for each window above 1 + FFMAX((s->num_windows - 1), 0) * 937 + + // 27 bits for targeted_system_display_maximum_luminance + 27 + + // 1-3855 bits for targeted system display peak luminance information + 1 + (s->targeted_system_display_actual_peak_luminance_flag ? 10 + + s->num_rows_targeted_system_display_actual_peak_luminance * + s->num_cols_targeted_system_display_actual_peak_luminance * 4 : 0) + + // 0-442 bits for intra-window pixel distribution information + s->num_windows * 82; + for (int w = 0; w < s->num_windows; w++) { + size_bits += s->params[w].num_distribution_maxrgb_percentiles * 24; + } + // 1-3855 bits for mastering display peak luminance information + size_bits += 1 + (s->mastering_display_actual_peak_luminance_flag ? 10 + + s->num_rows_mastering_display_actual_peak_luminance * + s->num_cols_mastering_display_actual_peak_luminance * 4 : 0) + + // 0-537 bits for per-window tonemapping information + s->num_windows * 1; + for (int w = 0; w < s->num_windows; w++) { + if (s->params[w].tone_mapping_flag) { + size_bits += 28 + s->params[w].num_bezier_curve_anchors * 10; + } + } + // 0-21 bits for per-window color saturation mapping information + size_bits += s->num_windows * 1; + for (int w = 0; w < s->num_windows; w++) { + if (s->params[w].color_saturation_mapping_flag) { + size_bits += 6; + } + } + + size_bytes = (size_bits + 7) / 8; + + buf = av_buffer_alloc(size_bytes); + if (!buf) { + return NULL; + } + + init_put_bits(pb, buf->data, size_bytes); + + // itu_t_t35_country_code shall be 0xB5 (USA) + put_bits(pb, 8, 0xB5); + // itu_t_t35_terminal_provider_code shall be 0x003C + put_bits(pb, 16, 0x003C); + // itu_t_t35_terminal_provider_oriented_code is set to ST 2094-40 + put_bits(pb, 16, 0x0001); + // application_identifier shall be set to 4 + put_bits(pb, 8, 4); + // application_mode is set to Application Version 1 + put_bits(pb, 8, 1); + + // Payload as per CTA-861-H p.253-254 + put_bits(pb, 2, s->num_windows); + + for (int w = 1; w < s->num_windows; w++) { + put_bits(pb, 16, s->params[w].window_upper_left_corner_x.num / s->params[w].window_upper_left_corner_x.den); + put_bits(pb, 16, s->params[w].window_upper_left_corner_y.num / s->params[w].window_upper_left_corner_y.den); + put_bits(pb, 16, s->params[w].window_lower_right_corner_x.num / s->params[w].window_lower_right_corner_x.den); + put_bits(pb, 16, s->params[w].window_lower_right_corner_y.num / s->params[w].window_lower_right_corner_y.den); + put_bits(pb, 16, s->params[w].center_of_ellipse_x); + put_bits(pb, 16, s->params[w].center_of_ellipse_y); + put_bits(pb, 8, s->params[w].rotation_angle); + put_bits(pb, 16, s->params[w].semimajor_axis_internal_ellipse); + put_bits(pb, 16, s->params[w].semimajor_axis_external_ellipse); + put_bits(pb, 16, s->params[w].semiminor_axis_external_ellipse); + put_bits(pb, 1, s->params[w].overlap_process_option); + } + + put_bits(pb, 27, s->targeted_system_display_maximum_luminance.num * luminance_den / + s->targeted_system_display_maximum_luminance.den); + put_bits(pb, 1, s->targeted_system_display_actual_peak_luminance_flag); + if (s->targeted_system_display_actual_peak_luminance_flag) { + put_bits(pb, 5, s->num_rows_targeted_system_display_actual_peak_luminance); + put_bits(pb, 5, s->num_cols_targeted_system_display_actual_peak_luminance); + for (int i = 0; i < s->num_rows_targeted_system_display_actual_peak_luminance; i++) { + for (int j = 0; j < s->num_cols_targeted_system_display_actual_peak_luminance; j++) { + put_bits(pb, 4, s->targeted_system_display_actual_peak_luminance[i][j].num * peak_luminance_den / + s->targeted_system_display_actual_peak_luminance[i][j].den); + } + } + } + + for (int w = 0; w < s->num_windows; w++) { + for (int i = 0; i < 3; i++) { + put_bits(pb, 17, s->params[w].maxscl[i].num * rgb_den / s->params[w].maxscl[i].den); + } + put_bits(pb, 17, s->params[w].average_maxrgb.num * rgb_den / s->params[w].average_maxrgb.den); + put_bits(pb, 4, s->params[w].num_distribution_maxrgb_percentiles); + for (int i = 0; i < s->params[w].num_distribution_maxrgb_percentiles; i++) { + put_bits(pb, 7, s->params[w].distribution_maxrgb[i].percentage); + put_bits(pb, 17, s->params[w].distribution_maxrgb[i].percentile.num * rgb_den / + s->params[w].distribution_maxrgb[i].percentile.den); + } + put_bits(pb, 10, s->params[w].fraction_bright_pixels.num * fraction_pixel_den / + s->params[w].fraction_bright_pixels.den); + } + + put_bits(pb, 1, s->mastering_display_actual_peak_luminance_flag); + if (s->mastering_display_actual_peak_luminance_flag) { + put_bits(pb, 5, s->num_rows_mastering_display_actual_peak_luminance); + put_bits(pb, 5, s->num_cols_mastering_display_actual_peak_luminance); + for (int i = 0; i < s->num_rows_mastering_display_actual_peak_luminance; i++) { + for (int j = 0; j < s->num_cols_mastering_display_actual_peak_luminance; j++) { + put_bits(pb, 4, s->mastering_display_actual_peak_luminance[i][j].num * peak_luminance_den / + s->mastering_display_actual_peak_luminance[i][j].den); + } + } + } + + for (int w = 0; w < s->num_windows; w++) { + put_bits(pb, 1, s->params[w].tone_mapping_flag); + if (s->params[w].tone_mapping_flag) { + put_bits(pb, 12, s->params[w].knee_point_x.num * knee_point_den / s->params[w].knee_point_x.den); + put_bits(pb, 12, s->params[w].knee_point_y.num * knee_point_den / s->params[w].knee_point_y.den); + put_bits(pb, 4, s->params[w].num_bezier_curve_anchors); + for (int i = 0; i < s->params[w].num_bezier_curve_anchors; i++) { + put_bits(pb, 10, s->params[w].bezier_curve_anchors[i].num * bezier_anchor_den / + s->params[w].bezier_curve_anchors[i].den); + } + put_bits(pb, 1, s->params[w].color_saturation_mapping_flag); + if (s->params[w].color_saturation_mapping_flag) { + put_bits(pb, 6, s->params[w].color_saturation_weight.num * saturation_weight_den / + s->params[w].color_saturation_weight.den); + } + } + } + + flush_put_bits(pb); + return buf; +} diff --git a/libavutil/hdr_dynamic_metadata.h b/libavutil/hdr_dynamic_metadata.h index 1f953ef1f5..f75d3e0739 100644 --- a/libavutil/hdr_dynamic_metadata.h +++ b/libavutil/hdr_dynamic_metadata.h @@ -21,6 +21,7 @@ #ifndef AVUTIL_HDR_DYNAMIC_METADATA_H #define AVUTIL_HDR_DYNAMIC_METADATA_H +#include "buffer.h" #include "frame.h" #include "rational.h" @@ -351,4 +352,13 @@ AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame); int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, int size); +/** + * Serialize dynamic HDR10+ metadata to a user data registered ITU-T T.35 buffer. + * @param s A pointer containing the decoded AVDynamicHDRPlus structure. + * + * @return Pointer to an AVBufferRef containing the raw ITU-T T.35 representation + * of the HDR10+ metadata if succeed, or NULL if buffer allocation fails. + */ +AVBufferRef *av_dynamic_hdr_plus_to_t35(AVDynamicHDRPlus *s); + #endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/libavutil/version.h b/libavutil/version.h index 900b798971..7635672985 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 58 -#define LIBAVUTIL_VERSION_MINOR 3 +#define LIBAVUTIL_VERSION_MINOR 4 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
Resent due to my mail client incorrectly re-wrapping lines in the version I sent earlier. See the previous patch for context. Signed-off-by: Raphaël Zumer <rzumer@tebako.net> --- libavutil/hdr_dynamic_metadata.c | 147 +++++++++++++++++++++++++++++++ libavutil/hdr_dynamic_metadata.h | 10 +++ libavutil/version.h | 2 +- 3 files changed, 158 insertions(+), 1 deletion(-)