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