Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This file contains an implementation of a VP9 bitstream parser. | 5 // This file contains an implementation of a VP9 bitstream parser. |
| 6 // | |
| 7 // VERBOSE level: | |
| 8 // 1 something wrong in bitstream | |
| 9 // 2 parsing steps | |
| 10 // 3 parsed values (selected) | |
| 6 | 11 |
| 7 #include "media/filters/vp9_parser.h" | 12 #include "media/filters/vp9_parser.h" |
| 8 | 13 |
| 9 #include <algorithm> | 14 #include <algorithm> |
| 10 | 15 |
| 16 #include "base/bind.h" | |
| 11 #include "base/logging.h" | 17 #include "base/logging.h" |
| 12 #include "base/macros.h" | 18 #include "base/macros.h" |
| 13 #include "base/numerics/safe_conversions.h" | 19 #include "base/numerics/safe_conversions.h" |
| 14 | 20 #include "media/filters/vp9_compressed_header_parser.h" |
| 15 namespace { | 21 #include "media/filters/vp9_uncompressed_header_parser.h" |
| 16 | |
| 17 const int kMaxLoopFilterLevel = 63; | |
| 18 | |
| 19 // Helper function for Vp9Parser::ReadTiles. Defined as get_min_log2_tile_cols | |
| 20 // in spec. | |
| 21 int GetMinLog2TileCols(int sb64_cols) { | |
| 22 const int kMaxTileWidthB64 = 64; | |
| 23 int min_log2 = 0; | |
| 24 while ((kMaxTileWidthB64 << min_log2) < sb64_cols) | |
| 25 min_log2++; | |
| 26 return min_log2; | |
| 27 } | |
| 28 | |
| 29 // Helper function for Vp9Parser::ReadTiles. Defined as get_max_log2_tile_cols | |
| 30 // in spec. | |
| 31 int GetMaxLog2TileCols(int sb64_cols) { | |
| 32 const int kMinTileWidthB64 = 4; | |
| 33 int max_log2 = 1; | |
| 34 while ((sb64_cols >> max_log2) >= kMinTileWidthB64) | |
| 35 max_log2++; | |
| 36 return max_log2 - 1; | |
| 37 } | |
| 38 | |
| 39 } // namespace | |
| 40 | 22 |
| 41 namespace media { | 23 namespace media { |
| 42 | 24 |
| 43 bool Vp9FrameHeader::IsKeyframe() const { | 25 bool Vp9FrameHeader::IsKeyframe() const { |
| 44 // When show_existing_frame is true, the frame header does not precede an | 26 // When show_existing_frame is true, the frame header does not precede an |
| 45 // actual frame to be decoded, so frame_type does not apply (and is not read | 27 // actual frame to be decoded, so frame_type does not apply (and is not read |
| 46 // from the stream). | 28 // from the stream). |
| 47 return !show_existing_frame && frame_type == KEYFRAME; | 29 return !show_existing_frame && frame_type == KEYFRAME; |
| 48 } | 30 } |
| 49 | 31 |
| 32 bool Vp9FrameHeader::IsIntra() const { | |
| 33 return !show_existing_frame && (frame_type == KEYFRAME || intra_only); | |
| 34 } | |
| 35 | |
| 50 Vp9Parser::FrameInfo::FrameInfo(const uint8_t* ptr, off_t size) | 36 Vp9Parser::FrameInfo::FrameInfo(const uint8_t* ptr, off_t size) |
| 51 : ptr(ptr), size(size) {} | 37 : ptr(ptr), size(size) {} |
| 52 | 38 |
| 53 Vp9Parser::Vp9Parser() { | 39 Vp9FrameContextManager::Vp9FrameContextManager() |
| 40 : initialized_(false), need_update_(false), weak_ptr_factory_(this) {} | |
| 41 | |
| 42 Vp9FrameContextManager::~Vp9FrameContextManager() {} | |
| 43 | |
| 44 bool Vp9FrameContextManager::IsValidFrameContext( | |
| 45 const Vp9FrameContext& context) { | |
| 46 // probs should be in [1, 255] range. | |
| 47 static_assert(sizeof(Vp9Prob) == 1, | |
| 48 "following checks assuming Vp9Prob is single byte"); | |
| 49 if (memchr(context.tx_probs_8x8, 0, sizeof(context.tx_probs_8x8))) | |
| 50 return false; | |
| 51 if (memchr(context.tx_probs_16x16, 0, sizeof(context.tx_probs_16x16))) | |
| 52 return false; | |
| 53 if (memchr(context.tx_probs_32x32, 0, sizeof(context.tx_probs_32x32))) | |
| 54 return false; | |
| 55 | |
| 56 for (auto& a : context.coef_probs) { | |
| 57 for (auto& ai : a) { | |
| 58 for (auto& aj : ai) { | |
| 59 for (auto& ak : aj) { | |
| 60 int max_l = (ak == aj[0]) ? 3 : 6; | |
| 61 for (int l = 0; l < max_l; l++) { | |
| 62 for (auto& x : ak[l]) { | |
| 63 if (x == 0) | |
| 64 return false; | |
| 65 } | |
| 66 } | |
| 67 } | |
| 68 } | |
| 69 } | |
| 70 } | |
| 71 if (memchr(context.skip_prob, 0, sizeof(context.skip_prob))) | |
| 72 return false; | |
| 73 if (memchr(context.inter_mode_probs, 0, sizeof(context.inter_mode_probs))) | |
| 74 return false; | |
| 75 if (memchr(context.interp_filter_probs, 0, | |
| 76 sizeof(context.interp_filter_probs))) | |
| 77 return false; | |
| 78 if (memchr(context.is_inter_prob, 0, sizeof(context.is_inter_prob))) | |
| 79 return false; | |
| 80 if (memchr(context.comp_mode_prob, 0, sizeof(context.comp_mode_prob))) | |
| 81 return false; | |
| 82 if (memchr(context.single_ref_prob, 0, sizeof(context.single_ref_prob))) | |
| 83 return false; | |
| 84 if (memchr(context.comp_ref_prob, 0, sizeof(context.comp_ref_prob))) | |
| 85 return false; | |
| 86 if (memchr(context.y_mode_probs, 0, sizeof(context.y_mode_probs))) | |
| 87 return false; | |
| 88 if (memchr(context.uv_mode_probs, 0, sizeof(context.uv_mode_probs))) | |
| 89 return false; | |
| 90 if (memchr(context.partition_probs, 0, sizeof(context.partition_probs))) | |
| 91 return false; | |
| 92 if (memchr(context.mv_joint_probs, 0, sizeof(context.mv_joint_probs))) | |
| 93 return false; | |
| 94 if (memchr(context.mv_sign_prob, 0, sizeof(context.mv_sign_prob))) | |
| 95 return false; | |
| 96 if (memchr(context.mv_class_probs, 0, sizeof(context.mv_class_probs))) | |
| 97 return false; | |
| 98 if (memchr(context.mv_class0_bit_prob, 0, sizeof(context.mv_class0_bit_prob))) | |
| 99 return false; | |
| 100 if (memchr(context.mv_bits_prob, 0, sizeof(context.mv_bits_prob))) | |
| 101 return false; | |
| 102 if (memchr(context.mv_class0_fr_probs, 0, sizeof(context.mv_class0_fr_probs))) | |
| 103 return false; | |
| 104 if (memchr(context.mv_fr_probs, 0, sizeof(context.mv_fr_probs))) | |
| 105 return false; | |
| 106 if (memchr(context.mv_class0_hp_prob, 0, sizeof(context.mv_class0_hp_prob))) | |
| 107 return false; | |
| 108 if (memchr(context.mv_hp_prob, 0, sizeof(context.mv_hp_prob))) | |
| 109 return false; | |
| 110 | |
| 111 return true; | |
| 112 } | |
| 113 | |
| 114 const Vp9FrameContext& Vp9FrameContextManager::frame_context() const { | |
| 115 DCHECK(initialized_); | |
| 116 DCHECK(!need_update_); | |
| 117 return frame_context_; | |
| 118 } | |
| 119 | |
| 120 void Vp9FrameContextManager::Reset() { | |
| 121 initialized_ = false; | |
| 122 need_update_ = false; | |
| 123 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 124 } | |
| 125 | |
| 126 Vp9FrameContextManager::ContextRefreshCallback | |
| 127 Vp9FrameContextManager::SetNeedUpdate() { | |
| 128 DCHECK(!need_update_); | |
| 129 initialized_ = true; | |
| 130 need_update_ = true; | |
| 131 | |
| 132 return base::Bind(&Vp9FrameContextManager::Update, | |
| 133 weak_ptr_factory_.GetWeakPtr()); | |
| 134 } | |
| 135 | |
| 136 void Vp9FrameContextManager::Update(const Vp9FrameContext& frame_context) { | |
| 137 if (need_update_) { | |
| 138 DVLOG(2) << "Got external frame_context update"; | |
| 139 // Verify values from driver explicitly. | |
| 140 if (!IsValidFrameContext(frame_context)) { | |
| 141 DLOG(ERROR) << "Invalid prob value in frame_context"; | |
| 142 return; | |
| 143 } | |
| 144 } else { | |
| 145 DCHECK(IsValidFrameContext(frame_context)); | |
| 146 } | |
| 147 need_update_ = false; | |
| 148 initialized_ = true; | |
| 149 frame_context_ = frame_context; | |
| 150 | |
| 151 // For frame context we are updating, it may be still awaiting previous | |
| 152 // ContextRefreshCallback. Because we overwrite the value of context here and | |
| 153 // previous ContextRefreshCallback no longer matters, invalidate the weak ptr | |
| 154 // to prevent previous ContextRefreshCallback run. | |
| 155 // With this optimization, we may be able to parse more frames while previous | |
| 156 // are still decoding. | |
| 157 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 158 } | |
| 159 | |
| 160 void Vp9Parser::Context::Reset() { | |
| 161 memset(&segmentation, 0, sizeof(segmentation)); | |
| 162 memset(&loop_filter, 0, sizeof(loop_filter)); | |
| 163 memset(&ref_slots, 0, sizeof(ref_slots)); | |
| 164 for (auto& manager : frame_context_managers) | |
| 165 manager.Reset(); | |
| 166 } | |
| 167 | |
| 168 Vp9Parser::Vp9Parser(bool parsing_compressed_header) | |
| 169 : parsing_compressed_header_(parsing_compressed_header) { | |
| 54 Reset(); | 170 Reset(); |
| 55 } | 171 } |
| 56 | 172 |
| 57 Vp9Parser::~Vp9Parser() {} | 173 Vp9Parser::~Vp9Parser() {} |
| 58 | 174 |
| 59 void Vp9Parser::SetStream(const uint8_t* stream, off_t stream_size) { | 175 void Vp9Parser::SetStream(const uint8_t* stream, off_t stream_size) { |
| 60 DCHECK(stream); | 176 DCHECK(stream); |
| 61 stream_ = stream; | 177 stream_ = stream; |
| 62 bytes_left_ = stream_size; | 178 bytes_left_ = stream_size; |
| 63 frames_.clear(); | 179 frames_.clear(); |
| 64 } | 180 } |
| 65 | 181 |
| 66 void Vp9Parser::Reset() { | 182 void Vp9Parser::Reset() { |
| 67 stream_ = nullptr; | 183 stream_ = nullptr; |
| 68 bytes_left_ = 0; | 184 bytes_left_ = 0; |
| 69 frames_.clear(); | 185 frames_.clear(); |
| 70 | 186 |
| 71 memset(&segmentation_, 0, sizeof(segmentation_)); | 187 context_.Reset(); |
| 72 memset(&loop_filter_, 0, sizeof(loop_filter_)); | 188 } |
| 73 memset(&ref_slots_, 0, sizeof(ref_slots_)); | 189 |
| 74 } | 190 Vp9Parser::Result Vp9Parser::ParseNextFrame( |
| 75 | 191 Vp9FrameHeader* fhdr, |
| 76 uint8_t Vp9Parser::ReadProfile() { | 192 base::Callback<void(const Vp9FrameContext&)>* context_refresh_cb) { |
| 77 uint8_t profile = 0; | 193 DCHECK(fhdr); |
| 78 | 194 DCHECK(!parsing_compressed_header_ || context_refresh_cb); |
| 79 // LSB first. | 195 DVLOG(2) << "ParseNextFrame"; |
| 80 if (reader_.ReadBool()) | 196 |
| 81 profile |= 1; | 197 // If |curr_frame_info_| is valid, uncompressed header was parsed into |
| 82 if (reader_.ReadBool()) | 198 // |curr_frame_header_| and awaiting context update. |
|
Pawel Osciak
2016/08/05 10:09:39
"and we are awaiting context update to proceed wit
kcwu
2016/08/05 11:38:48
Done.
| |
| 83 profile |= 2; | 199 if (!curr_frame_info_.IsValid()) { |
| 84 if (profile > 2 && reader_.ReadBool()) | 200 if (frames_.empty()) { |
| 85 profile += 1; | 201 // No frames to be decoded, if there is no more stream, request more. |
| 86 return profile; | 202 if (!stream_) |
| 87 } | 203 return kEOStream; |
| 88 | 204 |
| 89 bool Vp9Parser::VerifySyncCode() { | 205 // New stream to be parsed, parse it and fill frames_. |
| 90 const int kSyncCode = 0x498342; | 206 if (!ParseSuperframe()) { |
| 91 if (reader_.ReadLiteral(8 * 3) != kSyncCode) { | 207 DVLOG(1) << "Failed parsing superframes"; |
| 92 DVLOG(1) << "Invalid frame sync code"; | 208 return kInvalidStream; |
| 93 return false; | 209 } |
| 94 } | 210 } |
| 95 return true; | 211 |
| 96 } | 212 DCHECK(!frames_.empty()); |
|
Pawel Osciak
2016/08/05 10:09:39
Perhaps we could use frames_.empty() instead of re
kcwu
2016/08/05 11:38:48
I make ParseSuperFrame() return std::deque.
| |
| 97 | 213 |
| 98 bool Vp9Parser::ReadBitDepthColorSpaceSampling(Vp9FrameHeader* fhdr) { | 214 curr_frame_info_ = frames_.front(); |
| 99 if (fhdr->profile == 2 || fhdr->profile == 3) { | 215 frames_.pop_front(); |
| 100 fhdr->bit_depth = reader_.ReadBool() ? 12 : 10; | 216 |
| 101 } else { | 217 memset(&curr_frame_header_, 0, sizeof(curr_frame_header_)); |
| 102 fhdr->bit_depth = 8; | 218 |
| 103 } | 219 Vp9UncompressedHeaderParser uncompressed_parser(&context_); |
| 104 | 220 if (!uncompressed_parser.Parse(curr_frame_info_.ptr, curr_frame_info_.size, |
| 105 fhdr->color_space = static_cast<Vp9ColorSpace>(reader_.ReadLiteral(3)); | 221 &curr_frame_header_)) |
| 106 if (fhdr->color_space != Vp9ColorSpace::SRGB) { | 222 return kInvalidStream; |
| 107 fhdr->yuv_range = reader_.ReadBool(); | 223 |
| 108 if (fhdr->profile == 1 || fhdr->profile == 3) { | 224 if (curr_frame_header_.header_size_in_bytes == 0) { |
| 109 fhdr->subsampling_x = reader_.ReadBool() ? 1 : 0; | 225 // Verify padding bits are zero. |
| 110 fhdr->subsampling_y = reader_.ReadBool() ? 1 : 0; | 226 for (int i = curr_frame_header_.uncompressed_header_size; |
| 111 if (fhdr->subsampling_x == 1 && fhdr->subsampling_y == 1) { | 227 i < curr_frame_info_.size; i++) { |
| 112 DVLOG(1) << "4:2:0 color not supported in profile 1 or 3"; | 228 if (curr_frame_info_.ptr[i] != 0) { |
| 113 return false; | 229 DVLOG(1) << "Padding bits are not zeros."; |
| 114 } | 230 return kInvalidStream; |
| 115 bool reserved = reader_.ReadBool(); | 231 } |
| 116 if (reserved) { | 232 } |
| 117 DVLOG(1) << "reserved bit set"; | 233 *fhdr = curr_frame_header_; |
| 118 return false; | 234 curr_frame_info_.Reset(); |
| 119 } | 235 return kOk; |
| 120 } else { | 236 } |
| 121 fhdr->subsampling_x = fhdr->subsampling_y = 1; | 237 if (curr_frame_header_.uncompressed_header_size + |
| 122 } | 238 curr_frame_header_.header_size_in_bytes > |
| 123 } else { | 239 static_cast<size_t>(curr_frame_info_.size)) { |
|
Pawel Osciak
2016/08/05 10:09:39
Perhaps checked cast?
kcwu
2016/08/05 11:38:48
Done.
| |
| 124 if (fhdr->profile == 1 || fhdr->profile == 3) { | 240 DVLOG(1) << "header_size_in_bytes=" |
| 125 fhdr->subsampling_x = fhdr->subsampling_y = 0; | 241 << curr_frame_header_.header_size_in_bytes |
| 126 | 242 << " is larger than bytes left in buffer: " |
| 127 bool reserved = reader_.ReadBool(); | 243 << curr_frame_info_.size - |
| 128 if (reserved) { | 244 curr_frame_header_.uncompressed_header_size; |
| 129 DVLOG(1) << "reserved bit set"; | 245 return kInvalidStream; |
| 130 return false; | 246 } |
| 131 } | 247 } |
| 132 } else { | 248 |
| 133 DVLOG(1) << "4:4:4 color not supported in profile 0 or 2"; | 249 if (parsing_compressed_header_) { |
| 134 return false; | 250 Vp9FrameContextManager& context_to_load = |
| 135 } | 251 context_.frame_context_managers[curr_frame_header_.frame_context_idx]; |
| 136 } | 252 if (!context_to_load.initialized()) { |
| 137 | 253 // 8.2 Frame order constraints |
| 138 return true; | 254 // must load an initialized set of probabilities. |
| 139 } | 255 DVLOG(1) << "loading uninitialized frame context, index=" |
| 140 | 256 << curr_frame_header_.frame_context_idx; |
| 141 void Vp9Parser::ReadFrameSize(Vp9FrameHeader* fhdr) { | 257 return kInvalidStream; |
| 142 fhdr->width = reader_.ReadLiteral(16) + 1; | 258 } |
| 143 fhdr->height = reader_.ReadLiteral(16) + 1; | 259 if (context_to_load.need_update()) { |
| 144 } | 260 DVLOG(3) << "waiting frame_context_idx=" |
| 145 | 261 << static_cast<int>(curr_frame_header_.frame_context_idx) |
| 146 bool Vp9Parser::ReadFrameSizeFromRefs(Vp9FrameHeader* fhdr) { | 262 << " to update"; |
| 147 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | 263 return kAwaitingRefresh; |
| 148 if (reader_.ReadBool()) { | 264 } |
| 149 fhdr->width = ref_slots_[i].width; | 265 curr_frame_header_.initial_frame_context = |
| 150 fhdr->height = ref_slots_[i].height; | 266 curr_frame_header_.frame_context = context_to_load.frame_context(); |
| 151 | 267 |
| 152 const int kMaxDimension = 1 << 16; | 268 Vp9CompressedHeaderParser compressed_parser; |
| 153 if (fhdr->width == 0 || fhdr->width > kMaxDimension || | 269 if (!compressed_parser.Parse( |
| 154 fhdr->height == 0 || fhdr->height > kMaxDimension) { | 270 curr_frame_info_.ptr + curr_frame_header_.uncompressed_header_size, |
| 155 DVLOG(1) << "The size of reference frame is out of range: " | 271 curr_frame_header_.header_size_in_bytes, &curr_frame_header_)) { |
| 156 << ref_slots_[i].width << "," << ref_slots_[i].height; | 272 return kInvalidStream; |
| 157 return false; | 273 } |
| 158 } | 274 |
| 159 return true; | 275 if (curr_frame_header_.refresh_frame_context) { |
| 160 } | 276 Vp9FrameContextManager& frame_context_manager = |
| 161 } | 277 context_.frame_context_managers[curr_frame_header_.frame_context_idx]; |
| 162 | 278 |
| 163 fhdr->width = reader_.ReadLiteral(16) + 1; | 279 // In frame parallel mode, we can refresh the context without decoding |
| 164 fhdr->height = reader_.ReadLiteral(16) + 1; | 280 // tile data. |
| 165 return true; | 281 if (curr_frame_header_.frame_parallel_decoding_mode) { |
| 166 } | 282 frame_context_manager.Update(curr_frame_header_.frame_context); |
| 167 | |
| 168 void Vp9Parser::ReadDisplayFrameSize(Vp9FrameHeader* fhdr) { | |
| 169 if (reader_.ReadBool()) { | |
| 170 fhdr->display_width = reader_.ReadLiteral(16) + 1; | |
| 171 fhdr->display_height = reader_.ReadLiteral(16) + 1; | |
| 172 } else { | |
| 173 fhdr->display_width = fhdr->width; | |
| 174 fhdr->display_height = fhdr->height; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 Vp9InterpFilter Vp9Parser::ReadInterpFilter() { | |
| 179 if (reader_.ReadBool()) | |
| 180 return Vp9InterpFilter::SWICHABLE; | |
| 181 | |
| 182 // The mapping table for next two bits. | |
| 183 const Vp9InterpFilter table[] = { | |
| 184 Vp9InterpFilter::EIGHTTAP_SMOOTH, Vp9InterpFilter::EIGHTTAP, | |
| 185 Vp9InterpFilter::EIGHTTAP_SHARP, Vp9InterpFilter::BILINEAR, | |
| 186 }; | |
| 187 return table[reader_.ReadLiteral(2)]; | |
| 188 } | |
| 189 | |
| 190 void Vp9Parser::ReadLoopFilter() { | |
| 191 loop_filter_.filter_level = reader_.ReadLiteral(6); | |
| 192 loop_filter_.sharpness_level = reader_.ReadLiteral(3); | |
| 193 loop_filter_.mode_ref_delta_update = false; | |
| 194 | |
| 195 loop_filter_.mode_ref_delta_enabled = reader_.ReadBool(); | |
| 196 if (loop_filter_.mode_ref_delta_enabled) { | |
| 197 loop_filter_.mode_ref_delta_update = reader_.ReadBool(); | |
| 198 if (loop_filter_.mode_ref_delta_update) { | |
| 199 for (size_t i = 0; i < Vp9LoopFilter::VP9_FRAME_MAX; i++) { | |
| 200 loop_filter_.update_ref_deltas[i] = reader_.ReadBool(); | |
| 201 if (loop_filter_.update_ref_deltas[i]) | |
| 202 loop_filter_.ref_deltas[i] = reader_.ReadSignedLiteral(6); | |
| 203 } | |
| 204 | |
| 205 for (size_t i = 0; i < Vp9LoopFilter::kNumModeDeltas; i++) { | |
| 206 loop_filter_.update_mode_deltas[i] = reader_.ReadBool(); | |
| 207 if (loop_filter_.update_mode_deltas[i]) | |
| 208 loop_filter_.mode_deltas[i] = reader_.ReadLiteral(6); | |
| 209 } | |
| 210 } | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 void Vp9Parser::ReadQuantization(Vp9QuantizationParams* quants) { | |
| 215 quants->base_qindex = reader_.ReadLiteral(8); | |
| 216 | |
| 217 if (reader_.ReadBool()) | |
| 218 quants->y_dc_delta = reader_.ReadSignedLiteral(4); | |
| 219 | |
| 220 if (reader_.ReadBool()) | |
| 221 quants->uv_dc_delta = reader_.ReadSignedLiteral(4); | |
| 222 | |
| 223 if (reader_.ReadBool()) | |
| 224 quants->uv_ac_delta = reader_.ReadSignedLiteral(4); | |
| 225 } | |
| 226 | |
| 227 void Vp9Parser::ReadSegmentationMap() { | |
| 228 for (size_t i = 0; i < Vp9Segmentation::kNumTreeProbs; i++) { | |
| 229 segmentation_.tree_probs[i] = | |
| 230 reader_.ReadBool() ? reader_.ReadLiteral(8) : kVp9MaxProb; | |
| 231 } | |
| 232 | |
| 233 for (size_t i = 0; i < Vp9Segmentation::kNumPredictionProbs; i++) | |
| 234 segmentation_.pred_probs[i] = kVp9MaxProb; | |
| 235 | |
| 236 segmentation_.temporal_update = reader_.ReadBool(); | |
| 237 if (segmentation_.temporal_update) { | |
| 238 for (size_t i = 0; i < Vp9Segmentation::kNumPredictionProbs; i++) { | |
| 239 if (reader_.ReadBool()) | |
| 240 segmentation_.pred_probs[i] = reader_.ReadLiteral(8); | |
| 241 } | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 void Vp9Parser::ReadSegmentationData() { | |
| 246 segmentation_.abs_delta = reader_.ReadBool(); | |
| 247 | |
| 248 const int kFeatureDataBits[] = {8, 6, 2, 0}; | |
| 249 const bool kFeatureDataSigned[] = {true, true, false, false}; | |
| 250 | |
| 251 for (size_t i = 0; i < Vp9Segmentation::kNumSegments; i++) { | |
| 252 for (size_t j = 0; j < Vp9Segmentation::SEG_LVL_MAX; j++) { | |
| 253 int16_t data = 0; | |
| 254 segmentation_.feature_enabled[i][j] = reader_.ReadBool(); | |
| 255 if (segmentation_.feature_enabled[i][j]) { | |
| 256 data = reader_.ReadLiteral(kFeatureDataBits[j]); | |
| 257 if (kFeatureDataSigned[j]) | |
| 258 if (reader_.ReadBool()) | |
| 259 data = -data; | |
| 260 } | |
| 261 segmentation_.feature_data[i][j] = data; | |
| 262 } | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 void Vp9Parser::ReadSegmentation() { | |
| 267 segmentation_.update_map = false; | |
| 268 segmentation_.update_data = false; | |
| 269 | |
| 270 segmentation_.enabled = reader_.ReadBool(); | |
| 271 if (!segmentation_.enabled) | |
| 272 return; | |
| 273 | |
| 274 segmentation_.update_map = reader_.ReadBool(); | |
| 275 if (segmentation_.update_map) | |
| 276 ReadSegmentationMap(); | |
| 277 | |
| 278 segmentation_.update_data = reader_.ReadBool(); | |
| 279 if (segmentation_.update_data) | |
| 280 ReadSegmentationData(); | |
| 281 } | |
| 282 | |
| 283 void Vp9Parser::ReadTiles(Vp9FrameHeader* fhdr) { | |
| 284 int sb64_cols = (fhdr->width + 63) / 64; | |
| 285 | |
| 286 int min_log2_tile_cols = GetMinLog2TileCols(sb64_cols); | |
| 287 int max_log2_tile_cols = GetMaxLog2TileCols(sb64_cols); | |
| 288 | |
| 289 int max_ones = max_log2_tile_cols - min_log2_tile_cols; | |
| 290 fhdr->log2_tile_cols = min_log2_tile_cols; | |
| 291 while (max_ones-- && reader_.ReadBool()) | |
| 292 fhdr->log2_tile_cols++; | |
| 293 | |
| 294 fhdr->log2_tile_rows = reader_.ReadBool() ? 1 : 0; | |
| 295 if (fhdr->log2_tile_rows > 0 && reader_.ReadBool()) | |
| 296 fhdr->log2_tile_rows++; | |
| 297 } | |
| 298 | |
| 299 bool Vp9Parser::ParseUncompressedHeader(const uint8_t* stream, | |
| 300 off_t frame_size, | |
| 301 Vp9FrameHeader* fhdr) { | |
| 302 reader_.Initialize(stream, frame_size); | |
| 303 | |
| 304 fhdr->data = stream; | |
| 305 fhdr->frame_size = frame_size; | |
| 306 | |
| 307 // frame marker | |
| 308 if (reader_.ReadLiteral(2) != 0x2) | |
| 309 return false; | |
| 310 | |
| 311 fhdr->profile = ReadProfile(); | |
| 312 if (fhdr->profile >= kVp9MaxProfile) { | |
| 313 DVLOG(1) << "Unsupported bitstream profile"; | |
| 314 return false; | |
| 315 } | |
| 316 | |
| 317 fhdr->show_existing_frame = reader_.ReadBool(); | |
| 318 if (fhdr->show_existing_frame) { | |
| 319 fhdr->frame_to_show = reader_.ReadLiteral(3); | |
| 320 fhdr->show_frame = true; | |
| 321 | |
| 322 if (!reader_.IsValid()) { | |
| 323 DVLOG(1) << "parser reads beyond the end of buffer"; | |
| 324 return false; | |
| 325 } | |
| 326 fhdr->uncompressed_header_size = reader_.GetBytesRead(); | |
| 327 return true; | |
| 328 } | |
| 329 | |
| 330 fhdr->frame_type = static_cast<Vp9FrameHeader::FrameType>(reader_.ReadBool()); | |
| 331 fhdr->show_frame = reader_.ReadBool(); | |
| 332 fhdr->error_resilient_mode = reader_.ReadBool(); | |
| 333 | |
| 334 if (fhdr->IsKeyframe()) { | |
| 335 if (!VerifySyncCode()) | |
| 336 return false; | |
| 337 | |
| 338 if (!ReadBitDepthColorSpaceSampling(fhdr)) | |
| 339 return false; | |
| 340 | |
| 341 fhdr->refresh_flags = 0xff; | |
| 342 | |
| 343 ReadFrameSize(fhdr); | |
| 344 ReadDisplayFrameSize(fhdr); | |
| 345 } else { | |
| 346 if (!fhdr->show_frame) | |
| 347 fhdr->intra_only = reader_.ReadBool(); | |
| 348 | |
| 349 if (!fhdr->error_resilient_mode) | |
| 350 fhdr->reset_context = reader_.ReadLiteral(2); | |
| 351 | |
| 352 if (fhdr->intra_only) { | |
| 353 if (!VerifySyncCode()) | |
| 354 return false; | |
| 355 | |
| 356 if (fhdr->profile > 0) { | |
| 357 if (!ReadBitDepthColorSpaceSampling(fhdr)) | |
| 358 return false; | |
| 359 } else { | 283 } else { |
| 360 fhdr->bit_depth = 8; | 284 *context_refresh_cb = frame_context_manager.SetNeedUpdate(); |
| 361 fhdr->color_space = Vp9ColorSpace::BT_601; | 285 } |
| 362 fhdr->subsampling_x = fhdr->subsampling_y = 1; | 286 } |
| 363 } | 287 } |
| 364 | 288 |
| 365 fhdr->refresh_flags = reader_.ReadLiteral(8); | 289 SetupSegmentationDequant(); |
| 366 | |
| 367 ReadFrameSize(fhdr); | |
| 368 ReadDisplayFrameSize(fhdr); | |
| 369 } else { | |
| 370 fhdr->refresh_flags = reader_.ReadLiteral(8); | |
| 371 | |
| 372 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | |
| 373 fhdr->frame_refs[i] = reader_.ReadLiteral(kVp9NumRefFramesLog2); | |
| 374 fhdr->ref_sign_biases[i] = reader_.ReadBool(); | |
| 375 } | |
| 376 | |
| 377 if (!ReadFrameSizeFromRefs(fhdr)) | |
| 378 return false; | |
| 379 ReadDisplayFrameSize(fhdr); | |
| 380 | |
| 381 fhdr->allow_high_precision_mv = reader_.ReadBool(); | |
| 382 fhdr->interp_filter = ReadInterpFilter(); | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 if (fhdr->error_resilient_mode) { | |
| 387 fhdr->frame_parallel_decoding_mode = true; | |
| 388 } else { | |
| 389 fhdr->refresh_frame_context = reader_.ReadBool(); | |
| 390 fhdr->frame_parallel_decoding_mode = reader_.ReadBool(); | |
| 391 } | |
| 392 | |
| 393 fhdr->frame_context_idx = reader_.ReadLiteral(2); | |
| 394 | |
| 395 if (fhdr->IsKeyframe() || fhdr->intra_only) | |
| 396 SetupPastIndependence(); | |
| 397 | |
| 398 ReadLoopFilter(); | |
| 399 ReadQuantization(&fhdr->quant_params); | |
| 400 ReadSegmentation(); | |
| 401 | |
| 402 ReadTiles(fhdr); | |
| 403 | |
| 404 fhdr->first_partition_size = reader_.ReadLiteral(16); | |
| 405 if (fhdr->first_partition_size == 0) { | |
| 406 DVLOG(1) << "invalid header size"; | |
| 407 return false; | |
| 408 } | |
| 409 | |
| 410 if (!reader_.IsValid()) { | |
| 411 DVLOG(1) << "parser reads beyond the end of buffer"; | |
| 412 return false; | |
| 413 } | |
| 414 fhdr->uncompressed_header_size = reader_.GetBytesRead(); | |
| 415 | |
| 416 SetupSegmentationDequant(fhdr->quant_params); | |
| 417 SetupLoopFilter(); | 290 SetupLoopFilter(); |
| 418 | 291 UpdateSlots(); |
| 419 UpdateSlots(fhdr); | 292 |
| 420 | 293 *fhdr = curr_frame_header_; |
| 421 return true; | 294 curr_frame_info_.Reset(); |
| 422 } | |
| 423 | |
| 424 void Vp9Parser::UpdateSlots(const Vp9FrameHeader* fhdr) { | |
| 425 for (size_t i = 0; i < kVp9NumRefFrames; i++) { | |
| 426 if (fhdr->RefreshFlag(i)) { | |
| 427 ref_slots_[i].width = fhdr->width; | |
| 428 ref_slots_[i].height = fhdr->height; | |
| 429 } | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 Vp9Parser::Result Vp9Parser::ParseNextFrame(Vp9FrameHeader* fhdr) { | |
| 434 if (frames_.empty()) { | |
| 435 // No frames to be decoded, if there is no more stream, request more. | |
| 436 if (!stream_) | |
| 437 return kEOStream; | |
| 438 | |
| 439 // New stream to be parsed, parse it and fill frames_. | |
| 440 if (!ParseSuperframe()) { | |
| 441 DVLOG(1) << "Failed parsing superframes"; | |
| 442 return kInvalidStream; | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 DCHECK(!frames_.empty()); | |
| 447 FrameInfo frame_info = frames_.front(); | |
| 448 frames_.pop_front(); | |
| 449 | |
| 450 memset(fhdr, 0, sizeof(*fhdr)); | |
| 451 if (!ParseUncompressedHeader(frame_info.ptr, frame_info.size, fhdr)) | |
| 452 return kInvalidStream; | |
| 453 | |
| 454 return kOk; | 295 return kOk; |
| 455 } | 296 } |
| 456 | 297 |
| 298 // Annex B Superframes | |
| 457 bool Vp9Parser::ParseSuperframe() { | 299 bool Vp9Parser::ParseSuperframe() { |
| 458 const uint8_t* stream = stream_; | 300 const uint8_t* stream = stream_; |
| 459 off_t bytes_left = bytes_left_; | 301 off_t bytes_left = bytes_left_; |
| 460 | 302 |
| 461 DCHECK(frames_.empty()); | 303 DCHECK(frames_.empty()); |
| 462 | 304 |
| 463 // Make sure we don't parse stream_ more than once. | 305 // Make sure we don't parse stream_ more than once. |
| 464 stream_ = nullptr; | 306 stream_ = nullptr; |
| 465 bytes_left_ = 0; | 307 bytes_left_ = 0; |
| 466 | 308 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 511 frames_.push_back(FrameInfo(stream, size)); | 353 frames_.push_back(FrameInfo(stream, size)); |
| 512 stream += size; | 354 stream += size; |
| 513 bytes_left -= size; | 355 bytes_left -= size; |
| 514 | 356 |
| 515 DVLOG(1) << "Frame " << i << ", size: " << size; | 357 DVLOG(1) << "Frame " << i << ", size: " << size; |
| 516 } | 358 } |
| 517 | 359 |
| 518 return true; | 360 return true; |
| 519 } | 361 } |
| 520 | 362 |
| 521 void Vp9Parser::ResetLoopfilter() { | 363 // 8.6.1 |
| 522 loop_filter_.mode_ref_delta_enabled = true; | |
| 523 loop_filter_.mode_ref_delta_update = true; | |
| 524 | |
| 525 const int8_t default_ref_deltas[] = {1, 0, -1, -1}; | |
| 526 static_assert( | |
| 527 arraysize(default_ref_deltas) == arraysize(loop_filter_.ref_deltas), | |
| 528 "ref_deltas arrays of incorrect size"); | |
| 529 for (size_t i = 0; i < arraysize(loop_filter_.ref_deltas); ++i) | |
| 530 loop_filter_.ref_deltas[i] = default_ref_deltas[i]; | |
| 531 | |
| 532 memset(loop_filter_.mode_deltas, 0, sizeof(loop_filter_.mode_deltas)); | |
| 533 } | |
| 534 | |
| 535 void Vp9Parser::SetupPastIndependence() { | |
| 536 memset(&segmentation_, 0, sizeof(segmentation_)); | |
| 537 ResetLoopfilter(); | |
| 538 } | |
| 539 | |
| 540 const size_t QINDEX_RANGE = 256; | 364 const size_t QINDEX_RANGE = 256; |
| 541 const int16_t kDcQLookup[QINDEX_RANGE] = { | 365 const int16_t kDcQLookup[QINDEX_RANGE] = { |
| 542 4, 8, 8, 9, 10, 11, 12, 12, | 366 4, 8, 8, 9, 10, 11, 12, 12, |
| 543 13, 14, 15, 16, 17, 18, 19, 19, | 367 13, 14, 15, 16, 17, 18, 19, 19, |
| 544 20, 21, 22, 23, 24, 25, 26, 26, | 368 20, 21, 22, 23, 24, 25, 26, 26, |
| 545 27, 28, 29, 30, 31, 32, 32, 33, | 369 27, 28, 29, 30, 31, 32, 32, 33, |
| 546 34, 35, 36, 37, 38, 38, 39, 40, | 370 34, 35, 36, 37, 38, 38, 39, 40, |
| 547 41, 42, 43, 43, 44, 45, 46, 47, | 371 41, 42, 43, 43, 44, 45, 46, 47, |
| 548 48, 48, 49, 50, 51, 52, 53, 53, | 372 48, 48, 49, 50, 51, 52, 53, 53, |
| 549 54, 55, 56, 57, 57, 58, 59, 60, | 373 54, 55, 56, 57, 57, 58, 59, 60, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 604 864, 881, 898, 915, 933, 951, 969, 988, | 428 864, 881, 898, 915, 933, 951, 969, 988, |
| 605 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, | 429 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151, |
| 606 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, | 430 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343, |
| 607 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567, | 431 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567, |
| 608 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828, | 432 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828, |
| 609 }; | 433 }; |
| 610 | 434 |
| 611 static_assert(arraysize(kDcQLookup) == arraysize(kAcQLookup), | 435 static_assert(arraysize(kDcQLookup) == arraysize(kAcQLookup), |
| 612 "quantizer lookup arrays of incorrect size"); | 436 "quantizer lookup arrays of incorrect size"); |
| 613 | 437 |
| 614 #define CLAMP_Q(q) \ | 438 static size_t ClampQ(size_t q) { |
| 615 std::min(std::max(static_cast<size_t>(0), q), arraysize(kDcQLookup) - 1) | 439 return std::min(std::max(static_cast<size_t>(0), q), |
| 440 arraysize(kDcQLookup) - 1); | |
| 441 } | |
| 616 | 442 |
| 443 // 8.6.1 Dequantization functions | |
| 617 size_t Vp9Parser::GetQIndex(const Vp9QuantizationParams& quant, | 444 size_t Vp9Parser::GetQIndex(const Vp9QuantizationParams& quant, |
| 618 size_t segid) const { | 445 size_t segid) const { |
| 619 if (segmentation_.FeatureEnabled(segid, Vp9Segmentation::SEG_LVL_ALT_Q)) { | 446 const Vp9SegmentationParams& segmentation = context_.segmentation; |
| 447 | |
| 448 if (segmentation.FeatureEnabled(segid, | |
| 449 Vp9SegmentationParams::SEG_LVL_ALT_Q)) { | |
| 620 int16_t feature_data = | 450 int16_t feature_data = |
| 621 segmentation_.FeatureData(segid, Vp9Segmentation::SEG_LVL_ALT_Q); | 451 segmentation.FeatureData(segid, Vp9SegmentationParams::SEG_LVL_ALT_Q); |
| 622 size_t q_index = segmentation_.abs_delta ? feature_data | 452 size_t q_index = segmentation.abs_or_delta_update |
| 623 : quant.base_qindex + feature_data; | 453 ? feature_data |
| 624 return CLAMP_Q(q_index); | 454 : quant.base_q_idx + feature_data; |
| 455 return ClampQ(q_index); | |
| 625 } | 456 } |
| 626 | 457 |
| 627 return quant.base_qindex; | 458 return quant.base_q_idx; |
| 628 } | 459 } |
| 629 | 460 |
| 630 void Vp9Parser::SetupSegmentationDequant(const Vp9QuantizationParams& quant) { | 461 // 8.6.1 Dequantization functions |
| 631 if (segmentation_.enabled) { | 462 void Vp9Parser::SetupSegmentationDequant() { |
| 632 for (size_t i = 0; i < Vp9Segmentation::kNumSegments; ++i) { | 463 const Vp9QuantizationParams& quant = curr_frame_header_.quant_params; |
| 464 Vp9SegmentationParams& segmentation = context_.segmentation; | |
| 465 | |
| 466 DLOG_IF(ERROR, curr_frame_header_.bit_depth > 8) | |
| 467 << "bit_depth > 8 is not supported " | |
| 468 "yet, kDcQLookup and kAcQLookup " | |
| 469 "need extended"; | |
| 470 if (segmentation.enabled) { | |
| 471 for (size_t i = 0; i < Vp9SegmentationParams::kNumSegments; ++i) { | |
| 633 const size_t q_index = GetQIndex(quant, i); | 472 const size_t q_index = GetQIndex(quant, i); |
| 634 segmentation_.y_dequant[i][0] = | 473 segmentation.y_dequant[i][0] = |
| 635 kDcQLookup[CLAMP_Q(q_index + quant.y_dc_delta)]; | 474 kDcQLookup[ClampQ(q_index + quant.delta_q_y_dc)]; |
| 636 segmentation_.y_dequant[i][1] = kAcQLookup[CLAMP_Q(q_index)]; | 475 segmentation.y_dequant[i][1] = kAcQLookup[ClampQ(q_index)]; |
| 637 segmentation_.uv_dequant[i][0] = | 476 segmentation.uv_dequant[i][0] = |
| 638 kDcQLookup[CLAMP_Q(q_index + quant.uv_dc_delta)]; | 477 kDcQLookup[ClampQ(q_index + quant.delta_q_uv_dc)]; |
| 639 segmentation_.uv_dequant[i][1] = | 478 segmentation.uv_dequant[i][1] = |
| 640 kAcQLookup[CLAMP_Q(q_index + quant.uv_ac_delta)]; | 479 kAcQLookup[ClampQ(q_index + quant.delta_q_uv_ac)]; |
| 641 } | 480 } |
| 642 } else { | 481 } else { |
| 643 const size_t q_index = quant.base_qindex; | 482 const size_t q_index = quant.base_q_idx; |
| 644 segmentation_.y_dequant[0][0] = | 483 segmentation.y_dequant[0][0] = |
| 645 kDcQLookup[CLAMP_Q(q_index + quant.y_dc_delta)]; | 484 kDcQLookup[ClampQ(q_index + quant.delta_q_y_dc)]; |
| 646 segmentation_.y_dequant[0][1] = kAcQLookup[CLAMP_Q(q_index)]; | 485 segmentation.y_dequant[0][1] = kAcQLookup[ClampQ(q_index)]; |
| 647 segmentation_.uv_dequant[0][0] = | 486 segmentation.uv_dequant[0][0] = |
| 648 kDcQLookup[CLAMP_Q(q_index + quant.uv_dc_delta)]; | 487 kDcQLookup[ClampQ(q_index + quant.delta_q_uv_dc)]; |
| 649 segmentation_.uv_dequant[0][1] = | 488 segmentation.uv_dequant[0][1] = |
| 650 kAcQLookup[CLAMP_Q(q_index + quant.uv_ac_delta)]; | 489 kAcQLookup[ClampQ(q_index + quant.delta_q_uv_ac)]; |
| 651 } | 490 } |
| 652 } | 491 } |
| 653 #undef CLAMP_Q | |
| 654 | 492 |
| 655 #define CLAMP_LF(l) std::min(std::max(0, l), kMaxLoopFilterLevel) | 493 static int ClampLf(int lf) { |
| 494 const int kMaxLoopFilterLevel = 63; | |
| 495 return std::min(std::max(0, lf), kMaxLoopFilterLevel); | |
| 496 } | |
| 497 | |
| 498 // 8.8.1 Loop filter frame init process | |
| 656 void Vp9Parser::SetupLoopFilter() { | 499 void Vp9Parser::SetupLoopFilter() { |
| 657 if (!loop_filter_.filter_level) | 500 Vp9LoopFilterParams& loop_filter = context_.loop_filter; |
| 501 Vp9SegmentationParams& segmentation = context_.segmentation; | |
| 502 if (!loop_filter.level) | |
| 658 return; | 503 return; |
| 659 | 504 |
| 660 int scale = loop_filter_.filter_level < 32 ? 1 : 2; | 505 int scale = loop_filter.level < 32 ? 1 : 2; |
| 661 | 506 |
| 662 for (size_t i = 0; i < Vp9Segmentation::kNumSegments; ++i) { | 507 for (size_t i = 0; i < Vp9SegmentationParams::kNumSegments; ++i) { |
| 663 int level = loop_filter_.filter_level; | 508 int level = loop_filter.level; |
| 664 | 509 |
| 665 if (segmentation_.FeatureEnabled(i, Vp9Segmentation::SEG_LVL_ALT_LF)) { | 510 if (segmentation.FeatureEnabled(i, Vp9SegmentationParams::SEG_LVL_ALT_LF)) { |
| 666 int feature_data = | 511 int feature_data = |
| 667 segmentation_.FeatureData(i, Vp9Segmentation::SEG_LVL_ALT_LF); | 512 segmentation.FeatureData(i, Vp9SegmentationParams::SEG_LVL_ALT_LF); |
| 668 level = CLAMP_LF(segmentation_.abs_delta ? feature_data | 513 level = ClampLf(segmentation.abs_or_delta_update ? feature_data |
| 669 : level + feature_data); | 514 : level + feature_data); |
| 670 } | 515 } |
| 671 | 516 |
| 672 if (!loop_filter_.mode_ref_delta_enabled) { | 517 if (!loop_filter.delta_enabled) { |
| 673 memset(loop_filter_.lvl[i], level, sizeof(loop_filter_.lvl[i])); | 518 memset(loop_filter.lvl[i], level, sizeof(loop_filter.lvl[i])); |
| 674 } else { | 519 } else { |
| 675 loop_filter_.lvl[i][Vp9LoopFilter::VP9_FRAME_INTRA][0] = CLAMP_LF( | 520 loop_filter.lvl[i][Vp9FrameType::VP9_FRAME_INTRA][0] = ClampLf( |
| 676 level + | 521 level + |
| 677 loop_filter_.ref_deltas[Vp9LoopFilter::VP9_FRAME_INTRA] * scale); | 522 loop_filter.ref_deltas[Vp9FrameType::VP9_FRAME_INTRA] * scale); |
| 678 loop_filter_.lvl[i][Vp9LoopFilter::VP9_FRAME_INTRA][1] = 0; | 523 loop_filter.lvl[i][Vp9FrameType::VP9_FRAME_INTRA][1] = 0; |
| 679 | 524 |
| 680 for (size_t type = Vp9LoopFilter::VP9_FRAME_LAST; | 525 for (size_t type = Vp9FrameType::VP9_FRAME_LAST; |
| 681 type < Vp9LoopFilter::VP9_FRAME_MAX; ++type) { | 526 type < Vp9FrameType::VP9_FRAME_MAX; ++type) { |
| 682 for (size_t mode = 0; mode < Vp9LoopFilter::kNumModeDeltas; ++mode) { | 527 for (size_t mode = 0; mode < Vp9LoopFilterParams::kNumModeDeltas; |
| 683 loop_filter_.lvl[i][type][mode] = | 528 ++mode) { |
| 684 CLAMP_LF(level + loop_filter_.ref_deltas[type] * scale + | 529 loop_filter.lvl[i][type][mode] = |
| 685 loop_filter_.mode_deltas[mode] * scale); | 530 ClampLf(level + loop_filter.ref_deltas[type] * scale + |
| 531 loop_filter.mode_deltas[mode] * scale); | |
| 686 } | 532 } |
| 687 } | 533 } |
| 688 } | 534 } |
| 689 } | 535 } |
| 690 } | 536 } |
| 691 #undef CLAMP_LF | 537 |
| 538 void Vp9Parser::UpdateSlots() { | |
| 539 // 8.10 Reference frame update process | |
| 540 for (size_t i = 0; i < kVp9NumRefFrames; i++) { | |
| 541 if (curr_frame_header_.RefreshFlag(i)) { | |
| 542 ReferenceSlot& ref = context_.ref_slots[i]; | |
| 543 ref.initialized = true; | |
| 544 | |
| 545 ref.frame_width = curr_frame_header_.frame_width; | |
| 546 ref.frame_height = curr_frame_header_.frame_height; | |
| 547 ref.subsampling_x = curr_frame_header_.subsampling_x; | |
| 548 ref.subsampling_y = curr_frame_header_.subsampling_y; | |
| 549 ref.bit_depth = curr_frame_header_.bit_depth; | |
| 550 | |
| 551 ref.profile = curr_frame_header_.profile; | |
| 552 ref.color_space = curr_frame_header_.color_space; | |
| 553 } | |
| 554 } | |
| 555 } | |
| 692 | 556 |
| 693 } // namespace media | 557 } // namespace media |
| OLD | NEW |