1 // Copyright (c) 2016 The WebM project authors. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 #include "hdr_util.h" 9 10 #include <climits> 11 #include <cstddef> 12 #include <new> 13 14 #include "mkvparser/mkvparser.h" 15 16 namespace libwebm { 17 const int Vp9CodecFeatures::kValueNotPresent = INT_MAX; 18 19 bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc, 20 PrimaryChromaticityPtr* muxer_pc) { 21 muxer_pc->reset(new (std::nothrow) 22 mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y)); 23 if (!muxer_pc->get()) 24 return false; 25 return true; 26 } 27 28 bool MasteringMetadataValuePresent(double value) { 29 return value != mkvparser::MasteringMetadata::kValueNotPresent; 30 } 31 32 bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm, 33 mkvmuxer::MasteringMetadata* muxer_mm) { 34 if (MasteringMetadataValuePresent(parser_mm.luminance_max)) 35 muxer_mm->set_luminance_max(parser_mm.luminance_max); 36 if (MasteringMetadataValuePresent(parser_mm.luminance_min)) 37 muxer_mm->set_luminance_min(parser_mm.luminance_min); 38 39 PrimaryChromaticityPtr r_ptr(NULL); 40 PrimaryChromaticityPtr g_ptr(NULL); 41 PrimaryChromaticityPtr b_ptr(NULL); 42 PrimaryChromaticityPtr wp_ptr(NULL); 43 44 if (parser_mm.r) { 45 if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr)) 46 return false; 47 } 48 if (parser_mm.g) { 49 if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr)) 50 return false; 51 } 52 if (parser_mm.b) { 53 if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr)) 54 return false; 55 } 56 if (parser_mm.white_point) { 57 if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr)) 58 return false; 59 } 60 61 if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(), 62 wp_ptr.get())) { 63 return false; 64 } 65 66 return true; 67 } 68 69 bool ColourValuePresent(long long value) { 70 return value != mkvparser::Colour::kValueNotPresent; 71 } 72 73 bool CopyColour(const mkvparser::Colour& parser_colour, 74 mkvmuxer::Colour* muxer_colour) { 75 if (!muxer_colour) 76 return false; 77 78 if (ColourValuePresent(parser_colour.matrix_coefficients)) 79 muxer_colour->set_matrix_coefficients(parser_colour.matrix_coefficients); 80 if (ColourValuePresent(parser_colour.bits_per_channel)) 81 muxer_colour->set_bits_per_channel(parser_colour.bits_per_channel); 82 if (ColourValuePresent(parser_colour.chroma_subsampling_horz)) { 83 muxer_colour->set_chroma_subsampling_horz( 84 parser_colour.chroma_subsampling_horz); 85 } 86 if (ColourValuePresent(parser_colour.chroma_subsampling_vert)) { 87 muxer_colour->set_chroma_subsampling_vert( 88 parser_colour.chroma_subsampling_vert); 89 } 90 if (ColourValuePresent(parser_colour.cb_subsampling_horz)) 91 muxer_colour->set_cb_subsampling_horz(parser_colour.cb_subsampling_horz); 92 if (ColourValuePresent(parser_colour.cb_subsampling_vert)) 93 muxer_colour->set_cb_subsampling_vert(parser_colour.cb_subsampling_vert); 94 if (ColourValuePresent(parser_colour.chroma_siting_horz)) 95 muxer_colour->set_chroma_siting_horz(parser_colour.chroma_siting_horz); 96 if (ColourValuePresent(parser_colour.chroma_siting_vert)) 97 muxer_colour->set_chroma_siting_vert(parser_colour.chroma_siting_vert); 98 if (ColourValuePresent(parser_colour.range)) 99 muxer_colour->set_range(parser_colour.range); 100 if (ColourValuePresent(parser_colour.transfer_characteristics)) { 101 muxer_colour->set_transfer_characteristics( 102 parser_colour.transfer_characteristics); 103 } 104 if (ColourValuePresent(parser_colour.primaries)) 105 muxer_colour->set_primaries(parser_colour.primaries); 106 if (ColourValuePresent(parser_colour.max_cll)) 107 muxer_colour->set_max_cll(parser_colour.max_cll); 108 if (ColourValuePresent(parser_colour.max_fall)) 109 muxer_colour->set_max_fall(parser_colour.max_fall); 110 111 if (parser_colour.mastering_metadata) { 112 mkvmuxer::MasteringMetadata muxer_mm; 113 if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm)) 114 return false; 115 if (!muxer_colour->SetMasteringMetadata(muxer_mm)) 116 return false; 117 } 118 return true; 119 } 120 121 // Format of VPx private data: 122 // 123 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 124 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 125 // | ID Byte | Length | | 126 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 127 // | | 128 // : Bytes 1..Length of Codec Feature : 129 // | | 130 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 131 // 132 // ID Byte Format 133 // ID byte is an unsigned byte. 134 // 0 1 2 3 4 5 6 7 135 // +-+-+-+-+-+-+-+-+ 136 // |X| ID | 137 // +-+-+-+-+-+-+-+-+ 138 // 139 // The X bit is reserved. 140 // 141 // See the following link for more information: 142 // http://www.webmproject.org/vp9/profiles/ 143 bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length, 144 Vp9CodecFeatures* features) { 145 const int kVpxCodecPrivateMinLength = 3; 146 if (!private_data || !features || length < kVpxCodecPrivateMinLength) 147 return false; 148 149 const uint8_t kVp9ProfileId = 1; 150 const uint8_t kVp9LevelId = 2; 151 const uint8_t kVp9BitDepthId = 3; 152 const uint8_t kVp9ChromaSubsamplingId = 4; 153 const int kVpxFeatureLength = 1; 154 int offset = 0; 155 156 // Set features to not set. 157 features->profile = Vp9CodecFeatures::kValueNotPresent; 158 features->level = Vp9CodecFeatures::kValueNotPresent; 159 features->bit_depth = Vp9CodecFeatures::kValueNotPresent; 160 features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent; 161 do { 162 const uint8_t id_byte = private_data[offset++]; 163 const uint8_t length_byte = private_data[offset++]; 164 if (length_byte != kVpxFeatureLength) 165 return false; 166 if (id_byte == kVp9ProfileId) { 167 const int priv_profile = static_cast<int>(private_data[offset++]); 168 if (priv_profile < 0 || priv_profile > 3) 169 return false; 170 if (features->profile != Vp9CodecFeatures::kValueNotPresent && 171 features->profile != priv_profile) { 172 return false; 173 } 174 features->profile = priv_profile; 175 } else if (id_byte == kVp9LevelId) { 176 const int priv_level = static_cast<int>(private_data[offset++]); 177 178 const int kNumLevels = 14; 179 const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40, 180 41, 50, 51, 52, 60, 61, 62}; 181 182 for (int i = 0; i < kNumLevels; ++i) { 183 if (priv_level == levels[i]) { 184 if (features->level != Vp9CodecFeatures::kValueNotPresent && 185 features->level != priv_level) { 186 return false; 187 } 188 features->level = priv_level; 189 break; 190 } 191 } 192 if (features->level == Vp9CodecFeatures::kValueNotPresent) 193 return false; 194 } else if (id_byte == kVp9BitDepthId) { 195 const int priv_profile = static_cast<int>(private_data[offset++]); 196 if (priv_profile != 8 && priv_profile != 10 && priv_profile != 12) 197 return false; 198 if (features->bit_depth != Vp9CodecFeatures::kValueNotPresent && 199 features->bit_depth != priv_profile) { 200 return false; 201 } 202 features->bit_depth = priv_profile; 203 } else if (id_byte == kVp9ChromaSubsamplingId) { 204 const int priv_profile = static_cast<int>(private_data[offset++]); 205 if (priv_profile != 0 && priv_profile != 2 && priv_profile != 3) 206 return false; 207 if (features->chroma_subsampling != Vp9CodecFeatures::kValueNotPresent && 208 features->chroma_subsampling != priv_profile) { 209 return false; 210 } 211 features->chroma_subsampling = priv_profile; 212 } else { 213 // Invalid ID. 214 return false; 215 } 216 } while (offset + kVpxCodecPrivateMinLength <= length); 217 218 return true; 219 } 220 } // namespace libwebm 221