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 |