You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avcodec: support for CUVA HDR Vivid metadata
Signed-off-by: Limin Wang <lance.lmwang@gmail.com>
This commit is contained in:
		| @@ -96,7 +96,7 @@ OBJS-$(CONFIG_H264PARSE)               += h264_parse.o h2645_parse.o h264_ps.o | ||||
| OBJS-$(CONFIG_H264PRED)                += h264pred.o | ||||
| OBJS-$(CONFIG_H264QPEL)                += h264qpel.o | ||||
| OBJS-$(CONFIG_HEVCPARSE)               += hevc_parse.o h2645_parse.o hevc_ps.o hevc_sei.o hevc_data.o \ | ||||
|                                           dynamic_hdr10_plus.o | ||||
|                                           dynamic_hdr10_plus.o dynamic_hdr_vivid.o | ||||
| OBJS-$(CONFIG_HPELDSP)                 += hpeldsp.o | ||||
| OBJS-$(CONFIG_HUFFMAN)                 += huffman.o | ||||
| OBJS-$(CONFIG_HUFFYUVDSP)              += huffyuvdsp.o | ||||
|   | ||||
							
								
								
									
										139
									
								
								libavcodec/dynamic_hdr_vivid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								libavcodec/dynamic_hdr_vivid.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,139 @@ | ||||
