| // 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(nullptr); |
| PrimaryChromaticityPtr g_ptr(nullptr); |
| PrimaryChromaticityPtr b_ptr(nullptr); |
| PrimaryChromaticityPtr wp_ptr(nullptr); |
| |
| 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 |