1 /** DOVI metadata helper functions
2 
3    mkvmerge -- utility for splicing together matroska files
4    from component media subtypes
5 
6    Distributed under the GPL v2
7    see the file COPYING for details
8    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 
10    \file
11 
12 */
13 
14 #include "common/bit_reader.h"
15 #include "common/bit_writer.h"
16 #include "common/mm_mem_io.h"
17 #include "common/codec.h"
18 
19 #include "common/dovi_meta.h"
20 
21 namespace mtx::dovi {
22 
23 void
dump()24 dovi_rpu_data_header_t::dump() {
25   mxinfo(fmt::format("dovi_rpu_data_header\n"
26                      "  rpu_nal_prefix: {0}\n"
27                      "  rpu_type: {1}\n"
28                      "  rpu_format: {2}\n"
29                      "  vdr_rpu_profile: {3}\n"
30                      "  vdr_rpu_level: {4}\n"
31                      "  vdr_seq_info_present_flag: {5}\n"
32                      "  chroma_resampling_explicit_filter_flag: {6}\n"
33                      "  coefficient_data_type: {7}\n"
34                      "  coefficient_log2_denom: {8}\n"
35                      "  vdr_rpu_normalized_idc: {9}\n"
36                      "  bl_video_full_range_flag: {10}\n"
37                      "  bl_bit_depth_minus8: {11}\n"
38                      "  el_bit_depth_minus8: {12}\n"
39                      "  vdr_bit_depth_minus_8: {13}\n"
40                      "  spatial_resampling_filter_flag: {14}\n"
41                      "  reserved_zero_3bits: {15}\n"
42                      "  el_spatial_resampling_filter_flag: {16}\n"
43                      "  disable_residual_flag: {17}\n"
44                      "  vdr_dm_metadata_present_flag: {18}\n"
45                      "  use_prev_vdr_rpu_flag: {19}\n"
46                      "  prev_vdr_rpu_id: {20}\n"
47                      "  vdr_rpu_id: {21}\n"
48                      "  mapping_color_space: {22}\n"
49                      "  mapping_chroma_format_idc: {23}\n"
50                      "  num_x_partitions_minus1: {24}\n"
51                      "  num_y_partitions_minus1: {25}\n",
52                      rpu_nal_prefix,
53                      rpu_type,
54                      rpu_format,
55                      vdr_rpu_profile,
56                      vdr_rpu_level,
57                      vdr_seq_info_present_flag,
58                      chroma_resampling_explicit_filter_flag,
59                      coefficient_data_type,
60                      coefficient_log2_denom,
61                      vdr_rpu_normalized_idc,
62                      bl_video_full_range_flag,
63                      bl_bit_depth_minus8,
64                      el_bit_depth_minus8,
65                      vdr_bit_depth_minus_8,
66                      spatial_resampling_filter_flag,
67                      reserved_zero_3bits,
68                      el_spatial_resampling_filter_flag,
69                      disable_residual_flag,
70                      vdr_dm_metadata_present_flag,
71                      use_prev_vdr_rpu_flag,
72                      prev_vdr_rpu_id,
73                      vdr_rpu_id,
74                      mapping_color_space,
75                      mapping_chroma_format_idc,
76                      num_x_partitions_minus1,
77                      num_y_partitions_minus1
78                      ));
79 }
80 
81 void
dump()82 dovi_decoder_configuration_record_t::dump() {
83   mxinfo(fmt::format("dovi_decoder_configuration_record\n"
84                      "  dv_version_major: {0}\n"
85                      "  dv_version_minor: {1}\n"
86                      "  dv_profile: {2}\n"
87                      "  dv_level: {3}\n"
88                      "  rpu_present_flag: {4}\n"
89                      "  el_present_flag: {5}\n"
90                      "  bl_present_flag: {6}\n"
91                      "  dv_bl_signal_compatibility_id: {7}\n",
92                      dv_version_major,
93                      dv_version_minor,
94                      dv_profile,
95                      dv_level,
96                      rpu_present_flag,
97                      el_present_flag,
98                      bl_present_flag,
99                      dv_bl_signal_compatibility_id
100                      ));
101 }
102 
103 dovi_decoder_configuration_record_t
create_dovi_configuration_record(dovi_rpu_data_header_t const & hdr,unsigned int width,unsigned int height,mtx::hevc::vui_info_t const & vui,uint64_t duration)104 create_dovi_configuration_record(dovi_rpu_data_header_t const &hdr,
105                                  unsigned int width,
106                                  unsigned int height,
107                                  mtx::hevc::vui_info_t const &vui,
108                                  uint64_t duration) {
109   dovi_decoder_configuration_record_t conf{};
110 
111   bool has_el           = hdr.el_spatial_resampling_filter_flag && !hdr.disable_residual_flag;
112   conf.dv_version_major = 1;
113   conf.dv_version_minor = 0;
114 
115   if (hdr.rpu_nal_prefix == 25) {
116     if ((hdr.vdr_rpu_profile == 0) && hdr.bl_video_full_range_flag)
117       conf.dv_profile = 5;
118 
119     else if (has_el) {
120       // Profile 7 is max 12 bits, both MEL & FEL
121       if (hdr.vdr_bit_depth_minus_8 == 4)
122         conf.dv_profile = 7;
123       else
124         conf.dv_profile = 4;
125 
126     } else
127       conf.dv_profile = 8;
128   }
129 
130   conf.dv_level = calculate_dovi_level(width, height, duration);
131 
132   // In all single PID cases, these are set to 1
133   conf.rpu_present_flag = 1;
134   conf.bl_present_flag  = 1;
135 
136   conf.el_present_flag  = 0;
137 
138   if (conf.dv_profile == 4)
139     conf.dv_bl_signal_compatibility_id = 2;
140 
141   else if (conf.dv_profile == 5)
142     conf.dv_bl_signal_compatibility_id = 0;
143 
144   else if (conf.dv_profile == 8) {
145     auto trc = vui.transfer_characteristics;
146 
147     // WCG
148     if (vui.colour_primaries == 9 && vui.matrix_coefficients == 9) {
149       if (trc == 16)                       // ST2084, HDR10 base layer
150         conf.dv_bl_signal_compatibility_id = 1;
151       else if ((trc == 14) || (trc == 18)) // ARIB STD-B67, HLG base layer
152         conf.dv_bl_signal_compatibility_id = 4;
153       else                                 // undefined
154         conf.dv_bl_signal_compatibility_id = 0;
155 
156     } else                                 // BT.709, BT.1886, SDR
157       conf.dv_bl_signal_compatibility_id = 2;
158 
159   } else if (conf.dv_profile == 7)
160     conf.dv_bl_signal_compatibility_id = 6;
161 
162   else if (conf.dv_profile == 9)
163     conf.dv_bl_signal_compatibility_id = 2;
164 
165   // Profile 4 is necessarily SDR with an enhancement-layer
166   // It's possible that the first guess was wrong, so correct it
167   if (has_el && (conf.dv_bl_signal_compatibility_id == 2) && (conf.dv_profile != 4))
168     conf.dv_profile = 4;
169 
170   // Set EL present for profile 4 and 7
171   if ((conf.dv_profile == 4) || (conf.dv_profile == 7)) {
172     conf.el_present_flag = 1;
173   }
174 
175   return conf;
176 }
177 
178 uint8_t
calculate_dovi_level(unsigned int width,unsigned int height,uint64_t duration)179 calculate_dovi_level(unsigned int width,
180                      unsigned int height,
181                      uint64_t duration) {
182   constexpr auto level1     =    22'118'400ull;
183   constexpr auto level2     =    27'648'000ull;
184   constexpr auto level3     =    49'766'400ull;
185   constexpr auto level4     =    62'208'000ull;
186   constexpr auto level5     =   124'416'000ull;
187   constexpr auto level6     =   199'065'600ull;
188   constexpr auto level7     =   248'832'000ull;
189   constexpr auto level8     =   398'131'200ull;
190   constexpr auto level9     =   497'664'000ull;
191   constexpr auto level10_11 =   995'328'000ull;
192   constexpr auto level12    = 1'990'656'000ull;
193   constexpr auto level13    = 3'981'312'000ull;
194 
195   auto frame_rate           = 1'000'000'000ull / duration;
196   auto pps                  = frame_rate * (width * height);
197 
198   uint8_t level             = pps <= level1                          ?  1
199                             : pps <= level2                          ?  2
200                             : pps <= level3                          ?  3
201                             : pps <= level4                          ?  4
202                             : pps <= level5                          ?  5
203                             : pps <= level6                          ?  6
204                             : pps <= level7                          ?  7
205                             : pps <= level8                          ?  8
206                             : pps <= level9                          ?  9
207                             : (pps <= level10_11) && (width <= 3840) ? 10
208                             : pps <= level10_11                      ? 11
209                             : pps <= level12                         ? 12
210                             : pps <= level13                         ? 13
211                             :                                           0;
212 
213   return level;
214 }
215 
216 block_addition_mapping_t
create_dovi_block_addition_mapping(dovi_decoder_configuration_record_t const & dovi_conf)217 create_dovi_block_addition_mapping(dovi_decoder_configuration_record_t const &dovi_conf) {
218   block_addition_mapping_t mapping;
219 
220   mapping.id_name = "Dolby Vision configuration";
221   mapping.id_type = dovi_conf.dv_profile > 7 ? fourcc_c{"dvvC"}.value() : fourcc_c{"dvcC"}.value();
222 
223   mtx::bits::writer_c w{};
224 
225   w.put_bits(8, dovi_conf.dv_version_major);
226   w.put_bits(8, dovi_conf.dv_version_minor);
227   w.put_bits(7, dovi_conf.dv_profile);
228   w.put_bits(6, dovi_conf.dv_level);
229   w.put_bit(dovi_conf.rpu_present_flag);
230   w.put_bit(dovi_conf.el_present_flag);
231   w.put_bit(dovi_conf.bl_present_flag);
232   w.put_bits(4, dovi_conf.dv_bl_signal_compatibility_id);
233 
234   w.put_bits(28, 0); // reserved
235   w.put_bits(32, 0); // reserved
236   w.put_bits(32, 0);
237   w.put_bits(32, 0);
238   w.put_bits(32, 0);
239 
240   w.byte_align();
241 
242   mapping.id_extra_data = w.get_buffer();
243 
244   return mapping;
245 }
246 
247 }                              // namespace mtx::dovi
248