Shaka Packager SDK
webm_video_client.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "packager/media/formats/webm/webm_video_client.h"
6 
7 #include "packager/base/logging.h"
8 #include "packager/media/codecs/av1_codec_configuration_record.h"
9 #include "packager/media/codecs/vp_codec_configuration_record.h"
10 #include "packager/media/formats/webm/webm_constants.h"
11 
12 namespace {
13 
14 // Timestamps are represented in double in WebM. Convert to uint64_t in us.
15 const uint32_t kWebMTimeScale = 1000000u;
16 
17 int64_t GetGreatestCommonDivisor(int64_t a, int64_t b) {
18  while (b) {
19  int64_t temp = b;
20  b = a % b;
21  a = temp;
22  }
23  return a;
24 }
25 
26 } // namespace
27 
28 namespace shaka {
29 namespace media {
30 
31 WebMVideoClient::WebMVideoClient() {}
32 
33 WebMVideoClient::~WebMVideoClient() {}
34 
36  pixel_width_ = -1;
37  pixel_height_ = -1;
38  crop_bottom_ = -1;
39  crop_top_ = -1;
40  crop_left_ = -1;
41  crop_right_ = -1;
42  display_width_ = -1;
43  display_height_ = -1;
44  display_unit_ = -1;
45  alpha_mode_ = -1;
46 
47  matrix_coefficients_ = -1;
48  bits_per_channel_ = -1;
49  chroma_subsampling_horz_ = -1;
50  chroma_subsampling_vert_ = -1;
51  chroma_siting_horz_ = -1;
52  chroma_siting_vert_ = -1;
53  color_range_ = -1;
54  transfer_characteristics_ = -1;
55  color_primaries_ = -1;
56 }
57 
58 std::shared_ptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
59  int64_t track_num,
60  const std::string& codec_id,
61  const std::vector<uint8_t>& codec_private,
62  bool is_encrypted) {
63  std::string codec_string;
64  Codec video_codec = kUnknownCodec;
65  if (codec_id == "V_AV1") {
66  video_codec = kCodecAV1;
67 
68  // CodecPrivate is mandatory per AV in Matroska / WebM specification.
69  // https://github.com/Matroska-Org/matroska-specification/blob/av1-mappin/codec/av1.md#codecprivate-1
70  AV1CodecConfigurationRecord av1_config;
71  if (!av1_config.Parse(codec_private)) {
72  LOG(ERROR) << "Failed to parse AV1 codec_private.";
73  return nullptr;
74  }
75  codec_string = av1_config.GetCodecString();
76  } else if (codec_id == "V_VP8") {
77  video_codec = kCodecVP8;
78  // codec_string for VP8 is parsed later.
79  } else if (codec_id == "V_VP9") {
80  video_codec = kCodecVP9;
81  // codec_string for VP9 is parsed later.
82  } else {
83  LOG(ERROR) << "Unsupported video codec_id " << codec_id;
84  return nullptr;
85  }
86 
87  if (pixel_width_ <= 0 || pixel_height_ <= 0)
88  return nullptr;
89 
90  // Set crop and display unit defaults if these elements are not present.
91  if (crop_bottom_ == -1)
92  crop_bottom_ = 0;
93 
94  if (crop_top_ == -1)
95  crop_top_ = 0;
96 
97  if (crop_left_ == -1)
98  crop_left_ = 0;
99 
100  if (crop_right_ == -1)
101  crop_right_ = 0;
102 
103  if (display_unit_ == -1)
104  display_unit_ = 0;
105 
106  uint16_t width_after_crop = pixel_width_ - (crop_left_ + crop_right_);
107  uint16_t height_after_crop = pixel_height_ - (crop_top_ + crop_bottom_);
108 
109  if (display_unit_ == 0) {
110  if (display_width_ <= 0)
111  display_width_ = width_after_crop;
112  if (display_height_ <= 0)
113  display_height_ = height_after_crop;
114  } else if (display_unit_ == 3) {
115  if (display_width_ <= 0 || display_height_ <= 0)
116  return nullptr;
117  } else {
118  LOG(ERROR) << "Unsupported display unit type " << display_unit_;
119  return nullptr;
120  }
121  // Calculate sample aspect ratio.
122  int64_t sar_x = display_width_ * height_after_crop;
123  int64_t sar_y = display_height_ * width_after_crop;
124  int64_t gcd = GetGreatestCommonDivisor(sar_x, sar_y);
125  sar_x /= gcd;
126  sar_y /= gcd;
127 
128  // |codec_private| may be overriden later for some codecs, e.g. VP9 since for
129  // VP9, the format for MP4 and WebM are different; MP4 format is used as the
130  // intermediate format.
131  return std::make_shared<VideoStreamInfo>(
132  track_num, kWebMTimeScale, 0, video_codec, H26xStreamFormat::kUnSpecified,
133  codec_string, codec_private.data(), codec_private.size(),
134  width_after_crop, height_after_crop, sar_x, sar_y, 0, 0, std::string(),
135  is_encrypted);
136 }
137 
139  const std::vector<uint8_t>& codec_private) {
140  VPCodecConfigurationRecord vp_config;
141  vp_config.ParseWebM(codec_private);
142  if (matrix_coefficients_ != -1) {
143  vp_config.set_matrix_coefficients(matrix_coefficients_);
144  }
145  if (bits_per_channel_ != -1) {
146  vp_config.set_bit_depth(bits_per_channel_);
147  }
148  if (chroma_subsampling_horz_ != -1 && chroma_subsampling_vert_ != -1) {
149  vp_config.SetChromaSubsampling(chroma_subsampling_horz_,
150  chroma_subsampling_vert_);
151  }
152  if (chroma_siting_horz_ != -1 && chroma_siting_vert_ != -1) {
153  vp_config.SetChromaLocation(chroma_siting_horz_, chroma_siting_vert_);
154  }
155  if (color_range_ != -1) {
156  if (color_range_ == 0)
157  vp_config.set_video_full_range_flag(false);
158  else if (color_range_ == 1)
159  vp_config.set_video_full_range_flag(true);
160  // Ignore for other values.
161  }
162  if (transfer_characteristics_ != -1) {
163  vp_config.set_transfer_characteristics(transfer_characteristics_);
164  }
165  if (color_primaries_ != -1) {
166  vp_config.set_color_primaries(color_primaries_);
167  }
168  return vp_config;
169 }
170 
171 WebMParserClient* WebMVideoClient::OnListStart(int id) {
172  return id == kWebMIdColor ? this : WebMParserClient::OnListStart(id);
173 }
174 
175 bool WebMVideoClient::OnListEnd(int id) {
176  return id == kWebMIdColor ? true : WebMParserClient::OnListEnd(id);
177 }
178 
179 bool WebMVideoClient::OnUInt(int id, int64_t val) {
180  int64_t* dst = nullptr;
181 
182  switch (id) {
183  case kWebMIdPixelWidth:
184  dst = &pixel_width_;
185  break;
186  case kWebMIdPixelHeight:
187  dst = &pixel_height_;
188  break;
189  case kWebMIdPixelCropTop:
190  dst = &crop_top_;
191  break;
192  case kWebMIdPixelCropBottom:
193  dst = &crop_bottom_;
194  break;
195  case kWebMIdPixelCropLeft:
196  dst = &crop_left_;
197  break;
198  case kWebMIdPixelCropRight:
199  dst = &crop_right_;
200  break;
201  case kWebMIdDisplayWidth:
202  dst = &display_width_;
203  break;
204  case kWebMIdDisplayHeight:
205  dst = &display_height_;
206  break;
207  case kWebMIdDisplayUnit:
208  dst = &display_unit_;
209  break;
210  case kWebMIdAlphaMode:
211  dst = &alpha_mode_;
212  break;
213  case kWebMIdColorMatrixCoefficients:
214  dst = &matrix_coefficients_;
215  break;
216  case kWebMIdColorBitsPerChannel:
217  dst = &bits_per_channel_;
218  break;
219  case kWebMIdColorChromaSubsamplingHorz:
220  dst = &chroma_subsampling_horz_;
221  break;
222  case kWebMIdColorChromaSubsamplingVert:
223  dst = &chroma_subsampling_vert_;
224  break;
225  case kWebMIdColorChromaSitingHorz:
226  dst = &chroma_siting_horz_;
227  break;
228  case kWebMIdColorChromaSitingVert:
229  dst = &chroma_siting_vert_;
230  break;
231  case kWebMIdColorRange:
232  dst = &color_range_;
233  break;
234  case kWebMIdColorTransferCharacteristics:
235  dst = &transfer_characteristics_;
236  break;
237  case kWebMIdColorPrimaries:
238  dst = &color_primaries_;
239  break;
240  case kWebMIdColorMaxCLL:
241  case kWebMIdColorMaxFALL:
242  NOTIMPLEMENTED() << "HDR is not supported yet.";
243  return true;
244  default:
245  return true;
246  }
247 
248  if (*dst != -1) {
249  LOG(ERROR) << "Multiple values for id " << std::hex << id << " specified ("
250  << *dst << " and " << val << ")";
251  return false;
252  }
253 
254  *dst = val;
255  return true;
256 }
257 
258 bool WebMVideoClient::OnBinary(int id, const uint8_t* data, int size) {
259  // Accept binary fields we don't care about for now.
260  return true;
261 }
262 
263 bool WebMVideoClient::OnFloat(int id, double val) {
264  // Accept float fields we don't care about for now.
265  return true;
266 }
267 
268 } // namespace media
269 } // namespace shaka
std::shared_ptr< VideoStreamInfo > GetVideoStreamInfo(int64_t track_num, const std::string &codec_id, const std::vector< uint8_t > &codec_private, bool is_encrypted)
VPCodecConfigurationRecord GetVpCodecConfig(const std::vector< uint8_t > &codec_private)
void Reset()
Reset this object&#39;s state so it can process a new video track element.
Class for parsing or writing VP codec configuration record.
All the methods that are virtual are virtual for mocking.
bool Parse(const std::vector< uint8_t > &data)
Class for parsing AV1 codec configuration record.
bool ParseWebM(const std::vector< uint8_t > &data)