Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: media/filters/vp9_parser.cc

Issue 1258083004: Add a Vp9Parser implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: move ref slots back to Vp9Parser Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698