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