Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/video_codecs.h" | 5 #include "media/base/video_codecs.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/strings/string_split.h" | |
| 9 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| 10 | 11 |
| 11 namespace media { | 12 namespace media { |
| 12 | 13 |
| 13 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c | 14 // The names come from src/third_party/ffmpeg/libavcodec/codec_desc.c |
| 14 std::string GetCodecName(VideoCodec codec) { | 15 std::string GetCodecName(VideoCodec codec) { |
| 15 switch (codec) { | 16 switch (codec) { |
| 16 case kUnknownVideoCodec: | 17 case kUnknownVideoCodec: |
| 17 return "unknown"; | 18 return "unknown"; |
| 18 case kCodecH264: | 19 case kCodecH264: |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 case H264PROFILE_HIGH444PREDICTIVEPROFILE: | 56 case H264PROFILE_HIGH444PREDICTIVEPROFILE: |
| 56 return "h264 high 4:4:4 predictive"; | 57 return "h264 high 4:4:4 predictive"; |
| 57 case H264PROFILE_SCALABLEBASELINE: | 58 case H264PROFILE_SCALABLEBASELINE: |
| 58 return "h264 scalable baseline"; | 59 return "h264 scalable baseline"; |
| 59 case H264PROFILE_SCALABLEHIGH: | 60 case H264PROFILE_SCALABLEHIGH: |
| 60 return "h264 scalable high"; | 61 return "h264 scalable high"; |
| 61 case H264PROFILE_STEREOHIGH: | 62 case H264PROFILE_STEREOHIGH: |
| 62 return "h264 stereo high"; | 63 return "h264 stereo high"; |
| 63 case H264PROFILE_MULTIVIEWHIGH: | 64 case H264PROFILE_MULTIVIEWHIGH: |
| 64 return "h264 multiview high"; | 65 return "h264 multiview high"; |
| 66 case HEVCPROFILE_MAIN: | |
| 67 return "hevc main"; | |
| 68 case HEVCPROFILE_MAIN10: | |
| 69 return "hevc main 10"; | |
| 70 case HEVCPROFILE_MAIN_STILL_PICTURE: | |
| 71 return "hevc main still-picture"; | |
| 65 case VP8PROFILE_ANY: | 72 case VP8PROFILE_ANY: |
| 66 return "vp8"; | 73 return "vp8"; |
| 67 case VP9PROFILE_PROFILE0: | 74 case VP9PROFILE_PROFILE0: |
| 68 return "vp9 profile0"; | 75 return "vp9 profile0"; |
| 69 case VP9PROFILE_PROFILE1: | 76 case VP9PROFILE_PROFILE1: |
| 70 return "vp9 profile1"; | 77 return "vp9 profile1"; |
| 71 case VP9PROFILE_PROFILE2: | 78 case VP9PROFILE_PROFILE2: |
| 72 return "vp9 profile2"; | 79 return "vp9 profile2"; |
| 73 case VP9PROFILE_PROFILE3: | 80 case VP9PROFILE_PROFILE3: |
| 74 return "vp9 profile3"; | 81 return "vp9 profile3"; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 | 169 |
| 163 if (level_idc) | 170 if (level_idc) |
| 164 *level_idc = level_byte; | 171 *level_idc = level_byte; |
| 165 | 172 |
| 166 if (profile) | 173 if (profile) |
| 167 *profile = out_profile; | 174 *profile = out_profile; |
| 168 | 175 |
| 169 return true; | 176 return true; |
| 170 } | 177 } |
| 171 | 178 |
| 179 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | |
| 180 // The specification for HEVC codec id strings can be found in ISO IEC 14496-15 | |
| 181 // dated 2012 or newer in the Annex E.3 | |
| 182 bool ParseHEVCCodecId(const std::string& codec_id, | |
| 183 VideoCodecProfile* profile, | |
| 184 uint8_t* level_idc) { | |
| 185 if (!base::StartsWith(codec_id, "hev1.", base::CompareCase::SENSITIVE) && | |
| 186 !base::StartsWith(codec_id, "hvc1.", base::CompareCase::SENSITIVE)) { | |
| 187 return false; | |
| 188 } | |
| 189 | |
| 190 // HEVC codec id consists of: | |
| 191 const int kMaxHevcCodecIdLength = | |
| 192 5 + // 'hev1.' or 'hvc1.' prefix (5 chars) | |
| 193 4 + // profile, e.g. '.A12' (max 4 chars) | |
| 194 9 + // profile_compatibility, dot + 32-bit hex number (max 9 chars) | |
| 195 5 + // tier and level, e.g. '.H120' (max 5 chars) | |
| 196 18; // up to 6 constraint bytes, bytes are dot-separated and hex-encoded. | |
| 197 | |
| 198 if (codec_id.size() > kMaxHevcCodecIdLength) { | |
| 199 DVLOG(4) << __FUNCTION__ << ": Codec id is too long (" << codec_id << ")"; | |
| 200 return false; | |
| 201 } | |
| 202 | |
| 203 std::vector<std::string> elem = base::SplitString( | |
| 204 codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | |
|
ddorwin
2016/04/20 22:28:15
What happens with consecutive periods? If it creat
servolk
2016/04/20 23:14:46
Yes, base::SPLIT_WANT_ALL means we get empty eleme
| |
| 205 DCHECK(elem[0] == "hev1" || elem[0] == "hvc1"); | |
| 206 | |
| 207 if (elem.size() < 4) { | |
| 208 DVLOG(4) << __FUNCTION__ << ": invalid HEVC codec id " << codec_id; | |
| 209 return false; | |
| 210 } | |
| 211 | |
| 212 uint8_t general_profile_space = 0; | |
| 213 if (elem[1][0] == 'A' || elem[1][0] == 'B' || elem[1][0] == 'C') { | |
| 214 general_profile_space = 1 + (elem[1][0] - 'A'); | |
| 215 elem[1].erase(0, 1); | |
| 216 } | |
| 217 DCHECK(general_profile_space >= 0 && general_profile_space <= 3); | |
| 218 | |
| 219 unsigned general_profile_idc = 0; | |
| 220 if (!base::StringToUint(elem[1], &general_profile_idc) || | |
| 221 general_profile_idc > 0x1f) { | |
| 222 DVLOG(4) << __FUNCTION__ << ": invalid general_profile_idc=" << elem[1]; | |
| 223 return false; | |
| 224 } | |
| 225 | |
| 226 uint32_t general_profile_compatibility_flags = 0; | |
| 227 if (!base::HexStringToUInt(elem[2], &general_profile_compatibility_flags)) { | |
| 228 DVLOG(4) << __FUNCTION__ | |
| 229 << ": invalid general_profile_compatibility_flags=" << elem[2]; | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 if (profile) { | |
| 234 // TODO(servolk): Handle format range extension profiles as explained in | |
| 235 // HEVC standard (ISO/IEC ISO/IEC 23008-2) section A.3.5 | |
| 236 if (general_profile_idc == 3 || (general_profile_compatibility_flags & 4)) { | |
| 237 *profile = HEVCPROFILE_MAIN_STILL_PICTURE; | |
| 238 } | |
| 239 if (general_profile_idc == 2 || (general_profile_compatibility_flags & 2)) { | |
| 240 *profile = HEVCPROFILE_MAIN10; | |
| 241 } | |
| 242 if (general_profile_idc == 1 || (general_profile_compatibility_flags & 1)) { | |
| 243 *profile = HEVCPROFILE_MAIN; | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 uint8_t general_tier_flag; | |
| 248 if (elem[3][0] == 'L' || elem[3][0] == 'H') { | |
| 249 general_tier_flag = (elem[3][0] == 'L') ? 0 : 1; | |
| 250 elem[3].erase(0, 1); | |
| 251 } else { | |
| 252 DVLOG(4) << __FUNCTION__ << ": invalid general_tier_flag=" << elem[3]; | |
| 253 return false; | |
| 254 } | |
| 255 DCHECK(general_tier_flag == 0 || general_tier_flag == 1); | |
| 256 | |
| 257 unsigned general_level_idc = 0; | |
| 258 if (!base::StringToUint(elem[3], &general_level_idc) || | |
| 259 general_level_idc > 0xff) { | |
| 260 DVLOG(4) << __FUNCTION__ << ": invalid general_level_idc=" << elem[3]; | |
| 261 return false; | |
| 262 } | |
| 263 | |
| 264 if (level_idc) | |
| 265 *level_idc = static_cast<uint8_t>(general_level_idc); | |
| 266 | |
| 267 uint8_t constraint_flags[6]; | |
| 268 memset(constraint_flags, 0, sizeof(constraint_flags)); | |
| 269 | |
| 270 // Remove everything up to the first constraint_flags byte | |
|
ddorwin
2016/04/20 22:28:15
This seems a little strange when we could just cha
servolk
2016/04/20 23:14:46
Done.
| |
| 271 elem.erase(elem.begin(), elem.begin() + 4); | |
| 272 if (elem.size() > 6) { | |
|
ddorwin
2016/04/20 22:28:15
In particular, it's not immediately clear that thi
servolk
2016/04/20 23:14:46
Since we no longer remove the first elements, the
| |
| 273 DVLOG(4) << __FUNCTION__ << ": unexpected number of trailing bytes in HEVC " | |
| 274 << "codec id " << codec_id; | |
| 275 return false; | |
| 276 } | |
| 277 for (size_t i = 0; i < elem.size(); ++i) { | |
| 278 unsigned constr_byte = 0; | |
| 279 if (!base::HexStringToUInt(elem[i], &constr_byte) || constr_byte > 0xFF) { | |
| 280 DVLOG(4) << __FUNCTION__ << ": invalid constraint byte=" << elem[i]; | |
| 281 return false; | |
| 282 } | |
| 283 constraint_flags[i] = constr_byte; | |
| 284 } | |
| 285 | |
| 286 return true; | |
| 287 } | |
| 288 #endif | |
| 289 | |
| 172 } // namespace media | 290 } // namespace media |
| OLD | NEW |