Shaka Packager SDK
Loading...
Searching...
No Matches
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 <absl/log/log.h>
8
9#include <packager/macros/logging.h>
10#include <packager/media/base/buffer_writer.h>
11#include <packager/media/base/fourccs.h>
12#include <packager/media/base/video_util.h>
13#include <packager/media/codecs/av1_codec_configuration_record.h>
14#include <packager/media/codecs/vp_codec_configuration_record.h>
15#include <packager/media/formats/webm/webm_constants.h>
16
17namespace {
18
19// Timestamps are represented in double in WebM. Convert to int64_t in us.
20const int32_t kWebMTimeScale = 1000000;
21
22} // namespace
23
24namespace shaka {
25namespace media {
26
27WebMVideoClient::WebMVideoClient() {}
28
29WebMVideoClient::~WebMVideoClient() {}
30
32 pixel_width_ = -1;
33 pixel_height_ = -1;
34 crop_bottom_ = -1;
35 crop_top_ = -1;
36 crop_left_ = -1;
37 crop_right_ = -1;
38 display_width_ = -1;
39 display_height_ = -1;
40 display_unit_ = -1;
41 alpha_mode_ = -1;
42
43 matrix_coefficients_ = -1;
44 bits_per_channel_ = -1;
45 chroma_subsampling_horz_ = -1;
46 chroma_subsampling_vert_ = -1;
47 chroma_siting_horz_ = -1;
48 chroma_siting_vert_ = -1;
49 color_range_ = -1;
50 transfer_characteristics_ = -1;
51 color_primaries_ = -1;
52}
53
54std::shared_ptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
55 int64_t track_num,
56 const std::string& codec_id,
57 const std::vector<uint8_t>& codec_private,
58 bool is_encrypted) {
59 std::string codec_string;
60 Codec video_codec = kUnknownCodec;
61 if (codec_id == "V_AV1") {
62 video_codec = kCodecAV1;
63
64 // CodecPrivate is mandatory per AV in Matroska / WebM specification.
65 // https://github.com/Matroska-Org/matroska-specification/blob/av1-mappin/codec/av1.md#codecprivate-1
67 if (!av1_config.Parse(codec_private)) {
68 LOG(ERROR) << "Failed to parse AV1 codec_private.";
69 return nullptr;
70 }
71 codec_string = av1_config.GetCodecString();
72 } else if (codec_id == "V_VP8") {
73 video_codec = kCodecVP8;
74 // codec_string for VP8 is parsed later.
75 } else if (codec_id == "V_VP9") {
76 video_codec = kCodecVP9;
77 // codec_string for VP9 is parsed later.
78 } else {
79 LOG(ERROR) << "Unsupported video codec_id " << codec_id;
80 return nullptr;
81 }
82
83 if (pixel_width_ <= 0 || pixel_height_ <= 0)
84 return nullptr;
85
86 // Set crop and display unit defaults if these elements are not present.
87 if (crop_bottom_ == -1)
88 crop_bottom_ = 0;
89
90 if (crop_top_ == -1)
91 crop_top_ = 0;
92
93 if (crop_left_ == -1)
94 crop_left_ = 0;
95
96 if (crop_right_ == -1)
97 crop_right_ = 0;
98
99 if (display_unit_ == -1)
100 display_unit_ = 0;
101
102 uint16_t width_after_crop = pixel_width_ - (crop_left_ + crop_right_);
103 uint16_t height_after_crop = pixel_height_ - (crop_top_ + crop_bottom_);
104
105 if (display_unit_ == 0) {
106 if (display_width_ <= 0)
107 display_width_ = width_after_crop;
108 if (display_height_ <= 0)
109 display_height_ = height_after_crop;
110 } else if (display_unit_ == 3) {
111 if (display_width_ <= 0 || display_height_ <= 0)
112 return nullptr;
113 } else {
114 LOG(ERROR) << "Unsupported display unit type " << display_unit_;
115 return nullptr;
116 }
117
118 // Calculate sample aspect ratio.
119 uint32_t pixel_width;
120 uint32_t pixel_height;
121 DerivePixelWidthHeight(width_after_crop, height_after_crop, display_width_,
122 display_height_, &pixel_width, &pixel_height);
123
124 // |codec_private| may be overriden later for some codecs, e.g. VP9 since for
125 // VP9, the format for MP4 and WebM are different; MP4 format is used as the
126 // intermediate format.
127 auto video_stream_info = std::make_shared<VideoStreamInfo>(
128 track_num, kWebMTimeScale, 0, video_codec, H26xStreamFormat::kUnSpecified,
129 codec_string, codec_private.data(), codec_private.size(),
130 width_after_crop, height_after_crop, pixel_width, pixel_height, 0, 0, 0,
131 0, 0, std::string(), is_encrypted);
132
133 // Set colr box data for VP8/VP9 codecs
134 if ((video_codec == kCodecVP8 || video_codec == kCodecVP9) &&
135 HasColorInfo()) {
136 std::vector<uint8_t> colr_data = GenerateColrBoxData();
137 if (!colr_data.empty()) {
138 video_stream_info->set_colr_data(colr_data.data(), colr_data.size());
139 }
140 }
141
142 return video_stream_info;
143}
144
146 const std::vector<uint8_t>& codec_private) {
148 vp_config.ParseWebM(codec_private);
149 if (matrix_coefficients_ != -1) {
150 vp_config.set_matrix_coefficients(matrix_coefficients_);
151 }
152 if (bits_per_channel_ != -1) {
153 vp_config.set_bit_depth(bits_per_channel_);
154 }
155 if (chroma_subsampling_horz_ != -1 && chroma_subsampling_vert_ != -1) {
156 vp_config.SetChromaSubsampling(chroma_subsampling_horz_,
157 chroma_subsampling_vert_);
158 }
159 if (chroma_siting_horz_ != -1 && chroma_siting_vert_ != -1) {
160 vp_config.SetChromaLocation(chroma_siting_horz_, chroma_siting_vert_);
161 }
162 if (color_range_ != -1) {
163 vp_config.set_video_full_range_flag(color_range_ == 2);
164 }
165 if (transfer_characteristics_ != -1) {
166 vp_config.set_transfer_characteristics(transfer_characteristics_);
167 }
168 if (color_primaries_ != -1) {
169 vp_config.set_color_primaries(color_primaries_);
170 }
171 return vp_config;
172}
173
174WebMParserClient* WebMVideoClient::OnListStart(int id) {
175 return id == kWebMIdColor || id == kWebMIdProjection
176 ? this
177 : WebMParserClient::OnListStart(id);
178}
179
180bool WebMVideoClient::OnListEnd(int id) {
181 return id == kWebMIdColor || id == kWebMIdProjection
182 ? true
183 : WebMParserClient::OnListEnd(id);
184}
185
186bool WebMVideoClient::OnUInt(int id, int64_t val) {
187 int64_t* dst = nullptr;
188
189 switch (id) {
190 case kWebMIdPixelWidth:
191 dst = &pixel_width_;
192 break;
193 case kWebMIdPixelHeight:
194 dst = &pixel_height_;
195 break;
196 case kWebMIdPixelCropTop:
197 dst = &crop_top_;
198 break;
199 case kWebMIdPixelCropBottom:
200 dst = &crop_bottom_;
201 break;
202 case kWebMIdPixelCropLeft:
203 dst = &crop_left_;
204 break;
205 case kWebMIdPixelCropRight:
206 dst = &crop_right_;
207 break;
208 case kWebMIdDisplayWidth:
209 dst = &display_width_;
210 break;
211 case kWebMIdDisplayHeight:
212 dst = &display_height_;
213 break;
214 case kWebMIdDisplayUnit:
215 dst = &display_unit_;
216 break;
217 case kWebMIdAlphaMode:
218 dst = &alpha_mode_;
219 break;
220 case kWebMIdColorMatrixCoefficients:
221 dst = &matrix_coefficients_;
222 break;
223 case kWebMIdColorBitsPerChannel:
224 dst = &bits_per_channel_;
225 break;
226 case kWebMIdColorChromaSubsamplingHorz:
227 dst = &chroma_subsampling_horz_;
228 break;
229 case kWebMIdColorChromaSubsamplingVert:
230 dst = &chroma_subsampling_vert_;
231 break;
232 case kWebMIdColorChromaSitingHorz:
233 dst = &chroma_siting_horz_;
234 break;
235 case kWebMIdColorChromaSitingVert:
236 dst = &chroma_siting_vert_;
237 break;
238 case kWebMIdColorRange:
239 dst = &color_range_;
240 break;
241 case kWebMIdColorTransferCharacteristics:
242 dst = &transfer_characteristics_;
243 break;
244 case kWebMIdColorPrimaries:
245 dst = &color_primaries_;
246 break;
247 case kWebMIdColorMaxCLL:
248 case kWebMIdColorMaxFALL:
249 NOTIMPLEMENTED() << "HDR is not supported yet.";
250 return true;
251 case kWebMIdProjectionType:
252 LOG(WARNING) << "Ignoring ProjectionType with value " << val;
253 return true;
254 default:
255 return true;
256 }
257
258 if (*dst != -1) {
259 LOG(ERROR) << "Multiple values for id " << std::hex << id << " specified ("
260 << *dst << " and " << val << ")";
261 return false;
262 }
263
264 *dst = val;
265 return true;
266}
267
268bool WebMVideoClient::OnBinary(int /*id*/,
269 const uint8_t* /*data*/,
270 int /*size*/) {
271 // Accept binary fields we don't care about for now.
272 return true;
273}
274
275bool WebMVideoClient::OnFloat(int /*id*/, double /*val*/) {
276 // Accept float fields we don't care about for now.
277 return true;
278}
279
281 return color_range_ != -1 || color_primaries_ != -1 ||
282 transfer_characteristics_ != -1 || matrix_coefficients_ != -1;
283}
284
285std::vector<uint8_t> WebMVideoClient::GenerateColrBoxData() const {
286 BufferWriter writer;
287
288 writer.AppendInt(static_cast<uint32_t>(0)); // Size placeholder
289 writer.AppendInt(FOURCC_colr);
290 writer.AppendInt(FOURCC_nclx);
291
292 // Use BT.709 as default when not specified
293 uint16_t primaries =
294 (color_primaries_ != -1) ? static_cast<uint16_t>(color_primaries_) : 1;
295 uint16_t transfer = (transfer_characteristics_ != -1)
296 ? static_cast<uint16_t>(transfer_characteristics_)
297 : 1;
298 uint16_t matrix = (matrix_coefficients_ != -1)
299 ? static_cast<uint16_t>(matrix_coefficients_)
300 : 1;
301
302 writer.AppendInt(primaries);
303 writer.AppendInt(transfer);
304 writer.AppendInt(matrix);
305
306 // WebM color_range: 0=unspecified, 1=broadcast/limited, 2=full range.
307 uint8_t full_range_flag = 0;
308 if (color_range_ != -1) {
309 full_range_flag = (color_range_ == 2) ? 1 : 0;
310 }
311 writer.AppendInt(full_range_flag);
312
313 const uint8_t* buffer = writer.Buffer();
314 size_t buffer_size = writer.Size();
315
316 std::vector<uint8_t> data(buffer, buffer + buffer_size);
317 uint32_t box_size = static_cast<uint32_t>(data.size());
318
319 // Update size field in big-endian
320 data[0] = (box_size >> 24) & 0xFF;
321 data[1] = (box_size >> 16) & 0xFF;
322 data[2] = (box_size >> 8) & 0xFF;
323 data[3] = box_size & 0xFF;
324
325 return data;
326}
327
328} // namespace media
329} // namespace shaka
Class for parsing AV1 codec configuration record.
bool Parse(const std::vector< uint8_t > &data)
const uint8_t * Buffer() const
Class for parsing or writing VP codec configuration record.
bool ParseWebM(const std::vector< uint8_t > &data)
bool HasColorInfo() const
Check if color information is available.
std::vector< uint8_t > GenerateColrBoxData() const
Generate MP4 colr box data from color information.
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's state so it can process a new video track element.
All the methods that are virtual are virtual for mocking.