| // Copyright (c) 2016 The WebM project authors. All Rights Reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. An additional intellectual property rights grant can be found | |
| // in the file PATENTS. All contributing project authors may | |
| // be found in the AUTHORS file in the root of the source tree. | |
| #include "hdr_util.h" | |
| #include <climits> | |
| #include <cstddef> | |
| #include <new> | |
| #include "mkvparser/mkvparser.h" | |
| namespace libwebm { | |
| const int Vp9CodecFeatures::kValueNotPresent = INT_MAX; | |
| bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc, | |
| PrimaryChromaticityPtr* muxer_pc) { | |
| muxer_pc->reset(new (std::nothrow) | |
| mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y)); | |
| if (!muxer_pc->get()) | |
| return false; | |
| return true; | |
| } | |
| bool MasteringMetadataValuePresent(double value) { | |
| return value != mkvparser::MasteringMetadata::kValueNotPresent; | |
| } | |
| bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm, | |
| mkvmuxer::MasteringMetadata* muxer_mm) { | |
| if (MasteringMetadataValuePresent(parser_mm.luminance_max)) | |
| muxer_mm->set_luminance_max(parser_mm.luminance_max); | |
| if (MasteringMetadataValuePresent(parser_mm.luminance_min)) | |
| muxer_mm->set_luminance_min(parser_mm.luminance_min); | |
| PrimaryChromaticityPtr r_ptr(NULL); | |
| PrimaryChromaticityPtr g_ptr(NULL); | |
| PrimaryChromaticityPtr b_ptr(NULL); | |
| PrimaryChromaticityPtr wp_ptr(NULL); | |
| if (parser_mm.r) { | |
| if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr)) | |
| return false; | |
| } | |
| if (parser_mm.g) { | |
| if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr)) | |
| return false; | |
| } | |
| if (parser_mm.b) { | |
| if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr)) | |
| return false; | |
| } | |
| if (parser_mm.white_point) { | |
| if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr)) | |
| return false; | |
| } | |
| if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(), | |
| wp_ptr.get())) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool ColourValuePresent(long long value) { | |
| return value != mkvparser::Colour::kValueNotPresent; | |
| } | |
| bool CopyColour(const mkvparser::Colour& parser_colour, | |
| mkvmuxer::Colour* muxer_colour) { | |
| if (!muxer_colour) | |
| return false; | |
| if (ColourValuePresent(parser_colour.matrix_coefficients)) | |
| muxer_colour->set_matrix_coefficients(parser_colour.matrix_coefficients); | |
| if (ColourValuePresent(parser_colour.bits_per_channel)) | |
| muxer_colour->set_bits_per_channel(parser_colour.bits_per_channel); | |
| if (ColourValuePresent(parser_colour.chroma_subsampling_horz)) { | |
| muxer_colour->set_chroma_subsampling_horz( | |
| parser_colour.chroma_subsampling_horz); | |
| } | |
| if (ColourValuePresent(parser_colour.chroma_subsampling_vert)) { | |
| muxer_colour->set_chroma_subsampling_vert( | |
| parser_colour.chroma_subsampling_vert); | |
| } | |
| if (ColourValuePresent(parser_colour.cb_subsampling_horz)) | |
| muxer_colour->set_cb_subsampling_horz(parser_colour.cb_subsampling_horz); | |
| if (ColourValuePresent(parser_colour.cb_subsampling_vert)) | |
| muxer_colour->set_cb_subsampling_vert(parser_colour.cb_subsampling_vert); | |
| if (ColourValuePresent(parser_colour.chroma_siting_horz)) | |
| muxer_colour->set_chroma_siting_horz(parser_colour.chroma_siting_horz); | |
| if (ColourValuePresent(parser_colour.chroma_siting_vert)) | |
| muxer_colour->set_chroma_siting_vert(parser_colour.chroma_siting_vert); | |
| if (ColourValuePresent(parser_colour.range)) | |
| muxer_colour->set_range(parser_colour.range); | |
| if (ColourValuePresent(parser_colour.transfer_characteristics)) { | |
| muxer_colour->set_transfer_characteristics( | |
| parser_colour.transfer_characteristics); | |
| } | |
| if (ColourValuePresent(parser_colour.primaries)) | |
| muxer_colour->set_primaries(parser_colour.primaries); | |
| if (ColourValuePresent(parser_colour.max_cll)) | |
| muxer_colour->set_max_cll(parser_colour.max_cll); | |
| if (ColourValuePresent(parser_colour.max_fall)) | |
| muxer_colour->set_max_fall(parser_colour.max_fall); | |
| if (parser_colour.mastering_metadata) { | |
| mkvmuxer::MasteringMetadata muxer_mm; | |
| if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm)) | |
| return false; | |
| if (!muxer_colour->SetMasteringMetadata(muxer_mm)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Format of VPx private data: | |
| // | |
| // 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 | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | ID Byte | Length | | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | |
| // | | | |
| // : Bytes 1..Length of Codec Feature : | |
| // | | | |
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| // | |
| // ID Byte Format | |
| // ID byte is an unsigned byte. | |
| // 0 1 2 3 4 5 6 7 | |
| // +-+-+-+-+-+-+-+-+ | |
| // |X| ID | | |
| // +-+-+-+-+-+-+-+-+ | |
| // | |
| // The X bit is reserved. | |
| // | |
| // See the following link for more information: | |
| // http://www.webmproject.org/vp9/profiles/ | |
| bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length, | |
| Vp9CodecFeatures* features) { | |
| const int kVpxCodecPrivateMinLength = 3; | |
| if (!private_data || !features || length < kVpxCodecPrivateMinLength) | |
| return false; | |
| const uint8_t kVp9ProfileId = 1; | |
| const uint8_t kVp9LevelId = 2; | |
| const uint8_t kVp9BitDepthId = 3; | |
| const uint8_t kVp9ChromaSubsamplingId = 4; | |
| const int kVpxFeatureLength = 1; | |
| int offset = 0; | |
| // Set features to not set. | |
| features->profile = Vp9CodecFeatures::kValueNotPresent; | |
| features->level = Vp9CodecFeatures::kValueNotPresent; | |
| features->bit_depth = Vp9CodecFeatures::kValueNotPresent; | |
| features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent; | |
| do { | |
| const uint8_t id_byte = private_data[offset++]; | |
| const uint8_t length_byte = private_data[offset++]; | |
| if (length_byte != kVpxFeatureLength) | |
| return false; | |
| if (id_byte == kVp9ProfileId) { | |
| const int priv_profile = static_cast<int>(private_data[offset++]); | |
| if (priv_profile < 0 || priv_profile > 3) | |
| return false; | |
| if (features->profile != Vp9CodecFeatures::kValueNotPresent && | |
| features->profile != priv_profile) { | |
| return false; | |
| } | |
| features->profile = priv_profile; | |
| } else if (id_byte == kVp9LevelId) { | |
| const int priv_level = static_cast<int>(private_data[offset++]); | |
| const int kNumLevels = 14; | |
| const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40, | |
| 41, 50, 51, 52, 60, 61, 62}; | |
| for (int i = 0; i < kNumLevels; ++i) { | |
| if (priv_level == levels[i]) { | |
| if (features->level != Vp9CodecFeatures::kValueNotPresent && | |
| features->level != priv_level) { | |
| return false; | |
| } | |
| features->level = priv_level; | |
| break; | |
| } | |
| } | |
| if (features->level == Vp9CodecFeatures::kValueNotPresent) | |
| return false; | |
| } else if (id_byte == kVp9BitDepthId) { | |
| const int priv_profile = static_cast<int>(private_data[offset++]); | |
| if (priv_profile != 8 && priv_profile != 10 && priv_profile != 12) | |
| return false; | |
| if (features->bit_depth != Vp9CodecFeatures::kValueNotPresent && | |
| features->bit_depth != priv_profile) { | |
| return false; | |
| } | |
| features->bit_depth = priv_profile; | |
| } else if (id_byte == kVp9ChromaSubsamplingId) { | |
| const int priv_profile = static_cast<int>(private_data[offset++]); | |
| if (priv_profile != 0 && priv_profile != 2 && priv_profile != 3) | |
| return false; | |
| if (features->chroma_subsampling != Vp9CodecFeatures::kValueNotPresent && | |
| features->chroma_subsampling != priv_profile) { | |
| return false; | |
| } | |
| features->chroma_subsampling = priv_profile; | |
| } else { | |
| // Invalid ID. | |
| return false; | |
| } | |
| } while (offset + kVpxCodecPrivateMinLength <= length); | |
| return true; | |
| } | |
| } // namespace libwebm |