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

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: remove dependent files from this CL 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 int GetMinLog2TileCols(int sb64_cols) {
Pawel Osciak 2015/07/30 08:27:37 static? Also please document what this function is
kcwu 2015/07/31 08:51:51 IIUC, no need to add static qualifier if it is alr
14 const int kMaxTileWidthB64 = 64;
15 int min_log2 = 0;
16 while ((kMaxTileWidthB64 << min_log2) < sb64_cols)
17 min_log2++;
18 return min_log2;
19 }
20
21 int GetMaxLog2TileCols(int sb64_cols) {
Pawel Osciak 2015/07/30 08:27:37 static?
kcwu 2015/07/31 08:51:51 Acknowledged.
22 const int kMinTileWidthB64 = 4;
23 int max_log2 = 1;
24 while ((sb64_cols >> max_log2) >= kMinTileWidthB64)
25 max_log2++;
26 return max_log2 - 1;
27 }
28
29 } // namespace
30
31 namespace media {
32
33 Vp9Parser::Vp9Parser() : stream_(nullptr), size_(0) {
34 memset(&ref_slots_, 0, sizeof(ref_slots_));
35 }
36
37 uint8_t Vp9Parser::ReadProfile() {
38 uint8_t profile = 0;
39
40 // LSB first.
41 profile |= reader_.ReadBit();
42 profile |= reader_.ReadBit() << 1;
43 if (profile > 2)
44 profile |= reader_.ReadBit() << 2;
45 return profile;
46 }
47
48 bool Vp9Parser::VerifySyncCode() {
49 const int kSyncCode = 0x498342;
50 if (reader_.ReadLiteral(8 * 3) != kSyncCode) {
Pawel Osciak 2015/07/30 08:27:37 General comment: ReadLiteral/ReadBit should have a
kcwu 2015/07/31 08:51:51 Per our chat. We agreed checking reader failure at
51 DLOG(ERROR) << "Invalid frame sync code";
52 return false;
Pawel Osciak 2015/07/30 08:27:38 DVLOG please
kcwu1 2015/07/30 08:55:49 Only this one or all in this class?
Pawel Osciak 2015/07/30 08:59:24 All please.
kcwu1 2015/07/31 04:36:01 Done.
53 }
54 return true;
55 }
56
57 bool Vp9Parser::ReadBitDepthColorSpaceSampling(Vp9FrameHeader* fhdr) {
58 if (fhdr->profile >= 2) {
59 if (reader_.ReadBit())
60 fhdr->bit_depth = 12;
61 else
62 fhdr->bit_depth = 10;
63 } else {
64 fhdr->bit_depth = 8;
65 }
66
67 fhdr->color_space = static_cast<Vp9ColorSpace>(reader_.ReadLiteral(3));
68 if (fhdr->color_space != Vp9ColorSpace::SRGB) {
69 fhdr->yuv_range = reader_.ReadBit();
70 if (fhdr->profile == 1 || fhdr->profile == 3) {
71 fhdr->subsampling_x = reader_.ReadBit();
72 fhdr->subsampling_y = reader_.ReadBit();
73 if (fhdr->subsampling_x == 1 && fhdr->subsampling_y == 1) {
74 DLOG(ERROR) << "4:2:0 color not supported in profile 1 or 3";
75 return false;
76 }
77 bool reserved = reader_.ReadBit();
78 if (reserved) {
79 DLOG(ERROR) << "reserved bit set";
80 return false;
81 }
82 } else {
83 fhdr->subsampling_x = fhdr->subsampling_y = 1;
84 }
85 } else {
86 if (fhdr->profile == 1 || fhdr->profile == 3) {
87 fhdr->subsampling_x = fhdr->subsampling_y = 0;
88
89 // this bit is not specified in spec??
Pawel Osciak 2015/07/30 08:27:37 s/this/This/ s/??/?/
kcwu1 2015/07/30 08:55:49 just keep note. I expect this will be removed befo
90 bool reserved = reader_.ReadBit();
91 if (reserved) {
92 DLOG(ERROR) << "reserved bit set";
93 return false;
94 }
95 } else {
96 DLOG(ERROR) << "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 void Vp9Parser::ReadFrameSizeFromRefs(Vp9FrameHeader* fhdr) {
110 for (int i = 0; i < kVp9RefsPerFrame; i++) {
Pawel Osciak 2015/07/30 08:27:37 s/int/size_t/ Please use size_t in general for it
kcwu1 2015/07/31 04:36:02 Done.
111 if (reader_.ReadBit()) {
112 fhdr->width = ref_slots_[i].width;
113 fhdr->height = ref_slots_[i].height;
114 return;
115 }
116 }
117
118 fhdr->width = reader_.ReadLiteral(16) + 1;
119 fhdr->height = reader_.ReadLiteral(16) + 1;
120 }
121
122 void Vp9Parser::ReadDisplayFrameSize(Vp9FrameHeader* fhdr) {
123 if (reader_.ReadBit()) {
124 fhdr->display_width = reader_.ReadLiteral(16) + 1;
125 fhdr->display_height = reader_.ReadLiteral(16) + 1;
126 } else {
127 fhdr->display_width = fhdr->width;
128 fhdr->display_height = fhdr->height;
129 }
130 }
131
132 Vp9InterpFilter Vp9Parser::ReadInterpFilter() {
133 if (reader_.ReadBit())
134 return Vp9InterpFilter::INTERP_FILTER_SELECT;
135
136 // The mapping table for next two bits.
137 Vp9InterpFilter table[] = {
Pawel Osciak 2015/07/30 08:27:37 const?
kcwu1 2015/07/31 04:36:01 Done.
138 Vp9InterpFilter::EIGHTTAP_SMOOTH, Vp9InterpFilter::EIGHTTAP,
139 Vp9InterpFilter::EIGHTTAP_SHARP, Vp9InterpFilter::BILINEAR,
140 };
141 return table[reader_.ReadLiteral(2)];
Pawel Osciak 2015/07/30 08:27:38 Is this different from return ReadLiteral(2) + 1 ?
kcwu1 2015/07/30 08:55:49 No difference. I just followed libvpx and feel it
Pawel Osciak 2015/07/30 08:59:24 Acknowledged.
142 }
143
144 void Vp9Parser::ReadLoopFilter(Vp9LoopFilter* loop_filter) {
145 loop_filter->filter_level = reader_.ReadLiteral(6);
146 loop_filter->sharpness_level = reader_.ReadLiteral(3);
147
148 loop_filter->mode_ref_delta_enabled = reader_.ReadBit();
149 if (loop_filter->mode_ref_delta_enabled) {
150 loop_filter->mode_ref_delta_update = reader_.ReadBit();
151 if (loop_filter->mode_ref_delta_update) {
152 for (int i = 0; i < Vp9LoopFilter::kNumRefDeltas; i++) {
153 loop_filter->update_ref_deltas[i] = reader_.ReadBit();
154 if (loop_filter->update_ref_deltas[i])
155 loop_filter->ref_deltas[i] = reader_.ReadSignedLiteral(6);
156 }
157
158 for (int i = 0; i < Vp9LoopFilter::kNumModeDeltas; i++) {
159 loop_filter->update_mode_deltas[i] = reader_.ReadBit();
160 if (loop_filter->update_mode_deltas[i])
161 loop_filter->mode_deltas[i] = reader_.ReadLiteral(6);
162 }
163 }
164 } else {
165 loop_filter->mode_ref_delta_update = false;
166 }
167 }
168
169 void Vp9Parser::ReadQuantization(Vp9QuantizationParams* quants) {
170 quants->base_qindex = reader_.ReadLiteral(8);
171
172 if (reader_.ReadBit())
173 quants->y_dc_delta = reader_.ReadSignedLiteral(4);
174 else
175 quants->y_dc_delta = 0;
176
177 if (reader_.ReadBit())
178 quants->uv_ac_delta = reader_.ReadSignedLiteral(4);
179 else
180 quants->uv_ac_delta = 0;
181
182 if (reader_.ReadBit())
183 quants->uv_dc_delta = reader_.ReadSignedLiteral(4);
184 else
185 quants->uv_dc_delta = 0;
186 }
187
188 void Vp9Parser::ReadSegmentationMap(Vp9Segmentation* segment) {
189 for (int i = 0; i < Vp9Segmentation::kTreeProbs; i++) {
190 if (reader_.ReadBit())
191 segment->tree_probs[i] = reader_.ReadLiteral(8);
192 else
193 segment->tree_probs[i] = kVp9MaxProb;
194 }
195
196 for (int i = 0; i < Vp9Segmentation::kPredictionProbs; i++)
197 segment->pred_probs[i] = kVp9MaxProb;
198 if (reader_.ReadBit()) {
Pawel Osciak 2015/07/30 11:52:31 Please store this in frame header (as temporal_upd
kcwu1 2015/07/31 04:36:01 Done.
199 for (int i = 0; i < Vp9Segmentation::kPredictionProbs; i++) {
200 if (reader_.ReadBit())
201 segment->pred_probs[i] = reader_.ReadLiteral(8);
202 }
203 }
204 }
205
206 void Vp9Parser::ReadSegmentationData(Vp9Segmentation* segment) {
207 segment->abs_delta = reader_.ReadBit();
208
209 const int kFeatureDataBits[] = {7, 6, 2, 0};
210 const bool kFeatureDataSigned[] = {true, true, false, false};
211
212 for (int i = 0; i < Vp9Segmentation::kNumSegment; i++) {
213 for (int j = 0; j < Vp9Segmentation::kNumFeature; j++) {
214 int8_t data = 0;
215 segment->feature_enabled[i][j] = reader_.ReadBit();
216 if (segment->feature_enabled[i][j]) {
217 data = reader_.ReadLiteral(kFeatureDataBits[j]);
218 if (kFeatureDataSigned[j])
219 if (reader_.ReadBit())
220 data = -data;
221 }
222 segment->feature_data[i][j] = data;
223 }
224 }
225 }
226
227 void Vp9Parser::ReadSegmentation(Vp9Segmentation* segment) {
228 segment->enabled = reader_.ReadBit();
229
230 if (!segment->enabled) {
231 segment->update_map = false;
232 segment->update_data = false;
233 return;
234 }
235
236 segment->update_map = reader_.ReadBit();
237 if (segment->update_map)
238 ReadSegmentationMap(segment);
239
240 segment->update_data = reader_.ReadBit();
241 if (segment->update_data)
242 ReadSegmentationData(segment);
243 }
244
245 void Vp9Parser::ReadTiles(Vp9FrameHeader* fhdr) {
246 int sb64_cols = (fhdr->width + 63) / 64;
247
248 int min_log2_tile_cols = GetMinLog2TileCols(sb64_cols);
249 int max_log2_tile_cols = GetMaxLog2TileCols(sb64_cols);
250
251 int max_ones = max_log2_tile_cols - min_log2_tile_cols;
252 fhdr->log2_tile_cols = min_log2_tile_cols;
253 while (max_ones-- && reader_.ReadBit())
254 fhdr->log2_tile_cols++;
255
256 if (reader_.ReadBit())
257 fhdr->log2_tile_rows = reader_.ReadLiteral(2) - 1;
258 else
259 fhdr->log2_tile_rows = 0;
260 }
261
262 bool Vp9Parser::ParseUncompressedHeader(Vp9FrameHeader* fhdr) {
263 reader_.Initialize(stream_, size_);
264
265 // frame marker
266 if (reader_.ReadLiteral(2) != 0x2)
267 return false;
268
269 fhdr->profile = ReadProfile();
270 if (fhdr->profile >= kVp9MaxProfile) {
271 DLOG(ERROR) << "Unsupported bitstream profile";
272 return false;
273 }
274
275 fhdr->show_existing_frame = reader_.ReadBit();
276 if (fhdr->show_existing_frame) {
277 fhdr->frame_to_show = reader_.ReadLiteral(3);
278 fhdr->loop_filter.filter_level = 0;
Pawel Osciak 2015/07/30 08:27:37 It seems that sometimes we initialize members to 0
kcwu1 2015/07/31 04:36:01 Done.
279 fhdr->show_frame = true;
280
281 fhdr->first_partition_size = 0;
282 fhdr->compressed_header = nullptr;
283
284 if (reader_.IsOutOfBuffer()) {
Pawel Osciak 2015/07/30 08:27:37 This shouldn't be needed once we make ReadBit/Lite
kcwu1 2015/07/30 08:55:49 Since out of data is rare, I'd prefer checked only
Pawel Osciak 2015/07/30 08:59:24 We can't read beyond memory that we have available
kcwu1 2015/07/30 09:04:15 The reader returns 0 if out of buffer. The return
285 DLOG(ERROR) << "parser reads beyond the end of buffer";
286 return false;
287 }
288 return true;
289 }
290
291 fhdr->frame_type = static_cast<Vp9FrameHeader::FrameType>(reader_.ReadBit());
292 fhdr->show_frame = reader_.ReadBit();
293 fhdr->error_resilient_mode = reader_.ReadBit();
294
295 if (fhdr->IsKeyframe()) {
296 if (!VerifySyncCode())
297 return false;
298
299 if (!ReadBitDepthColorSpaceSampling(fhdr))
300 return false;
301
302 memset(&ref_slots_, 0, sizeof(ref_slots_));
303 for (int i = 0; i < kVp9RefFrames; i++)
304 fhdr->refresh_flag[i] = true;
305
306 ReadFrameSize(fhdr);
307 ReadDisplayFrameSize(fhdr);
308 } else {
309 if (fhdr->show_frame)
310 fhdr->intra_only = false;
311 else
312 fhdr->intra_only = reader_.ReadBit();
313 if (fhdr->error_resilient_mode)
Pawel Osciak 2015/07/30 08:27:37 Please add empty line above.
kcwu1 2015/07/31 04:36:01 Done.
314 fhdr->reset_context = false;
315 else
316 fhdr->reset_context = reader_.ReadLiteral(2);
317
318 if (fhdr->intra_only) {
319 if (!VerifySyncCode())
320 return false;
321
322 if (fhdr->profile > 0) {
323 if (!ReadBitDepthColorSpaceSampling(fhdr))
324 return false;
325 } else {
326 fhdr->bit_depth = 8;
327 fhdr->color_space = Vp9ColorSpace::BT_601;
328 fhdr->subsampling_x = fhdr->subsampling_y = 1;
329 }
330
331 for (int i = 0; i < kVp9RefFrames; i++)
332 fhdr->refresh_flag[i] = reader_.ReadBit();
333 ReadFrameSize(fhdr);
334 ReadDisplayFrameSize(fhdr);
335 } else {
336 for (int i = 0; i < kVp9RefFrames; i++)
337 fhdr->refresh_flag[i] = reader_.ReadBit();
338
339 for (int i = 0; i < kVp9RefsPerFrame; i++) {
340 fhdr->frame_refs[i] = reader_.ReadLiteral(kVp9RefFramesLog2);
341 fhdr->ref_sign_biases[i] = reader_.ReadBit();
342 }
343
344 ReadFrameSizeFromRefs(fhdr);
345 ReadDisplayFrameSize(fhdr);
346
347 fhdr->allow_high_precision_mv = reader_.ReadBit();
348 fhdr->interp_filter = ReadInterpFilter();
349 }
350 }
351
352 if (fhdr->error_resilient_mode) {
353 fhdr->refresh_frame_context = false;
354 fhdr->frame_parallel_decoding_mode = true;
355 } else {
356 fhdr->refresh_frame_context = reader_.ReadBit();
357 fhdr->frame_parallel_decoding_mode = reader_.ReadBit();
358 }
359
360 const int kFrameContextLog2 = 2;
Pawel Osciak 2015/07/30 08:27:37 Any reason to make this specifically into a consta
kcwu1 2015/07/30 08:55:49 Do you mean why not use literal 2 directly?
Pawel Osciak 2015/07/30 08:59:24 Yes.
kcwu1 2015/07/31 04:36:01 Done.
361 fhdr->frame_context_idx = reader_.ReadLiteral(kFrameContextLog2);
362
363 ReadLoopFilter(&fhdr->loop_filter);
364 ReadQuantization(&fhdr->quant_params);
365 ReadSegmentation(&fhdr->segment);
366
367 ReadTiles(fhdr);
368
369 fhdr->first_partition_size = reader_.ReadLiteral(16);
370 if (fhdr->first_partition_size == 0) {
371 DLOG(ERROR) << "invalid header size";
372 return false;
373 }
374 fhdr->compressed_header = stream_ + reader_.GetBytesRead();
Pawel Osciak 2015/07/30 11:52:31 Could we also store the size of uncompressed heade
kcwu1 2015/07/31 04:36:01 Done. And remove |compressed_header| since it is r
375
376 if (reader_.IsOutOfBuffer()) {
377 DLOG(ERROR) << "parser reads beyond the end of buffer";
378 return false;
379 }
380
381 return true;
382 }
383
384 void Vp9Parser::UpdateSlots(Vp9FrameHeader* fhdr) {
385 for (int i = 0; i < kVp9RefFrames; i++) {
386 if (fhdr->refresh_flag[i]) {
387 ref_slots_[i].used = true;
388 ref_slots_[i].width = fhdr->width;
389 ref_slots_[i].height = fhdr->height;
390 }
391 }
392 }
393
394 bool Vp9Parser::ParseFrame(const uint8_t* ptr,
395 size_t frame_size,
396 Vp9FrameHeader* fhdr) {
397 stream_ = ptr;
398 size_ = frame_size;
399 memset(fhdr, 0, sizeof(*fhdr));
400
401 if (!ParseUncompressedHeader(fhdr))
402 return false;
403
404 UpdateSlots(fhdr);
405
406 return true;
407 }
408
409 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698