Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 // | |
| 5 // This file contains an implementation of a VP9 bitstream parser. | |
| 6 | |
| 7 #include "media/filters/vp9_parser.h" | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 | |
| 11 namespace { | |
| 12 | |
| 13 // Helper function for Vp9Parser::ReadTiles. Defined as get_min_log2_tile_cols | |
| 14 // in spec. | |
| 15 int GetMinLog2TileCols(int sb64_cols) { | |
| 16 const int kMaxTileWidthB64 = 64; | |
| 17 int min_log2 = 0; | |
| 18 while ((kMaxTileWidthB64 << min_log2) < sb64_cols) | |
| 19 min_log2++; | |
| 20 return min_log2; | |
| 21 } | |
| 22 | |
| 23 // Helper function for Vp9Parser::ReadTiles. Defined as get_max_log2_tile_cols | |
| 24 // in spec. | |
| 25 int GetMaxLog2TileCols(int sb64_cols) { | |
| 26 const int kMinTileWidthB64 = 4; | |
| 27 int max_log2 = 1; | |
| 28 while ((sb64_cols >> max_log2) >= kMinTileWidthB64) | |
| 29 max_log2++; | |
| 30 return max_log2 - 1; | |
| 31 } | |
| 32 | |
| 33 } // namespace | |
| 34 | |
| 35 namespace media { | |
| 36 | |
| 37 Vp9Parser::Vp9Parser() : stream_(nullptr), size_(0) { | |
| 38 memset(&ref_slots_, 0, sizeof(ref_slots_)); | |
| 39 } | |
| 40 | |
| 41 uint8_t Vp9Parser::ReadProfile() { | |
| 42 uint8_t profile = 0; | |
| 43 | |
| 44 // LSB first. | |
| 45 profile |= reader_.ReadBit(); | |
| 46 profile |= reader_.ReadBit() << 1; | |
| 47 if (profile > 2) | |
| 48 profile += reader_.ReadBit(); | |
| 49 return profile; | |
| 50 } | |
| 51 | |
| 52 bool Vp9Parser::VerifySyncCode() { | |
| 53 const int kSyncCode = 0x498342; | |
| 54 if (reader_.ReadLiteral(8 * 3) != kSyncCode) { | |
| 55 DVLOG(1) << "Invalid frame sync code"; | |
| 56 return false; | |
| 57 } | |
| 58 return true; | |
| 59 } | |
| 60 | |
| 61 bool Vp9Parser::ReadBitDepthColorSpaceSampling(Vp9FrameHeader* fhdr) { | |
| 62 if (fhdr->profile == 2 || fhdr->profile == 3) { | |
| 63 fhdr->bit_depth = reader_.ReadBit() ? 12 : 10; | |
| 64 } else { | |
| 65 fhdr->bit_depth = 8; | |
| 66 } | |
| 67 | |
| 68 fhdr->color_space = static_cast<Vp9ColorSpace>(reader_.ReadLiteral(3)); | |
| 69 if (fhdr->color_space != Vp9ColorSpace::SRGB) { | |
| 70 fhdr->yuv_range = reader_.ReadBit(); | |
| 71 if (fhdr->profile == 1 || fhdr->profile == 3) { | |
| 72 fhdr->subsampling_x = reader_.ReadBit(); | |
| 73 fhdr->subsampling_y = reader_.ReadBit(); | |
| 74 if (fhdr->subsampling_x == 1 && fhdr->subsampling_y == 1) { | |
| 75 DVLOG(1) << "4:2:0 color not supported in profile 1 or 3"; | |
| 76 return false; | |
| 77 } | |
| 78 bool reserved = reader_.ReadBit(); | |
| 79 if (reserved) { | |
| 80 DVLOG(1) << "reserved bit set"; | |
| 81 return false; | |
| 82 } | |
| 83 } else { | |
| 84 fhdr->subsampling_x = fhdr->subsampling_y = 1; | |
| 85 } | |
| 86 } else { | |
| 87 if (fhdr->profile == 1 || fhdr->profile == 3) { | |
| 88 fhdr->subsampling_x = fhdr->subsampling_y = 0; | |
| 89 | |
| 90 bool reserved = reader_.ReadBit(); | |
| 91 if (reserved) { | |
| 92 DVLOG(1) << "reserved bit set"; | |
| 93 return false; | |
| 94 } | |
| 95 } else { | |
| 96 DVLOG(1) << "4:4:4 color not supported in profile 0 or 2"; | |
| 97 return false; | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 return true; | |
| 102 } | |
| 103 | |
| 104 void Vp9Parser::ReadFrameSize(Vp9FrameHeader* fhdr) { | |
| 105 fhdr->width = reader_.ReadLiteral(16) + 1; | |
| 106 fhdr->height = reader_.ReadLiteral(16) + 1; | |
| 107 } | |
| 108 | |
| 109 bool Vp9Parser::ReadFrameSizeFromRefs(Vp9FrameHeader* fhdr) { | |
| 110 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | |
| 111 if (reader_.ReadBit()) { | |
| 112 fhdr->width = ref_slots_[i].width; | |
| 113 fhdr->height = ref_slots_[i].height; | |
| 114 | |
| 115 const int kMaxDimension = 1 << 16; | |
| 116 if (fhdr->width < 1 || fhdr->width > kMaxDimension || fhdr->height < 1 || | |
|
Pawel Osciak
2015/08/05 07:46:32
Oh sorry, we should say if fhdr->width == 0 not <
kcwu
2015/08/05 08:42:40
Done.
| |
| 117 fhdr->height > kMaxDimension) { | |
| 118 DVLOG(1) << "The size of referenced frame is out of range: " | |
|
Pawel Osciak
2015/08/05 07:46:32
s/referenced/reference/
kcwu
2015/08/05 08:42:40
Done.
| |
| 119 << ref_slots_[i].width << "," << ref_slots_[i].height; | |
| 120 return false; | |
| 121 } | |
| 122 return true; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 fhdr->width = reader_.ReadLiteral(16) + 1; | |
| 127 fhdr->height = reader_.ReadLiteral(16) + 1; | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 void Vp9Parser::ReadDisplayFrameSize(Vp9FrameHeader* fhdr) { | |
| 132 if (reader_.ReadBit()) { | |
| 133 fhdr->display_width = reader_.ReadLiteral(16) + 1; | |
| 134 fhdr->display_height = reader_.ReadLiteral(16) + 1; | |
| 135 } else { | |
| 136 fhdr->display_width = fhdr->width; | |
| 137 fhdr->display_height = fhdr->height; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 Vp9InterpFilter Vp9Parser::ReadInterpFilter() { | |
| 142 if (reader_.ReadBit()) | |
| 143 return Vp9InterpFilter::INTERP_FILTER_SELECT; | |
| 144 | |
| 145 // The mapping table for next two bits. | |
| 146 const Vp9InterpFilter table[] = { | |
| 147 Vp9InterpFilter::EIGHTTAP_SMOOTH, Vp9InterpFilter::EIGHTTAP, | |
| 148 Vp9InterpFilter::EIGHTTAP_SHARP, Vp9InterpFilter::BILINEAR, | |
| 149 }; | |
| 150 return table[reader_.ReadLiteral(2)]; | |
| 151 } | |
| 152 | |
| 153 void Vp9Parser::ReadLoopFilter(Vp9LoopFilter* loop_filter) { | |
| 154 loop_filter->filter_level = reader_.ReadLiteral(6); | |
| 155 loop_filter->sharpness_level = reader_.ReadLiteral(3); | |
| 156 | |
| 157 loop_filter->mode_ref_delta_enabled = reader_.ReadBit(); | |
| 158 if (loop_filter->mode_ref_delta_enabled) { | |
| 159 loop_filter->mode_ref_delta_update = reader_.ReadBit(); | |
| 160 if (loop_filter->mode_ref_delta_update) { | |
| 161 for (size_t i = 0; i < Vp9LoopFilter::kNumRefDeltas; i++) { | |
| 162 loop_filter->update_ref_deltas[i] = reader_.ReadBit(); | |
| 163 if (loop_filter->update_ref_deltas[i]) | |
| 164 loop_filter->ref_deltas[i] = reader_.ReadSignedLiteral(6); | |
| 165 } | |
| 166 | |
| 167 for (size_t i = 0; i < Vp9LoopFilter::kNumModeDeltas; i++) { | |
| 168 loop_filter->update_mode_deltas[i] = reader_.ReadBit(); | |
| 169 if (loop_filter->update_mode_deltas[i]) | |
| 170 loop_filter->mode_deltas[i] = reader_.ReadLiteral(6); | |
| 171 } | |
| 172 } | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 void Vp9Parser::ReadQuantization(Vp9QuantizationParams* quants) { | |
| 177 quants->base_qindex = reader_.ReadLiteral(8); | |
| 178 | |
| 179 if (reader_.ReadBit()) | |
| 180 quants->y_dc_delta = reader_.ReadSignedLiteral(4); | |
| 181 | |
| 182 if (reader_.ReadBit()) | |
| 183 quants->uv_ac_delta = reader_.ReadSignedLiteral(4); | |
| 184 | |
| 185 if (reader_.ReadBit()) | |
| 186 quants->uv_dc_delta = reader_.ReadSignedLiteral(4); | |
| 187 } | |
| 188 | |
| 189 void Vp9Parser::ReadSegmentationMap(Vp9Segmentation* segment) { | |
| 190 for (size_t i = 0; i < Vp9Segmentation::kNumTreeProbs; i++) { | |
| 191 segment->tree_probs[i] = | |
| 192 reader_.ReadBit() ? reader_.ReadLiteral(8) : kVp9MaxProb; | |
| 193 } | |
| 194 | |
| 195 for (size_t i = 0; i < Vp9Segmentation::kNumPredictionProbs; i++) | |
| 196 segment->pred_probs[i] = kVp9MaxProb; | |
| 197 | |
| 198 segment->temporal_update = reader_.ReadBit(); | |
| 199 if (segment->temporal_update) { | |
| 200 for (size_t i = 0; i < Vp9Segmentation::kNumPredictionProbs; i++) { | |
| 201 if (reader_.ReadBit()) | |
| 202 segment->pred_probs[i] = reader_.ReadLiteral(8); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 void Vp9Parser::ReadSegmentationData(Vp9Segmentation* segment) { | |
| 208 segment->abs_delta = reader_.ReadBit(); | |
| 209 | |
| 210 const int kFeatureDataBits[] = {7, 6, 2, 0}; | |
| 211 const bool kFeatureDataSigned[] = {true, true, false, false}; | |
| 212 | |
| 213 for (size_t i = 0; i < Vp9Segmentation::kNumSegments; i++) { | |
| 214 for (size_t j = 0; j < Vp9Segmentation::kNumFeatures; j++) { | |
| 215 int8_t data = 0; | |
| 216 segment->feature_enabled[i][j] = reader_.ReadBit(); | |
| 217 if (segment->feature_enabled[i][j]) { | |
| 218 data = reader_.ReadLiteral(kFeatureDataBits[j]); | |
| 219 if (kFeatureDataSigned[j]) | |
| 220 if (reader_.ReadBit()) | |
| 221 data = -data; | |
| 222 } | |
| 223 segment->feature_data[i][j] = data; | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 void Vp9Parser::ReadSegmentation(Vp9Segmentation* segment) { | |
| 229 segment->enabled = reader_.ReadBit(); | |
| 230 | |
| 231 if (!segment->enabled) { | |
| 232 return; | |
| 233 } | |
| 234 | |
| 235 segment->update_map = reader_.ReadBit(); | |
| 236 if (segment->update_map) | |
| 237 ReadSegmentationMap(segment); | |
| 238 | |
| 239 segment->update_data = reader_.ReadBit(); | |
| 240 if (segment->update_data) | |
| 241 ReadSegmentationData(segment); | |
| 242 } | |
| 243 | |
| 244 void Vp9Parser::ReadTiles(Vp9FrameHeader* fhdr) { | |
| 245 int sb64_cols = (fhdr->width + 63) / 64; | |
| 246 | |
| 247 int min_log2_tile_cols = GetMinLog2TileCols(sb64_cols); | |
| 248 int max_log2_tile_cols = GetMaxLog2TileCols(sb64_cols); | |
| 249 | |
| 250 int max_ones = max_log2_tile_cols - min_log2_tile_cols; | |
| 251 fhdr->log2_tile_cols = min_log2_tile_cols; | |
| 252 while (max_ones-- && reader_.ReadBit()) | |
| 253 fhdr->log2_tile_cols++; | |
| 254 | |
| 255 if (reader_.ReadBit()) | |
| 256 fhdr->log2_tile_rows = reader_.ReadLiteral(2) - 1; | |
| 257 } | |
| 258 | |
| 259 bool Vp9Parser::ParseUncompressedHeader(Vp9FrameHeader* fhdr) { | |
| 260 reader_.Initialize(stream_, size_); | |
| 261 | |
| 262 // frame marker | |
| 263 if (reader_.ReadLiteral(2) != 0x2) | |
| 264 return false; | |
| 265 | |
| 266 fhdr->profile = ReadProfile(); | |
| 267 if (fhdr->profile >= kVp9MaxProfile) { | |
| 268 DVLOG(1) << "Unsupported bitstream profile"; | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 272 fhdr->show_existing_frame = reader_.ReadBit(); | |
| 273 if (fhdr->show_existing_frame) { | |
| 274 fhdr->frame_to_show = reader_.ReadLiteral(3); | |
| 275 fhdr->show_frame = true; | |
| 276 | |
| 277 if (!reader_.IsValid()) { | |
|
Pawel Osciak
2015/08/05 07:46:32
I'm wondering, why this check here specifically? W
kcwu
2015/08/05 08:42:40
Here is a "return true".
| |
| 278 DVLOG(1) << "parser reads beyond the end of buffer"; | |
| 279 return false; | |
| 280 } | |
| 281 fhdr->uncompressed_header_size = reader_.GetBytesRead(); | |
| 282 return true; | |
| 283 } | |
| 284 | |
| 285 fhdr->frame_type = static_cast<Vp9FrameHeader::FrameType>(reader_.ReadBit()); | |
| 286 fhdr->show_frame = reader_.ReadBit(); | |
| 287 fhdr->error_resilient_mode = reader_.ReadBit(); | |
| 288 | |
| 289 if (fhdr->IsKeyframe()) { | |
| 290 if (!VerifySyncCode()) | |
| 291 return false; | |
| 292 | |
| 293 if (!ReadBitDepthColorSpaceSampling(fhdr)) | |
| 294 return false; | |
| 295 | |
| 296 for (size_t i = 0; i < kVp9NumRefFrames; i++) | |
| 297 fhdr->refresh_flag[i] = true; | |
| 298 | |
| 299 ReadFrameSize(fhdr); | |
| 300 ReadDisplayFrameSize(fhdr); | |
| 301 } else { | |
| 302 if (!fhdr->show_frame) | |
| 303 fhdr->intra_only = reader_.ReadBit(); | |
| 304 | |
| 305 if (!fhdr->error_resilient_mode) | |
| 306 fhdr->reset_context = reader_.ReadLiteral(2); | |
| 307 | |
| 308 if (fhdr->intra_only) { | |
| 309 if (!VerifySyncCode()) | |
| 310 return false; | |
| 311 | |
| 312 if (fhdr->profile > 0) { | |
| 313 if (!ReadBitDepthColorSpaceSampling(fhdr)) | |
| 314 return false; | |
| 315 } else { | |
| 316 fhdr->bit_depth = 8; | |
| 317 fhdr->color_space = Vp9ColorSpace::BT_601; | |
| 318 fhdr->subsampling_x = fhdr->subsampling_y = 1; | |
| 319 } | |
| 320 | |
| 321 for (size_t i = 0; i < kVp9NumRefFrames; i++) | |
| 322 fhdr->refresh_flag[i] = reader_.ReadBit(); | |
| 323 ReadFrameSize(fhdr); | |
| 324 ReadDisplayFrameSize(fhdr); | |
| 325 } else { | |
| 326 for (size_t i = 0; i < kVp9NumRefFrames; i++) | |
| 327 fhdr->refresh_flag[i] = reader_.ReadBit(); | |
| 328 | |
| 329 for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { | |
| 330 fhdr->frame_refs[i] = reader_.ReadLiteral(kVp9NumRefFramesLog2); | |
| 331 fhdr->ref_sign_biases[i] = reader_.ReadBit(); | |
| 332 } | |
| 333 | |
| 334 if (!ReadFrameSizeFromRefs(fhdr)) | |
| 335 return false; | |
| 336 ReadDisplayFrameSize(fhdr); | |
| 337 | |
| 338 fhdr->allow_high_precision_mv = reader_.ReadBit(); | |
| 339 fhdr->interp_filter = ReadInterpFilter(); | |
| 340 } | |
| 341 } | |
| 342 | |
| 343 if (fhdr->error_resilient_mode) { | |
| 344 fhdr->frame_parallel_decoding_mode = true; | |
| 345 } else { | |
| 346 fhdr->refresh_frame_context = reader_.ReadBit(); | |
| 347 fhdr->frame_parallel_decoding_mode = reader_.ReadBit(); | |
| 348 } | |
| 349 | |
| 350 fhdr->frame_context_idx = reader_.ReadLiteral(2); | |
| 351 | |
| 352 ReadLoopFilter(&fhdr->loop_filter); | |
| 353 ReadQuantization(&fhdr->quant_params); | |
| 354 ReadSegmentation(&fhdr->segment); | |
| 355 | |
| 356 ReadTiles(fhdr); | |
| 357 | |
| 358 fhdr->first_partition_size = reader_.ReadLiteral(16); | |
| 359 if (fhdr->first_partition_size == 0) { | |
| 360 DVLOG(1) << "invalid header size"; | |
| 361 return false; | |
| 362 } | |
| 363 | |
| 364 if (!reader_.IsValid()) { | |
| 365 DVLOG(1) << "parser reads beyond the end of buffer"; | |
| 366 return false; | |
| 367 } | |
| 368 fhdr->uncompressed_header_size = reader_.GetBytesRead(); | |
| 369 | |
| 370 return true; | |
| 371 } | |
| 372 | |
| 373 void Vp9Parser::UpdateSlots(const Vp9FrameHeader* fhdr) { | |
| 374 for (int i = 0; i < kVp9NumRefFrames; i++) { | |
|
Pawel Osciak
2015/08/05 07:46:32
s/int/size_t/
kcwu
2015/08/05 08:42:40
Done.
| |
| 375 if (fhdr->refresh_flag[i]) { | |
| 376 ref_slots_[i].width = fhdr->width; | |
| 377 ref_slots_[i].height = fhdr->height; | |
| 378 } | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 bool Vp9Parser::ParseFrame(const uint8_t* stream, | |
| 383 size_t frame_size, | |
| 384 Vp9FrameHeader* fhdr) { | |
| 385 DCHECK(stream); | |
| 386 stream_ = stream; | |
| 387 size_ = frame_size; | |
| 388 memset(fhdr, 0, sizeof(*fhdr)); | |
| 389 | |
| 390 if (!ParseUncompressedHeader(fhdr)) | |
| 391 return false; | |
| 392 | |
| 393 UpdateSlots(fhdr); | |
| 394 | |
| 395 return true; | |
| 396 } | |
| 397 | |
| 398 } // namespace media | |
| OLD | NEW |