1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
11
12 #include "absl/numeric/bits.h"
13 #include "absl/strings/string_view.h"
14 #include "rtc_base/bitstream_reader.h"
15 #include "rtc_base/logging.h"
16 #include "rtc_base/strings/string_builder.h"
17
18 namespace webrtc {
19 namespace {
20 const size_t kVp9NumRefsPerFrame = 3;
21 const size_t kVp9MaxRefLFDeltas = 4;
22 const size_t kVp9MaxModeLFDeltas = 2;
23 const size_t kVp9MinTileWidthB64 = 4;
24 const size_t kVp9MaxTileWidthB64 = 64;
25
Vp9ReadColorConfig(BitstreamReader & br,Vp9UncompressedHeader * frame_info)26 void Vp9ReadColorConfig(BitstreamReader& br,
27 Vp9UncompressedHeader* frame_info) {
28 if (frame_info->profile == 2 || frame_info->profile == 3) {
29 frame_info->bit_detph =
30 br.Read<bool>() ? Vp9BitDept::k12Bit : Vp9BitDept::k10Bit;
31 } else {
32 frame_info->bit_detph = Vp9BitDept::k8Bit;
33 }
34
35 frame_info->color_space = static_cast<Vp9ColorSpace>(br.ReadBits(3));
36
37 if (frame_info->color_space != Vp9ColorSpace::CS_RGB) {
38 frame_info->color_range =
39 br.Read<bool>() ? Vp9ColorRange::kFull : Vp9ColorRange::kStudio;
40
41 if (frame_info->profile == 1 || frame_info->profile == 3) {
42 static constexpr Vp9YuvSubsampling kSubSamplings[] = {
43 Vp9YuvSubsampling::k444, Vp9YuvSubsampling::k440,
44 Vp9YuvSubsampling::k422, Vp9YuvSubsampling::k420};
45 frame_info->sub_sampling = kSubSamplings[br.ReadBits(2)];
46
47 if (br.Read<bool>()) {
48 RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set.";
49 br.Invalidate();
50 return;
51 }
52 } else {
53 // Profile 0 or 2.
54 frame_info->sub_sampling = Vp9YuvSubsampling::k420;
55 }
56 } else {
57 // SRGB
58 frame_info->color_range = Vp9ColorRange::kFull;
59 if (frame_info->profile == 1 || frame_info->profile == 3) {
60 frame_info->sub_sampling = Vp9YuvSubsampling::k444;
61 if (br.Read<bool>()) {
62 RTC_LOG(LS_WARNING) << "Failed to parse header. Reserved bit set.";
63 br.Invalidate();
64 }
65 } else {
66 RTC_LOG(LS_WARNING) << "Failed to parse header. 4:4:4 color not supported"
67 " in profile 0 or 2.";
68 br.Invalidate();
69 }
70 }
71 }
72
ReadRefreshFrameFlags(BitstreamReader & br,Vp9UncompressedHeader * frame_info)73 void ReadRefreshFrameFlags(BitstreamReader& br,
74 Vp9UncompressedHeader* frame_info) {
75 // Refresh frame flags.
76 uint8_t flags = br.Read<uint8_t>();
77 for (int i = 0; i < 8; ++i) {
78 frame_info->updated_buffers.set(i, (flags & (0x01 << (7 - i))) != 0);
79 }
80 }
81
Vp9ReadFrameSize(BitstreamReader & br,Vp9UncompressedHeader * frame_info)82 void Vp9ReadFrameSize(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
83 // 16 bits: frame (width|height) - 1.
84 frame_info->frame_width = br.Read<uint16_t>() + 1;
85 frame_info->frame_height = br.Read<uint16_t>() + 1;
86 }
87
Vp9ReadRenderSize(size_t total_buffer_size_bits,BitstreamReader & br,Vp9UncompressedHeader * frame_info)88 void Vp9ReadRenderSize(size_t total_buffer_size_bits,
89 BitstreamReader& br,
90 Vp9UncompressedHeader* frame_info) {
91 // render_and_frame_size_different
92 if (br.Read<bool>()) {
93 frame_info->render_size_offset_bits =
94 total_buffer_size_bits - br.RemainingBitCount();
95 // 16 bits: render (width|height) - 1.
96 frame_info->render_width = br.Read<uint16_t>() + 1;
97 frame_info->render_height = br.Read<uint16_t>() + 1;
98 } else {
99 frame_info->render_height = frame_info->frame_height;
100 frame_info->render_width = frame_info->frame_width;
101 }
102 }
103
Vp9ReadFrameSizeFromRefs(BitstreamReader & br,Vp9UncompressedHeader * frame_info)104 void Vp9ReadFrameSizeFromRefs(BitstreamReader& br,
105 Vp9UncompressedHeader* frame_info) {
106 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) {
107 // Size in refs.
108 if (br.Read<bool>()) {
109 frame_info->infer_size_from_reference = frame_info->reference_buffers[i];
110 return;
111 }
112 }
113
114 Vp9ReadFrameSize(br, frame_info);
115 }
116
Vp9ReadLoopfilter(BitstreamReader & br)117 void Vp9ReadLoopfilter(BitstreamReader& br) {
118 // 6 bits: filter level.
119 // 3 bits: sharpness level.
120 br.ConsumeBits(9);
121
122 if (!br.Read<bool>()) { // mode_ref_delta_enabled
123 return;
124 }
125 if (!br.Read<bool>()) { // mode_ref_delta_update
126 return;
127 }
128
129 for (size_t i = 0; i < kVp9MaxRefLFDeltas; i++) {
130 if (br.Read<bool>()) { // update_ref_delta
131 br.ConsumeBits(7);
132 }
133 }
134 for (size_t i = 0; i < kVp9MaxModeLFDeltas; i++) {
135 if (br.Read<bool>()) { // update_mode_delta
136 br.ConsumeBits(7);
137 }
138 }
139 }
140
Vp9ReadQp(BitstreamReader & br,Vp9UncompressedHeader * frame_info)141 void Vp9ReadQp(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
142 frame_info->base_qp = br.Read<uint8_t>();
143
144 // yuv offsets
145 frame_info->is_lossless = frame_info->base_qp == 0;
146 for (int i = 0; i < 3; ++i) {
147 if (br.Read<bool>()) { // if delta_coded
148 // delta_q is a signed integer with leading 4 bits containing absolute
149 // value and last bit containing sign. There are are two ways to represent
150 // zero with such encoding.
151 if ((br.ReadBits(5) & 0b1111'0) != 0) { // delta_q
152 frame_info->is_lossless = false;
153 }
154 }
155 }
156 }
157
Vp9ReadSegmentationParams(BitstreamReader & br,Vp9UncompressedHeader * frame_info)158 void Vp9ReadSegmentationParams(BitstreamReader& br,
159 Vp9UncompressedHeader* frame_info) {
160 constexpr int kSegmentationFeatureBits[kVp9SegLvlMax] = {8, 6, 2, 0};
161 constexpr bool kSegmentationFeatureSigned[kVp9SegLvlMax] = {true, true, false,
162 false};
163
164 frame_info->segmentation_enabled = br.Read<bool>();
165 if (!frame_info->segmentation_enabled) {
166 return;
167 }
168
169 if (br.Read<bool>()) { // update_map
170 frame_info->segmentation_tree_probs.emplace();
171 for (int i = 0; i < 7; ++i) {
172 if (br.Read<bool>()) {
173 (*frame_info->segmentation_tree_probs)[i] = br.Read<uint8_t>();
174 } else {
175 (*frame_info->segmentation_tree_probs)[i] = 255;
176 }
177 }
178
179 // temporal_update
180 frame_info->segmentation_pred_prob.emplace();
181 if (br.Read<bool>()) {
182 for (int i = 0; i < 3; ++i) {
183 if (br.Read<bool>()) {
184 (*frame_info->segmentation_pred_prob)[i] = br.Read<uint8_t>();
185 } else {
186 (*frame_info->segmentation_pred_prob)[i] = 255;
187 }
188 }
189 } else {
190 frame_info->segmentation_pred_prob->fill(255);
191 }
192 }
193
194 if (br.Read<bool>()) { // segmentation_update_data
195 frame_info->segmentation_is_delta = br.Read<bool>();
196 for (size_t i = 0; i < kVp9MaxSegments; ++i) {
197 for (size_t j = 0; j < kVp9SegLvlMax; ++j) {
198 if (!br.Read<bool>()) { // feature_enabled
199 continue;
200 }
201 if (kSegmentationFeatureBits[j] == 0) {
202 // No feature bits used and no sign, just mark it and return.
203 frame_info->segmentation_features[i][j] = 1;
204 continue;
205 }
206 frame_info->segmentation_features[i][j] =
207 br.ReadBits(kSegmentationFeatureBits[j]);
208 if (kSegmentationFeatureSigned[j] && br.Read<bool>()) {
209 (*frame_info->segmentation_features[i][j]) *= -1;
210 }
211 }
212 }
213 }
214 }
215
Vp9ReadTileInfo(BitstreamReader & br,Vp9UncompressedHeader * frame_info)216 void Vp9ReadTileInfo(BitstreamReader& br, Vp9UncompressedHeader* frame_info) {
217 size_t mi_cols = (frame_info->frame_width + 7) >> 3;
218 size_t sb64_cols = (mi_cols + 7) >> 3;
219
220 size_t min_log2 = 0;
221 while ((kVp9MaxTileWidthB64 << min_log2) < sb64_cols) {
222 ++min_log2;
223 }
224
225 size_t max_log2 = 1;
226 while ((sb64_cols >> max_log2) >= kVp9MinTileWidthB64) {
227 ++max_log2;
228 }
229 --max_log2;
230
231 frame_info->tile_cols_log2 = min_log2;
232 while (frame_info->tile_cols_log2 < max_log2) {
233 if (br.Read<bool>()) {
234 ++frame_info->tile_cols_log2;
235 } else {
236 break;
237 }
238 }
239 frame_info->tile_rows_log2 = 0;
240 if (br.Read<bool>()) {
241 ++frame_info->tile_rows_log2;
242 if (br.Read<bool>()) {
243 ++frame_info->tile_rows_log2;
244 }
245 }
246 }
247
248 const Vp9InterpolationFilter kLiteralToType[4] = {
249 Vp9InterpolationFilter::kEightTapSmooth, Vp9InterpolationFilter::kEightTap,
250 Vp9InterpolationFilter::kEightTapSharp, Vp9InterpolationFilter::kBilinear};
251 } // namespace
252
ToString() const253 std::string Vp9UncompressedHeader::ToString() const {
254 char buf[1024];
255 rtc::SimpleStringBuilder oss(buf);
256
257 oss << "Vp9UncompressedHeader { "
258 << "profile = " << profile;
259
260 if (show_existing_frame) {
261 oss << ", show_existing_frame = " << *show_existing_frame << " }";
262 return oss.str();
263 }
264
265 oss << ", frame type = " << (is_keyframe ? "key" : "delta")
266 << ", show_frame = " << (show_frame ? "true" : "false")
267 << ", error_resilient = " << (error_resilient ? "true" : "false");
268
269 oss << ", bit_depth = ";
270 switch (bit_detph) {
271 case Vp9BitDept::k8Bit:
272 oss << "8bit";
273 break;
274 case Vp9BitDept::k10Bit:
275 oss << "10bit";
276 break;
277 case Vp9BitDept::k12Bit:
278 oss << "12bit";
279 break;
280 }
281
282 if (color_space) {
283 oss << ", color_space = ";
284 switch (*color_space) {
285 case Vp9ColorSpace::CS_UNKNOWN:
286 oss << "unknown";
287 break;
288 case Vp9ColorSpace::CS_BT_601:
289 oss << "CS_BT_601 Rec. ITU-R BT.601-7";
290 break;
291 case Vp9ColorSpace::CS_BT_709:
292 oss << "Rec. ITU-R BT.709-6";
293 break;
294 case Vp9ColorSpace::CS_SMPTE_170:
295 oss << "SMPTE-170";
296 break;
297 case Vp9ColorSpace::CS_SMPTE_240:
298 oss << "SMPTE-240";
299 break;
300 case Vp9ColorSpace::CS_BT_2020:
301 oss << "Rec. ITU-R BT.2020-2";
302 break;
303 case Vp9ColorSpace::CS_RESERVED:
304 oss << "Reserved";
305 break;
306 case Vp9ColorSpace::CS_RGB:
307 oss << "sRGB (IEC 61966-2-1)";
308 break;
309 }
310 }
311
312 if (color_range) {
313 oss << ", color_range = ";
314 switch (*color_range) {
315 case Vp9ColorRange::kFull:
316 oss << "full";
317 break;
318 case Vp9ColorRange::kStudio:
319 oss << "studio";
320 break;
321 }
322 }
323
324 if (sub_sampling) {
325 oss << ", sub_sampling = ";
326 switch (*sub_sampling) {
327 case Vp9YuvSubsampling::k444:
328 oss << "444";
329 break;
330 case Vp9YuvSubsampling::k440:
331 oss << "440";
332 break;
333 case Vp9YuvSubsampling::k422:
334 oss << "422";
335 break;
336 case Vp9YuvSubsampling::k420:
337 oss << "420";
338 break;
339 }
340 }
341
342 if (infer_size_from_reference) {
343 oss << ", infer_frame_resolution_from = " << *infer_size_from_reference;
344 } else {
345 oss << ", frame_width = " << frame_width
346 << ", frame_height = " << frame_height;
347 }
348 if (render_width != 0 && render_height != 0) {
349 oss << ", render_width = " << render_width
350 << ", render_height = " << render_height;
351 }
352
353 oss << ", base qp = " << base_qp;
354 if (reference_buffers[0] != -1) {
355 oss << ", last_buffer = " << reference_buffers[0];
356 }
357 if (reference_buffers[1] != -1) {
358 oss << ", golden_buffer = " << reference_buffers[1];
359 }
360 if (reference_buffers[2] != -1) {
361 oss << ", altref_buffer = " << reference_buffers[2];
362 }
363
364 oss << ", updated buffers = { ";
365 bool first = true;
366 for (int i = 0; i < 8; ++i) {
367 if (updated_buffers.test(i)) {
368 if (first) {
369 first = false;
370 } else {
371 oss << ", ";
372 }
373 oss << i;
374 }
375 }
376 oss << " }";
377
378 oss << ", compressed_header_size_bytes = " << compressed_header_size;
379
380 oss << " }";
381 return oss.str();
382 }
383
Parse(BitstreamReader & br,Vp9UncompressedHeader * frame_info,bool qp_only)384 void Parse(BitstreamReader& br,
385 Vp9UncompressedHeader* frame_info,
386 bool qp_only) {
387 const size_t total_buffer_size_bits = br.RemainingBitCount();
388
389 // Frame marker.
390 if (br.ReadBits(2) != 0b10) {
391 RTC_LOG(LS_WARNING) << "Failed to parse header. Frame marker should be 2.";
392 br.Invalidate();
393 return;
394 }
395
396 // Profile has low bit first.
397 frame_info->profile = br.ReadBit();
398 frame_info->profile |= br.ReadBit() << 1;
399 if (frame_info->profile > 2 && br.Read<bool>()) {
400 RTC_LOG(LS_WARNING)
401 << "Failed to parse header. Unsupported bitstream profile.";
402 br.Invalidate();
403 return;
404 }
405
406 // Show existing frame.
407 if (br.Read<bool>()) {
408 frame_info->show_existing_frame = br.ReadBits(3);
409 return;
410 }
411
412 // Frame type: KEY_FRAME(0), INTER_FRAME(1).
413 frame_info->is_keyframe = !br.Read<bool>();
414 frame_info->show_frame = br.Read<bool>();
415 frame_info->error_resilient = br.Read<bool>();
416
417 if (frame_info->is_keyframe) {
418 if (br.ReadBits(24) != 0x498342) {
419 RTC_LOG(LS_WARNING) << "Failed to parse header. Invalid sync code.";
420 br.Invalidate();
421 return;
422 }
423
424 Vp9ReadColorConfig(br, frame_info);
425 Vp9ReadFrameSize(br, frame_info);
426 Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
427
428 // Key-frames implicitly update all buffers.
429 frame_info->updated_buffers.set();
430 } else {
431 // Non-keyframe.
432 bool is_intra_only = false;
433 if (!frame_info->show_frame) {
434 is_intra_only = br.Read<bool>();
435 }
436 if (!frame_info->error_resilient) {
437 br.ConsumeBits(2); // Reset frame context.
438 }
439
440 if (is_intra_only) {
441 if (br.ReadBits(24) != 0x498342) {
442 RTC_LOG(LS_WARNING) << "Failed to parse header. Invalid sync code.";
443 br.Invalidate();
444 return;
445 }
446
447 if (frame_info->profile > 0) {
448 Vp9ReadColorConfig(br, frame_info);
449 } else {
450 frame_info->color_space = Vp9ColorSpace::CS_BT_601;
451 frame_info->sub_sampling = Vp9YuvSubsampling::k420;
452 frame_info->bit_detph = Vp9BitDept::k8Bit;
453 }
454 frame_info->reference_buffers.fill(-1);
455 ReadRefreshFrameFlags(br, frame_info);
456 Vp9ReadFrameSize(br, frame_info);
457 Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
458 } else {
459 ReadRefreshFrameFlags(br, frame_info);
460
461 frame_info->reference_buffers_sign_bias[0] = false;
462 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) {
463 frame_info->reference_buffers[i] = br.ReadBits(3);
464 frame_info->reference_buffers_sign_bias[Vp9ReferenceFrame::kLast + i] =
465 br.Read<bool>();
466 }
467
468 Vp9ReadFrameSizeFromRefs(br, frame_info);
469 Vp9ReadRenderSize(total_buffer_size_bits, br, frame_info);
470
471 frame_info->allow_high_precision_mv = br.Read<bool>();
472
473 // Interpolation filter.
474 if (br.Read<bool>()) {
475 frame_info->interpolation_filter = Vp9InterpolationFilter::kSwitchable;
476 } else {
477 frame_info->interpolation_filter = kLiteralToType[br.ReadBits(2)];
478 }
479 }
480 }
481
482 if (!frame_info->error_resilient) {
483 // 1 bit: Refresh frame context.
484 // 1 bit: Frame parallel decoding mode.
485 br.ConsumeBits(2);
486 }
487
488 // Frame context index.
489 frame_info->frame_context_idx = br.ReadBits(2);
490
491 Vp9ReadLoopfilter(br);
492
493 // Read base QP.
494 Vp9ReadQp(br, frame_info);
495
496 if (qp_only) {
497 // Not interested in the rest of the header, return early.
498 return;
499 }
500
501 Vp9ReadSegmentationParams(br, frame_info);
502 Vp9ReadTileInfo(br, frame_info);
503 frame_info->compressed_header_size = br.Read<uint16_t>();
504 frame_info->uncompressed_header_size =
505 (total_buffer_size_bits / 8) - (br.RemainingBitCount() / 8);
506 }
507
ParseUncompressedVp9Header(rtc::ArrayView<const uint8_t> buf)508 absl::optional<Vp9UncompressedHeader> ParseUncompressedVp9Header(
509 rtc::ArrayView<const uint8_t> buf) {
510 BitstreamReader reader(buf);
511 Vp9UncompressedHeader frame_info;
512 Parse(reader, &frame_info, /*qp_only=*/false);
513 if (reader.Ok() && frame_info.frame_width > 0) {
514 return frame_info;
515 }
516 return absl::nullopt;
517 }
518
519 namespace vp9 {
520
GetQp(const uint8_t * buf,size_t length,int * qp)521 bool GetQp(const uint8_t* buf, size_t length, int* qp) {
522 BitstreamReader reader(rtc::MakeArrayView(buf, length));
523 Vp9UncompressedHeader frame_info;
524 Parse(reader, &frame_info, /*qp_only=*/true);
525 if (!reader.Ok()) {
526 return false;
527 }
528 *qp = frame_info.base_qp;
529 return true;
530 }
531
532 } // namespace vp9
533 } // namespace webrtc
534