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
16namespace libwebm {
17const int Vp9CodecFeatures::kValueNotPresent = INT_MAX;
18
19bool 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
28bool MasteringMetadataValuePresent(double value) {
29  return value != mkvparser::MasteringMetadata::kValueNotPresent;
30}
31
32bool 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
69bool ColourValuePresent(long long value) {
70  return value != mkvparser::Colour::kValueNotPresent;
71}
72
73bool 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/
143bool 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