1 // Copyright 2015 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.
5 // This file contains an implementation of a VP9 bitstream parser.
7 #include "media/filters/vp9_parser.h"
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
14 const int kMaxLoopFilterLevel
= 63;
16 // Helper function for Vp9Parser::ReadTiles. Defined as get_min_log2_tile_cols
18 int GetMinLog2TileCols(int sb64_cols
) {
19 const int kMaxTileWidthB64
= 64;
21 while ((kMaxTileWidthB64
<< min_log2
) < sb64_cols
)
26 // Helper function for Vp9Parser::ReadTiles. Defined as get_max_log2_tile_cols
28 int GetMaxLog2TileCols(int sb64_cols
) {
29 const int kMinTileWidthB64
= 4;
31 while ((sb64_cols
>> max_log2
) >= kMinTileWidthB64
)
40 bool Vp9FrameHeader::IsKeyframe() const {
41 // When show_existing_frame is true, the frame header does not precede an
42 // actual frame to be decoded, so frame_type does not apply (and is not read
44 return !show_existing_frame
&& frame_type
== KEYFRAME
;
47 Vp9Parser::FrameInfo::FrameInfo(const uint8_t* ptr
, off_t size
)
48 : ptr(ptr
), size(size
) {}
50 Vp9Parser::Vp9Parser() {
54 Vp9Parser::~Vp9Parser() {}
56 void Vp9Parser::SetStream(const uint8_t* stream
, off_t stream_size
) {
59 bytes_left_
= stream_size
;
63 void Vp9Parser::Reset() {
68 memset(&segmentation_
, 0, sizeof(segmentation_
));
69 memset(&loop_filter_
, 0, sizeof(loop_filter_
));
70 memset(&ref_slots_
, 0, sizeof(ref_slots_
));
73 uint8_t Vp9Parser::ReadProfile() {
77 if (reader_
.ReadBool())
79 if (reader_
.ReadBool())
81 if (profile
> 2 && reader_
.ReadBool())
86 bool Vp9Parser::VerifySyncCode() {
87 const int kSyncCode
= 0x498342;
88 if (reader_
.ReadLiteral(8 * 3) != kSyncCode
) {
89 DVLOG(1) << "Invalid frame sync code";
95 bool Vp9Parser::ReadBitDepthColorSpaceSampling(Vp9FrameHeader
* fhdr
) {
96 if (fhdr
->profile
== 2 || fhdr
->profile
== 3) {
97 fhdr
->bit_depth
= reader_
.ReadBool() ? 12 : 10;
102 fhdr
->color_space
= static_cast<Vp9ColorSpace
>(reader_
.ReadLiteral(3));
103 if (fhdr
->color_space
!= Vp9ColorSpace::SRGB
) {
104 fhdr
->yuv_range
= reader_
.ReadBool();
105 if (fhdr
->profile
== 1 || fhdr
->profile
== 3) {
106 fhdr
->subsampling_x
= reader_
.ReadBool() ? 1 : 0;
107 fhdr
->subsampling_y
= reader_
.ReadBool() ? 1 : 0;
108 if (fhdr
->subsampling_x
== 1 && fhdr
->subsampling_y
== 1) {
109 DVLOG(1) << "4:2:0 color not supported in profile 1 or 3";
112 bool reserved
= reader_
.ReadBool();
114 DVLOG(1) << "reserved bit set";
118 fhdr
->subsampling_x
= fhdr
->subsampling_y
= 1;
121 if (fhdr
->profile
== 1 || fhdr
->profile
== 3) {
122 fhdr
->subsampling_x
= fhdr
->subsampling_y
= 0;
124 bool reserved
= reader_
.ReadBool();
126 DVLOG(1) << "reserved bit set";
130 DVLOG(1) << "4:4:4 color not supported in profile 0 or 2";
138 void Vp9Parser::ReadFrameSize(Vp9FrameHeader
* fhdr
) {
139 fhdr
->width
= reader_
.ReadLiteral(16) + 1;
140 fhdr
->height
= reader_
.ReadLiteral(16) + 1;
143 bool Vp9Parser::ReadFrameSizeFromRefs(Vp9FrameHeader
* fhdr
) {
144 for (size_t i
= 0; i
< kVp9NumRefsPerFrame
; i
++) {
145 if (reader_
.ReadBool()) {
146 fhdr
->width
= ref_slots_
[i
].width
;
147 fhdr
->height
= ref_slots_
[i
].height
;
149 const int kMaxDimension
= 1 << 16;
150 if (fhdr
->width
== 0 || fhdr
->width
> kMaxDimension
||
151 fhdr
->height
== 0 || fhdr
->height
> kMaxDimension
) {
152 DVLOG(1) << "The size of reference frame is out of range: "
153 << ref_slots_
[i
].width
<< "," << ref_slots_
[i
].height
;
160 fhdr
->width
= reader_
.ReadLiteral(16) + 1;
161 fhdr
->height
= reader_
.ReadLiteral(16) + 1;
165 void Vp9Parser::ReadDisplayFrameSize(Vp9FrameHeader
* fhdr
) {
166 if (reader_
.ReadBool()) {
167 fhdr
->display_width
= reader_
.ReadLiteral(16) + 1;
168 fhdr
->display_height
= reader_
.ReadLiteral(16) + 1;
170 fhdr
->display_width
= fhdr
->width
;
171 fhdr
->display_height
= fhdr
->height
;
175 Vp9InterpFilter
Vp9Parser::ReadInterpFilter() {
176 if (reader_
.ReadBool())
177 return Vp9InterpFilter::SWICHABLE
;
179 // The mapping table for next two bits.
180 const Vp9InterpFilter table
[] = {
181 Vp9InterpFilter::EIGHTTAP_SMOOTH
, Vp9InterpFilter::EIGHTTAP
,
182 Vp9InterpFilter::EIGHTTAP_SHARP
, Vp9InterpFilter::BILINEAR
,
184 return table
[reader_
.ReadLiteral(2)];
187 void Vp9Parser::ReadLoopFilter() {
188 loop_filter_
.filter_level
= reader_
.ReadLiteral(6);
189 loop_filter_
.sharpness_level
= reader_
.ReadLiteral(3);
190 loop_filter_
.mode_ref_delta_update
= false;
192 loop_filter_
.mode_ref_delta_enabled
= reader_
.ReadBool();
193 if (loop_filter_
.mode_ref_delta_enabled
) {
194 loop_filter_
.mode_ref_delta_update
= reader_
.ReadBool();
195 if (loop_filter_
.mode_ref_delta_update
) {
196 for (size_t i
= 0; i
< Vp9LoopFilter::VP9_FRAME_MAX
; i
++) {
197 loop_filter_
.update_ref_deltas
[i
] = reader_
.ReadBool();
198 if (loop_filter_
.update_ref_deltas
[i
])
199 loop_filter_
.ref_deltas
[i
] = reader_
.ReadSignedLiteral(6);
202 for (size_t i
= 0; i
< Vp9LoopFilter::kNumModeDeltas
; i
++) {
203 loop_filter_
.update_mode_deltas
[i
] = reader_
.ReadBool();
204 if (loop_filter_
.update_mode_deltas
[i
])
205 loop_filter_
.mode_deltas
[i
] = reader_
.ReadLiteral(6);
211 void Vp9Parser::ReadQuantization(Vp9QuantizationParams
* quants
) {
212 quants
->base_qindex
= reader_
.ReadLiteral(8);
214 if (reader_
.ReadBool())
215 quants
->y_dc_delta
= reader_
.ReadSignedLiteral(4);
217 if (reader_
.ReadBool())
218 quants
->uv_ac_delta
= reader_
.ReadSignedLiteral(4);
220 if (reader_
.ReadBool())
221 quants
->uv_dc_delta
= reader_
.ReadSignedLiteral(4);
224 void Vp9Parser::ReadSegmentationMap() {
225 for (size_t i
= 0; i
< Vp9Segmentation::kNumTreeProbs
; i
++) {
226 segmentation_
.tree_probs
[i
] =
227 reader_
.ReadBool() ? reader_
.ReadLiteral(8) : kVp9MaxProb
;
230 for (size_t i
= 0; i
< Vp9Segmentation::kNumPredictionProbs
; i
++)
231 segmentation_
.pred_probs
[i
] = kVp9MaxProb
;
233 segmentation_
.temporal_update
= reader_
.ReadBool();
234 if (segmentation_
.temporal_update
) {
235 for (size_t i
= 0; i
< Vp9Segmentation::kNumPredictionProbs
; i
++) {
236 if (reader_
.ReadBool())
237 segmentation_
.pred_probs
[i
] = reader_
.ReadLiteral(8);
242 void Vp9Parser::ReadSegmentationData() {
243 segmentation_
.abs_delta
= reader_
.ReadBool();
245 const int kFeatureDataBits
[] = {7, 6, 2, 0};
246 const bool kFeatureDataSigned
[] = {true, true, false, false};
248 for (size_t i
= 0; i
< Vp9Segmentation::kNumSegments
; i
++) {
249 for (size_t j
= 0; j
< Vp9Segmentation::SEG_LVL_MAX
; j
++) {
251 segmentation_
.feature_enabled
[i
][j
] = reader_
.ReadBool();
252 if (segmentation_
.feature_enabled
[i
][j
]) {
253 data
= reader_
.ReadLiteral(kFeatureDataBits
[j
]);
254 if (kFeatureDataSigned
[j
])
255 if (reader_
.ReadBool())
258 segmentation_
.feature_data
[i
][j
] = data
;
263 void Vp9Parser::ReadSegmentation() {
264 segmentation_
.update_map
= false;
265 segmentation_
.update_data
= false;
267 segmentation_
.enabled
= reader_
.ReadBool();
268 if (!segmentation_
.enabled
)
271 segmentation_
.update_map
= reader_
.ReadBool();
272 if (segmentation_
.update_map
)
273 ReadSegmentationMap();
275 segmentation_
.update_data
= reader_
.ReadBool();
276 if (segmentation_
.update_data
)
277 ReadSegmentationData();
280 void Vp9Parser::ReadTiles(Vp9FrameHeader
* fhdr
) {
281 int sb64_cols
= (fhdr
->width
+ 63) / 64;
283 int min_log2_tile_cols
= GetMinLog2TileCols(sb64_cols
);
284 int max_log2_tile_cols
= GetMaxLog2TileCols(sb64_cols
);
286 int max_ones
= max_log2_tile_cols
- min_log2_tile_cols
;
287 fhdr
->log2_tile_cols
= min_log2_tile_cols
;
288 while (max_ones
-- && reader_
.ReadBool())
289 fhdr
->log2_tile_cols
++;
291 if (reader_
.ReadBool())
292 fhdr
->log2_tile_rows
= reader_
.ReadLiteral(2) - 1;
295 bool Vp9Parser::ParseUncompressedHeader(const uint8_t* stream
,
297 Vp9FrameHeader
* fhdr
) {
298 reader_
.Initialize(stream
, frame_size
);
301 fhdr
->frame_size
= frame_size
;
304 if (reader_
.ReadLiteral(2) != 0x2)
307 fhdr
->profile
= ReadProfile();
308 if (fhdr
->profile
>= kVp9MaxProfile
) {
309 DVLOG(1) << "Unsupported bitstream profile";
313 fhdr
->show_existing_frame
= reader_
.ReadBool();
314 if (fhdr
->show_existing_frame
) {
315 fhdr
->frame_to_show
= reader_
.ReadLiteral(3);
316 fhdr
->show_frame
= true;
318 if (!reader_
.IsValid()) {
319 DVLOG(1) << "parser reads beyond the end of buffer";
322 fhdr
->uncompressed_header_size
= reader_
.GetBytesRead();
326 fhdr
->frame_type
= static_cast<Vp9FrameHeader::FrameType
>(reader_
.ReadBool());
327 fhdr
->show_frame
= reader_
.ReadBool();
328 fhdr
->error_resilient_mode
= reader_
.ReadBool();
330 if (fhdr
->IsKeyframe()) {
331 if (!VerifySyncCode())
334 if (!ReadBitDepthColorSpaceSampling(fhdr
))
337 fhdr
->refresh_flags
= 0xff;
340 ReadDisplayFrameSize(fhdr
);
342 if (!fhdr
->show_frame
)
343 fhdr
->intra_only
= reader_
.ReadBool();
345 if (!fhdr
->error_resilient_mode
)
346 fhdr
->reset_context
= reader_
.ReadLiteral(2);
348 if (fhdr
->intra_only
) {
349 if (!VerifySyncCode())
352 if (fhdr
->profile
> 0) {
353 if (!ReadBitDepthColorSpaceSampling(fhdr
))
357 fhdr
->color_space
= Vp9ColorSpace::BT_601
;
358 fhdr
->subsampling_x
= fhdr
->subsampling_y
= 1;
361 fhdr
->refresh_flags
= reader_
.ReadLiteral(8);
364 ReadDisplayFrameSize(fhdr
);
366 fhdr
->refresh_flags
= reader_
.ReadLiteral(8);
368 for (size_t i
= 0; i
< kVp9NumRefsPerFrame
; i
++) {
369 fhdr
->frame_refs
[i
] = reader_
.ReadLiteral(kVp9NumRefFramesLog2
);
370 fhdr
->ref_sign_biases
[i
] = reader_
.ReadBool();
373 if (!ReadFrameSizeFromRefs(fhdr
))
375 ReadDisplayFrameSize(fhdr
);
377 fhdr
->allow_high_precision_mv
= reader_
.ReadBool();
378 fhdr
->interp_filter
= ReadInterpFilter();
382 if (fhdr
->error_resilient_mode
) {
383 fhdr
->frame_parallel_decoding_mode
= true;
385 fhdr
->refresh_frame_context
= reader_
.ReadBool();
386 fhdr
->frame_parallel_decoding_mode
= reader_
.ReadBool();
389 fhdr
->frame_context_idx
= reader_
.ReadLiteral(2);
391 if (fhdr
->IsKeyframe() || fhdr
->intra_only
)
392 SetupPastIndependence();
395 ReadQuantization(&fhdr
->quant_params
);
400 fhdr
->first_partition_size
= reader_
.ReadLiteral(16);
401 if (fhdr
->first_partition_size
== 0) {
402 DVLOG(1) << "invalid header size";
406 if (!reader_
.IsValid()) {
407 DVLOG(1) << "parser reads beyond the end of buffer";
410 fhdr
->uncompressed_header_size
= reader_
.GetBytesRead();
412 SetupSegmentationDequant(fhdr
->quant_params
);
420 void Vp9Parser::UpdateSlots(const Vp9FrameHeader
* fhdr
) {
421 for (size_t i
= 0; i
< kVp9NumRefFrames
; i
++) {
422 if (fhdr
->RefreshFlag(i
)) {
423 ref_slots_
[i
].width
= fhdr
->width
;
424 ref_slots_
[i
].height
= fhdr
->height
;
429 Vp9Parser::Result
Vp9Parser::ParseNextFrame(Vp9FrameHeader
* fhdr
) {
430 if (frames_
.empty()) {
431 // No frames to be decoded, if there is no more stream, request more.
435 // New stream to be parsed, parse it and fill frames_.
436 if (!ParseSuperframe()) {
437 DVLOG(1) << "Failed parsing superframes";
438 return kInvalidStream
;
442 DCHECK(!frames_
.empty());
443 FrameInfo frame_info
= frames_
.front();
446 memset(fhdr
, 0, sizeof(*fhdr
));
447 if (!ParseUncompressedHeader(frame_info
.ptr
, frame_info
.size
, fhdr
))
448 return kInvalidStream
;
453 bool Vp9Parser::ParseSuperframe() {
454 const uint8_t* stream
= stream_
;
455 off_t bytes_left
= bytes_left_
;
457 DCHECK(frames_
.empty());
459 // Make sure we don't parse stream_ more than once.
466 // If this is a superframe, the last byte in the stream will contain the
467 // superframe marker. If not, the whole buffer contains a single frame.
468 uint8_t marker
= *(stream
+ bytes_left
- 1);
469 if ((marker
& 0xe0) != 0xc0) {
470 frames_
.push_back(FrameInfo(stream
, bytes_left
));
474 DVLOG(1) << "Parsing a superframe";
476 // The bytes immediately before the superframe marker constitute superframe
477 // index, which stores information about sizes of each frame in it.
478 // Calculate its size and set index_ptr to the beginning of it.
479 size_t num_frames
= (marker
& 0x7) + 1;
480 size_t mag
= ((marker
>> 3) & 0x3) + 1;
481 off_t index_size
= 2 + mag
* num_frames
;
483 if (bytes_left
< index_size
)
486 const uint8_t* index_ptr
= stream
+ bytes_left
- index_size
;
487 if (marker
!= *index_ptr
)
491 bytes_left
-= index_size
;
493 // Parse frame information contained in the index and add a pointer to and
494 // size of each frame to frames_.
495 for (size_t i
= 0; i
< num_frames
; ++i
) {
497 for (size_t j
= 0; j
< mag
; ++j
) {
498 size
|= *index_ptr
<< (j
* 8);
502 if (base::checked_cast
<off_t
>(size
) > bytes_left
) {
503 DVLOG(1) << "Not enough data in the buffer for frame " << i
;
507 frames_
.push_back(FrameInfo(stream
, size
));
511 DVLOG(1) << "Frame " << i
<< ", size: " << size
;
517 void Vp9Parser::ResetLoopfilter() {
518 loop_filter_
.mode_ref_delta_enabled
= true;
519 loop_filter_
.mode_ref_delta_update
= true;
521 const int8_t default_ref_deltas
[] = {1, 0, -1, -1};
523 arraysize(default_ref_deltas
) == arraysize(loop_filter_
.ref_deltas
),
524 "ref_deltas arrays of incorrect size");
525 for (size_t i
= 0; i
< arraysize(loop_filter_
.ref_deltas
); ++i
)
526 loop_filter_
.ref_deltas
[i
] = default_ref_deltas
[i
];
528 memset(loop_filter_
.mode_deltas
, 0, sizeof(loop_filter_
.mode_deltas
));
531 void Vp9Parser::SetupPastIndependence() {
532 memset(&segmentation_
, 0, sizeof(segmentation_
));
536 const size_t QINDEX_RANGE
= 256;
537 const int16_t kDcQLookup
[QINDEX_RANGE
] = {
538 4, 8, 8, 9, 10, 11, 12, 12,
539 13, 14, 15, 16, 17, 18, 19, 19,
540 20, 21, 22, 23, 24, 25, 26, 26,
541 27, 28, 29, 30, 31, 32, 32, 33,
542 34, 35, 36, 37, 38, 38, 39, 40,
543 41, 42, 43, 43, 44, 45, 46, 47,
544 48, 48, 49, 50, 51, 52, 53, 53,
545 54, 55, 56, 57, 57, 58, 59, 60,
546 61, 62, 62, 63, 64, 65, 66, 66,
547 67, 68, 69, 70, 70, 71, 72, 73,
548 74, 74, 75, 76, 77, 78, 78, 79,
549 80, 81, 81, 82, 83, 84, 85, 85,
550 87, 88, 90, 92, 93, 95, 96, 98,
551 99, 101, 102, 104, 105, 107, 108, 110,
552 111, 113, 114, 116, 117, 118, 120, 121,
553 123, 125, 127, 129, 131, 134, 136, 138,
554 140, 142, 144, 146, 148, 150, 152, 154,
555 156, 158, 161, 164, 166, 169, 172, 174,
556 177, 180, 182, 185, 187, 190, 192, 195,
557 199, 202, 205, 208, 211, 214, 217, 220,
558 223, 226, 230, 233, 237, 240, 243, 247,
559 250, 253, 257, 261, 265, 269, 272, 276,
560 280, 284, 288, 292, 296, 300, 304, 309,
561 313, 317, 322, 326, 330, 335, 340, 344,
562 349, 354, 359, 364, 369, 374, 379, 384,
563 389, 395, 400, 406, 411, 417, 423, 429,
564 435, 441, 447, 454, 461, 467, 475, 482,
565 489, 497, 505, 513, 522, 530, 539, 549,
566 559, 569, 579, 590, 602, 614, 626, 640,
567 654, 668, 684, 700, 717, 736, 755, 775,
568 796, 819, 843, 869, 896, 925, 955, 988,
569 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
572 const int16_t kAcQLookup
[QINDEX_RANGE
] = {
573 4, 8, 9, 10, 11, 12, 13, 14,
574 15, 16, 17, 18, 19, 20, 21, 22,
575 23, 24, 25, 26, 27, 28, 29, 30,
576 31, 32, 33, 34, 35, 36, 37, 38,
577 39, 40, 41, 42, 43, 44, 45, 46,
578 47, 48, 49, 50, 51, 52, 53, 54,
579 55, 56, 57, 58, 59, 60, 61, 62,
580 63, 64, 65, 66, 67, 68, 69, 70,
581 71, 72, 73, 74, 75, 76, 77, 78,
582 79, 80, 81, 82, 83, 84, 85, 86,
583 87, 88, 89, 90, 91, 92, 93, 94,
584 95, 96, 97, 98, 99, 100, 101, 102,
585 104, 106, 108, 110, 112, 114, 116, 118,
586 120, 122, 124, 126, 128, 130, 132, 134,
587 136, 138, 140, 142, 144, 146, 148, 150,
588 152, 155, 158, 161, 164, 167, 170, 173,
589 176, 179, 182, 185, 188, 191, 194, 197,
590 200, 203, 207, 211, 215, 219, 223, 227,
591 231, 235, 239, 243, 247, 251, 255, 260,
592 265, 270, 275, 280, 285, 290, 295, 300,
593 305, 311, 317, 323, 329, 335, 341, 347,
594 353, 359, 366, 373, 380, 387, 394, 401,
595 408, 416, 424, 432, 440, 448, 456, 465,
596 474, 483, 492, 501, 510, 520, 530, 540,
597 550, 560, 571, 582, 593, 604, 615, 627,
598 639, 651, 663, 676, 689, 702, 715, 729,
599 743, 757, 771, 786, 801, 816, 832, 848,
600 864, 881, 898, 915, 933, 951, 969, 988,
601 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151,
602 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
603 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567,
604 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
607 static_assert(arraysize(kDcQLookup
) == arraysize(kAcQLookup
),
608 "quantizer lookup arrays of incorrect size");
611 std::min(std::max(static_cast<size_t>(0), q), arraysize(kDcQLookup) - 1)
613 size_t Vp9Parser::GetQIndex(const Vp9QuantizationParams
& quant
,
614 size_t segid
) const {
615 if (segmentation_
.FeatureEnabled(segid
, Vp9Segmentation::SEG_LVL_ALT_Q
)) {
616 int8_t feature_data
=
617 segmentation_
.FeatureData(segid
, Vp9Segmentation::SEG_LVL_ALT_Q
);
618 size_t q_index
= segmentation_
.abs_delta
? feature_data
619 : quant
.base_qindex
+ feature_data
;
620 return CLAMP_Q(q_index
);
623 return quant
.base_qindex
;
626 void Vp9Parser::SetupSegmentationDequant(const Vp9QuantizationParams
& quant
) {
627 if (segmentation_
.enabled
) {
628 for (size_t i
= 0; i
< Vp9Segmentation::kNumSegments
; ++i
) {
629 const size_t q_index
= GetQIndex(quant
, i
);
630 segmentation_
.y_dequant
[i
][0] =
631 kDcQLookup
[CLAMP_Q(q_index
+ quant
.y_dc_delta
)];
632 segmentation_
.y_dequant
[i
][1] = kAcQLookup
[CLAMP_Q(q_index
)];
633 segmentation_
.uv_dequant
[i
][0] =
634 kDcQLookup
[CLAMP_Q(q_index
+ quant
.uv_dc_delta
)];
635 segmentation_
.uv_dequant
[i
][1] =
636 kAcQLookup
[CLAMP_Q(q_index
+ quant
.uv_ac_delta
)];
639 const size_t q_index
= quant
.base_qindex
;
640 segmentation_
.y_dequant
[0][0] =
641 kDcQLookup
[CLAMP_Q(q_index
+ quant
.y_dc_delta
)];
642 segmentation_
.y_dequant
[0][1] = kAcQLookup
[CLAMP_Q(q_index
)];
643 segmentation_
.uv_dequant
[0][0] =
644 kDcQLookup
[CLAMP_Q(q_index
+ quant
.uv_dc_delta
)];
645 segmentation_
.uv_dequant
[0][1] =
646 kAcQLookup
[CLAMP_Q(q_index
+ quant
.uv_ac_delta
)];
651 #define CLAMP_LF(l) std::min(std::max(0, l), kMaxLoopFilterLevel)
652 void Vp9Parser::SetupLoopFilter() {
653 if (!loop_filter_
.filter_level
)
656 int scale
= loop_filter_
.filter_level
< 32 ? 1 : 2;
658 for (size_t i
= 0; i
< Vp9Segmentation::kNumSegments
; ++i
) {
659 int level
= loop_filter_
.filter_level
;
661 if (segmentation_
.FeatureEnabled(i
, Vp9Segmentation::SEG_LVL_ALT_LF
)) {
663 segmentation_
.FeatureData(i
, Vp9Segmentation::SEG_LVL_ALT_LF
);
664 level
= CLAMP_LF(segmentation_
.abs_delta
? feature_data
665 : level
+ feature_data
);
668 if (!loop_filter_
.mode_ref_delta_enabled
) {
669 memset(loop_filter_
.lvl
[i
], level
, sizeof(loop_filter_
.lvl
[i
]));
671 loop_filter_
.lvl
[i
][Vp9LoopFilter::VP9_FRAME_INTRA
][0] = CLAMP_LF(
673 loop_filter_
.ref_deltas
[Vp9LoopFilter::VP9_FRAME_INTRA
] * scale
);
674 loop_filter_
.lvl
[i
][Vp9LoopFilter::VP9_FRAME_INTRA
][1] = 0;
676 for (size_t type
= Vp9LoopFilter::VP9_FRAME_LAST
;
677 type
< Vp9LoopFilter::VP9_FRAME_MAX
; ++type
) {
678 for (size_t mode
= 0; mode
< Vp9LoopFilter::kNumModeDeltas
; ++mode
) {
679 loop_filter_
.lvl
[i
][type
][mode
] =
680 CLAMP_LF(level
+ loop_filter_
.ref_deltas
[type
] * scale
+
681 loop_filter_
.mode_deltas
[mode
] * scale
);