| /* | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "dynamic_hdr_vivid.h" | ||||
| #include "get_bits.h" | ||||
|  | ||||
| static const int32_t maxrgb_den = 4095; | ||||
| static const int32_t color_saturation_gain_den = 128; | ||||
| static const int32_t maximum_luminance_den = 4095; | ||||
| static const int32_t base_param_m_p_den = 16383; | ||||
| static const int32_t base_param_m_m_den = 10; | ||||
| static const int32_t base_param_m_a_den = 1023; | ||||
| static const int32_t base_param_m_b_den = 1023; | ||||
| static const int32_t base_param_m_n_den = 10; | ||||
| static const int32_t base_param_Delta_den = 127; | ||||
|  | ||||
| int ff_parse_itu_t_t35_to_dynamic_hdr_vivid(AVDynamicHDRVivid *s, const uint8_t *data, | ||||
|                                              int size) | ||||
| { | ||||
|     GetBitContext gbc, *gb = &gbc; | ||||
|     int ret; | ||||
|  | ||||
|     if (!s) | ||||
|         return AVERROR(ENOMEM); | ||||
|  | ||||
|     ret = init_get_bits8(gb, data, size); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
|     if (get_bits_left(gb) < 8) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     s->system_start_code = get_bits(gb, 8); | ||||
|     if (s->system_start_code == 0x01) { | ||||
|         s->num_windows = 1; | ||||
|  | ||||
|         if (get_bits_left(gb) < 12 * 4 * s->num_windows) | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         for (int w = 0; w < s->num_windows; w++) { | ||||
|             AVHDRVividColorTransformParams *params = &s->params[w]; | ||||
|  | ||||
|             params->minimum_maxrgb  = (AVRational){get_bits(gb, 12), maxrgb_den}; | ||||
|             params->average_maxrgb  = (AVRational){get_bits(gb, 12), maxrgb_den}; | ||||
|             params->variance_maxrgb = (AVRational){get_bits(gb, 12), maxrgb_den}; | ||||
|             params->maximum_maxrgb  = (AVRational){get_bits(gb, 12), maxrgb_den}; | ||||
|         } | ||||
|  | ||||
|         if (get_bits_left(gb) < 2 * s->num_windows) | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         for (int w = 0; w < s->num_windows; w++) { | ||||
|             AVHDRVividColorTransformParams *params = &s->params[w]; | ||||
|  | ||||
|             params->tone_mapping_mode_flag = get_bits(gb, 1); | ||||
|             if (params->tone_mapping_mode_flag) { | ||||
|                 if (get_bits_left(gb) < 1 ) | ||||
|                     return AVERROR_INVALIDDATA; | ||||
|                 params->tone_mapping_param_num = get_bits(gb, 1) + 1; | ||||
|                 for (int i = 0; i < params->tone_mapping_param_num; i++) { | ||||
|                     AVHDRVividColorToneMappingParams *tm_params = ¶ms->tm_params[i]; | ||||
|  | ||||
|                     if (get_bits_left(gb) < 13) | ||||
|                         return AVERROR_INVALIDDATA; | ||||
|                     tm_params->targeted_system_display_maximum_luminance = (AVRational){get_bits(gb, 12), maximum_luminance_den}; | ||||
|                     tm_params->base_enable_flag = get_bits(gb, 1); | ||||
|                     if (tm_params->base_enable_flag) { | ||||
|                         if (get_bits_left(gb) < (14 + 6 + 10 + 10 + 6 + 8 + 10)) | ||||
|                             return AVERROR_INVALIDDATA; | ||||
|                         tm_params->base_param_m_p = (AVRational){get_bits(gb, 14), base_param_m_p_den}; | ||||
|                         tm_params->base_param_m_m = (AVRational){get_bits(gb,  6), base_param_m_m_den}; | ||||
|                         tm_params->base_param_m_a = (AVRational){get_bits(gb, 10), base_param_m_a_den}; | ||||
|                         tm_params->base_param_m_b = (AVRational){get_bits(gb, 10), base_param_m_b_den}; | ||||
|                         tm_params->base_param_m_n = (AVRational){get_bits(gb,  6), base_param_m_n_den}; | ||||
|                         tm_params->base_param_k1 = get_bits(gb, 2); | ||||
|                         tm_params->base_param_k2 = get_bits(gb, 2); | ||||
|                         tm_params->base_param_k3 = get_bits(gb, 4); | ||||
|                         tm_params->base_param_Delta_enable_mode = get_bits(gb, 3); | ||||
|                         if (tm_params->base_param_Delta_enable_mode == 2 || tm_params->base_param_Delta_enable_mode == 6) | ||||
|                             tm_params->base_param_Delta = (AVRational){get_bits(gb, 7) * -1, base_param_Delta_den}; | ||||
|                         else | ||||
|                             tm_params->base_param_Delta = (AVRational){get_bits(gb, 7), base_param_Delta_den}; | ||||
|  | ||||
|                         if (get_bits_left(gb) < 1) | ||||
|                             return AVERROR_INVALIDDATA; | ||||
|                         tm_params->three_Spline_enable_flag = get_bits(gb, 1); | ||||
|                         if (tm_params->three_Spline_enable_flag) { | ||||
|                             if (get_bits_left(gb) < 1 + tm_params->three_Spline_num * (2 + 12 + 28 + 1)) | ||||
|                                 return AVERROR_INVALIDDATA; | ||||
|                             tm_params->three_Spline_num = get_bits(gb, 1) + 1; | ||||
|                             for (int j = 0; j < tm_params->three_Spline_num; j++) { | ||||
|                                 tm_params->three_Spline_TH_mode = get_bits(gb, 2); | ||||
|                                 if (tm_params->three_Spline_TH_mode == 0 || tm_params->three_Spline_TH_mode == 2) { | ||||
|                                     if (get_bits_left(gb) < 8) | ||||
|                                         return AVERROR_INVALIDDATA; | ||||
|                                     tm_params->three_Spline_TH_enable_MB = (AVRational){get_bits(gb, 8),  255}; | ||||
|                                 } | ||||
|                                 tm_params->three_Spline_TH_enable = (AVRational){get_bits(gb, 12),  4095}; | ||||
|                                 tm_params->three_Spline_TH_Delta1 = (AVRational){get_bits(gb, 10),  1023}; | ||||
|                                 tm_params->three_Spline_TH_Delta2 = (AVRational){get_bits(gb, 10),  1023}; | ||||
|                                 tm_params->three_Spline_enable_Strength = (AVRational){get_bits(gb,  8),  255}; | ||||
|                             } | ||||
|                         } else { | ||||
|                             tm_params->three_Spline_num     = 1; | ||||
|                             tm_params->three_Spline_TH_mode = 0; | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             params->color_saturation_mapping_flag = get_bits(gb, 1); | ||||
|             if (params->color_saturation_mapping_flag) { | ||||
|                 if (get_bits_left(gb) < 3 + params->color_saturation_num * 8) | ||||
|                     return AVERROR_INVALIDDATA; | ||||
|  | ||||
|                 params->color_saturation_num = get_bits(gb, 3); | ||||
|                 for (int i = 0; i < params->color_saturation_num; i++) { | ||||
|                     params->color_saturation_gain[i] = (AVRational){get_bits(gb, 8), color_saturation_gain_den}; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										35
									
								
								libavcodec/dynamic_hdr_vivid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								libavcodec/dynamic_hdr_vivid.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #ifndef AVCODEC_DYNAMIC_HDR_VIVID_H | ||||
| #define AVCODEC_DYNAMIC_HDR_VIVID_H | ||||
|  | ||||
| #include "libavutil/hdr_dynamic_vivid_metadata.h" | ||||
|  | ||||
| /** | ||||
|  * Parse the user data registered ITU-T T.35 to AVbuffer (AVDynamicHDRVivid). | ||||
|  * @param s A pointer containing the decoded AVDynamicHDRVivid structure. | ||||
|  * @param data The byte array containing the raw ITU-T T.35 data. | ||||
|  * @param size Size of the data array in bytes. | ||||
|  * | ||||
|  * @return 0 if succeed. Otherwise, returns the appropriate AVERROR. | ||||
|  */ | ||||
| int ff_parse_itu_t_t35_to_dynamic_hdr_vivid(AVDynamicHDRVivid *s, const uint8_t *data, | ||||
|                                              int size); | ||||
|  | ||||
| #endif /* AVCODEC_DYNAMIC_HDR_VIVID_H */ | ||||
| @@ -24,6 +24,7 @@ | ||||
|  | ||||
| #include "atsc_a53.h" | ||||
| #include "dynamic_hdr10_plus.h" | ||||
| #include "dynamic_hdr_vivid.h" | ||||
| #include "golomb.h" | ||||
| #include "hevc_ps.h" | ||||
| #include "hevc_sei.h" | ||||
| @@ -245,6 +246,34 @@ static int decode_registered_user_data_dynamic_hdr_plus(HEVCSEIDynamicHDRPlus *s | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int decode_registered_user_data_dynamic_hdr_vivid(HEVCSEIDynamicHDRVivid *s, | ||||
|                                                         GetBitContext *gb, int size) | ||||
| { | ||||
|     size_t meta_size; | ||||
|     int err; | ||||
|     AVDynamicHDRVivid *metadata = av_dynamic_hdr_vivid_alloc(&meta_size); | ||||
|     if (!metadata) | ||||
|         return AVERROR(ENOMEM); | ||||
|  | ||||
|     err = ff_parse_itu_t_t35_to_dynamic_hdr_vivid(metadata, | ||||
|                                                   gb->buffer + get_bits_count(gb) / 8, size); | ||||
|     if (err < 0) { | ||||
|         av_free(metadata); | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     av_buffer_unref(&s->info); | ||||
|     s->info = av_buffer_create((uint8_t *)metadata, meta_size, NULL, NULL, 0); | ||||
|     if (!s->info) { | ||||
|         av_free(metadata); | ||||
|         return AVERROR(ENOMEM); | ||||
|     } | ||||
|  | ||||
|     skip_bits_long(gb, size * 8); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetBitContext *gb, | ||||
|                                                          void *logctx, int size) | ||||
| { | ||||
| @@ -263,9 +292,9 @@ static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetBitConte | ||||
|         size--; | ||||
|     } | ||||
|  | ||||
|     if (country_code != 0xB5) { // usa_country_code | ||||
|     if (country_code != 0xB5 && country_code != 0x26) { // usa_country_code and cn_country_code | ||||
|         av_log(logctx, AV_LOG_VERBOSE, | ||||
|                "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d)\n", | ||||
|                "Unsupported User Data Registered ITU-T T35 SEI message (country_code = 0x%x)\n", | ||||
|                country_code); | ||||
|         goto end; | ||||
|     } | ||||
| @@ -273,6 +302,20 @@ static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetBitConte | ||||
|     provider_code = get_bits(gb, 16); | ||||
|  | ||||
|     switch (provider_code) { | ||||
|     case 0x04: { // cuva_provider_code | ||||
|         const uint16_t cuva_provider_oriented_code = 0x0005; | ||||
|         uint16_t provider_oriented_code; | ||||
|  | ||||
|         if (size < 2) | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         size -= 2; | ||||
|  | ||||
|         provider_oriented_code = get_bits(gb, 16); | ||||
|         if (provider_oriented_code == cuva_provider_oriented_code) { | ||||
|             return decode_registered_user_data_dynamic_hdr_vivid(&s->dynamic_hdr_vivid, gb, size); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     case 0x3C: { // smpte_provider_code | ||||
|         // A/341 Amendment - 2094-40 | ||||
|         const uint16_t smpte2094_40_provider_oriented_code = 0x0001; | ||||
| @@ -559,4 +602,5 @@ void ff_hevc_reset_sei(HEVCSEI *s) | ||||
|     s->unregistered.nb_buf_ref = 0; | ||||
|     av_freep(&s->unregistered.buf_ref); | ||||
|     av_buffer_unref(&s->dynamic_hdr_plus.info); | ||||
|     av_buffer_unref(&s->dynamic_hdr_vivid.info); | ||||
| } | ||||
|   | ||||
| @@ -78,6 +78,10 @@ typedef struct HEVCSEIDynamicHDRPlus { | ||||
|     AVBufferRef *info; | ||||
| } HEVCSEIDynamicHDRPlus; | ||||
|  | ||||
| typedef struct HEVCSEIDynamicHDRVivid { | ||||
|     AVBufferRef *info; | ||||
| } HEVCSEIDynamicHDRVivid; | ||||
|  | ||||
| typedef struct HEVCSEIContentLight { | ||||
|     int present; | ||||
|     uint16_t max_content_light_level; | ||||
| @@ -139,6 +143,7 @@ typedef struct HEVCSEI { | ||||
|     HEVCSEIUnregistered unregistered; | ||||
|     HEVCSEIMasteringDisplay mastering_display; | ||||
|     HEVCSEIDynamicHDRPlus dynamic_hdr_plus; | ||||
|     HEVCSEIDynamicHDRVivid dynamic_hdr_vivid; | ||||
|     HEVCSEIContentLight content_light; | ||||
|     int active_seq_parameter_set_id; | ||||
|     HEVCSEIAlternativeTransfer alternative_transfer; | ||||
|   | ||||
| @@ -2984,6 +2984,17 @@ static int set_side_data(HEVCContext *s) | ||||
|     if ((ret = ff_dovi_attach_side_data(&s->dovi_ctx, out)) < 0) | ||||
|         return ret; | ||||
|  | ||||
|     if (s->sei.dynamic_hdr_vivid.info) { | ||||
|         AVBufferRef *info_ref = av_buffer_ref(s->sei.dynamic_hdr_vivid.info); | ||||
|         if (!info_ref) | ||||
|             return AVERROR(ENOMEM); | ||||
|  | ||||
|         if (!av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_DYNAMIC_HDR_VIVID, info_ref)) { | ||||
|             av_buffer_unref(&info_ref); | ||||
|             return AVERROR(ENOMEM); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -3777,6 +3788,10 @@ static int hevc_update_thread_context(AVCodecContext *dst, | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
|     ret = av_buffer_replace(&s->sei.dynamic_hdr_vivid.info, s0->sei.dynamic_hdr_vivid.info); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|  | ||||
|     s->sei.frame_packing        = s0->sei.frame_packing; | ||||
|     s->sei.display_orientation  = s0->sei.display_orientation; | ||||
|     s->sei.mastering_display    = s0->sei.mastering_display; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user