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

Side by Side Diff: content/common/gpu/media/vaapi_jpeg_parser.cc

Issue 748023002: Add JPEG parser for JPEG decode acceleration (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 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 2014 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 #include "base/logging.h"
6 #include "content/common/gpu/media/vaapi_jpeg_parser.h"
7
8 using base::BigEndianReader;
9
10 #define READ_U8_OR_RETURN_FALSE(out) \
11 do { \
12 uint8_t _out; \
13 if (!reader.ReadU8(&_out)) { \
14 DVLOG(1) \
15 << "Error in stream: unexpected EOS while trying to read " #out; \
16 return false; \
17 } \
18 *(out) = _out; \
19 } while (0)
20
21 #define READ_U16_OR_RETURN_FALSE(out) \
22 do { \
23 uint16_t _out; \
24 if (!reader.ReadU16(&_out)) { \
25 DVLOG(1) \
26 << "Error in stream: unexpected EOS while trying to read " #out; \
27 return false; \
28 } \
29 *(out) = _out; \
30 } while (0)
31
32 #define IN_RANGE_OR_RETURN_FALSE(val, min, max) \
33 do { \
34 if ((val) < (min) || (val) > (max)) { \
35 DVLOG(1) << "Error in stream: invalid value, expected " #val " to be" \
36 << " in range [" << (min) << ":" << (max) << "]" \
37 << " found " << (val) << " instead"; \
38 return false; \
39 } \
40 } while (0)
41
42 namespace content {
43
44 namespace {
45 enum JpegMarker {
46 SOF0 = 0xC0, // start of frame (baseline)
47 DHT = 0xC4, // define huffman table
48 SOI = 0xD8, // start of image
49 SOS = 0xDA, // start of scan
50 DQT = 0xDB, // define quantization table
51 DRI = 0xDD, // define restart internal
52 MARKER1 = 0xFF, // jpeg marker prefix
53 };
54 } // namespace
55
56 JpegParseResult::JpegParseResult() {
57 }
58
59 JpegParser::JpegParser() {
60 }
61 JpegParser::~JpegParser() {
62 }
63
64 bool JpegParser::ParseSOF(const char* buffer,
65 size_t length,
66 JpegParseResult* result) {
67 // Spec B.2.2 Frame header syntax
68 DCHECK(buffer);
69 DCHECK(result);
70 BigEndianReader reader(buffer, length);
71
72 uint8_t precision;
73 uint16_t visible_width;
74 uint16_t visible_height;
75 READ_U8_OR_RETURN_FALSE(&precision);
76 READ_U16_OR_RETURN_FALSE(&visible_height);
77 READ_U16_OR_RETURN_FALSE(&visible_width);
78 READ_U8_OR_RETURN_FALSE(&result->num_components);
79 result->visible_size = gfx::Size(visible_width, visible_height);
Owen Lin 2014/12/29 09:03:20 Why not result->visible_size.SetSize()?
80
81 if (precision != 8) {
82 DLOG(ERROR) << "Only support 8 bit precision, not "
83 << static_cast<int>(precision) << " bit for baseline";
84 return false;
85 }
86 if (result->num_components >= arraysize(result->components)) {
87 DLOG(ERROR) << "num_components=" << static_cast<int>(result->num_components)
88 << " is not supported";
89 return false;
90 }
91
92 for (size_t i = 0; i < result->num_components; i++) {
93 JpegComponent& component = result->components[i];
94 READ_U8_OR_RETURN_FALSE(&component.id);
95 if (component.id > result->num_components) {
96 DLOG(ERROR) << "component id (" << static_cast<int>(component.id)
97 << ") should be <= num_components ("
98 << static_cast<int>(result->num_components) << ")";
99 return false;
100 }
101 uint8_t hv;
102 READ_U8_OR_RETURN_FALSE(&hv);
103 component.horizontal_sampling_factor = hv / 16;
104 component.vertical_sampling_factor = hv % 16;
105 IN_RANGE_OR_RETURN_FALSE(component.horizontal_sampling_factor, 1, 4);
106 IN_RANGE_OR_RETURN_FALSE(component.vertical_sampling_factor, 1, 4);
107 READ_U8_OR_RETURN_FALSE(&component.quantization_table_selector);
108 }
109
110 return true;
111 }
112
113 bool JpegParser::ParseDQT(const char* buffer,
114 size_t length,
115 JpegParseResult* result) {
116 // Spec B.2.4.1 Quantization table-specification syntax
117 DCHECK(buffer);
118 DCHECK(result);
119 BigEndianReader reader(buffer, length);
120 while (reader.remaining() > 0) {
121 uint8_t tmp;
122 READ_U8_OR_RETURN_FALSE(&tmp);
123 uint8_t precision = tmp / 16;
124 uint8_t table_id = tmp % 16;
125 IN_RANGE_OR_RETURN_FALSE(precision, 0, 1);
126 if (precision == 1) { // 1 means 16-bit precision
127 DLOG(ERROR) << "An 8-bit DCT-based process shall not use a 16-bit "
128 << "precision quantization table";
129 return false;
130 }
131 if (table_id >= kJpegMaxQuantizationTableNum) {
132 DLOG(ERROR) << "Quantization table id (" << static_cast<int>(table_id)
133 << ") exceeded " << kJpegMaxQuantizationTableNum;
134 return false;
135 }
136
137 if (!reader.ReadBytes(&result->q_table[table_id].value,
138 sizeof(result->q_table[table_id].value)))
139 return false;
140 result->q_table[table_id].valid = true;
141 }
142 return true;
143 }
144
145 bool JpegParser::ParseDHT(const char* buffer,
146 size_t length,
147 JpegParseResult* result) {
148 // Spec B.2.4.2 Huffman table-specification syntax
149 DCHECK(buffer);
150 DCHECK(result);
151 BigEndianReader reader(buffer, length);
152 while (reader.remaining() > 0) {
153 uint8_t tmp;
154 READ_U8_OR_RETURN_FALSE(&tmp);
155 int table_class = tmp / 16;
156 int table_id = tmp % 16;
157 IN_RANGE_OR_RETURN_FALSE(table_class, 0, 1);
158 if (table_id >= 2) {
159 DLOG(ERROR) << "Table id(" << table_id
160 << ") >= 2 is invalid for baseline profile";
161 return false;
162 }
163
164 JpegHuffmanTable* table;
165 if (table_class == 1)
166 table = &result->ac_table[table_id];
167 else
168 table = &result->dc_table[table_id];
169
170 size_t count = 0;
171 if (!reader.ReadBytes(&table->code_length, sizeof(table->code_length)))
172 return false;
173 for (size_t i = 0; i < arraysize(table->code_length); i++)
174 count += table->code_length[i];
175
176 IN_RANGE_OR_RETURN_FALSE(count, 0, sizeof(table->code_value));
177 if (!reader.ReadBytes(&table->code_value, count))
178 return false;
179 table->valid = true;
180 }
181 return true;
182 }
183
184 bool JpegParser::ParseDRI(const char* buffer,
185 size_t length,
186 JpegParseResult* result) {
187 // Spec B.2.4.4 Restart interval definition syntax
188 DCHECK(buffer);
189 DCHECK(result);
190 BigEndianReader reader(buffer, length);
191 return reader.ReadU16(&result->restart_interval) && reader.remaining() == 0;
192 }
193
194 bool JpegParser::ParseSOS(const char* buffer,
195 size_t length,
196 JpegParseResult* result) {
197 // Spec B.2.3 Scan header syntax
198 DCHECK(buffer);
199 DCHECK(result);
200 BigEndianReader reader(buffer, length);
201 READ_U8_OR_RETURN_FALSE(&result->scan.num_components);
202 if (result->scan.num_components != result->num_components) {
203 DLOG(ERROR) << "The number of scan components ("
204 << static_cast<int>(result->scan.num_components)
205 << ") mismatches the number of image components ("
206 << static_cast<int>(result->num_components) << ")";
207 return false;
208 }
209
210 for (int i = 0; i < result->scan.num_components; i++) {
211 JpegScan::Component* component = &result->scan.components[i];
212 READ_U8_OR_RETURN_FALSE(&component->component_selector);
213 uint8_t tmp;
214 READ_U8_OR_RETURN_FALSE(&tmp);
215 component->dc_selector = tmp / 16;
216 component->ac_selector = tmp % 16;
217 if (component->component_selector != result->components[i].id) {
218 DLOG(ERROR) << "component selector mismatches image component id";
219 return false;
220 }
221 if (component->dc_selector >= kJpegMaxHuffmanTableNum_baseline) {
222 DLOG(ERROR) << "DC selector (" << static_cast<int>(component->dc_selector)
223 << ") should be 0 or 1 for baseline mode";
224 return false;
225 }
226 if (component->ac_selector >= kJpegMaxHuffmanTableNum_baseline) {
227 DLOG(ERROR) << "AC selector (" << static_cast<int>(component->ac_selector)
228 << ") should be 0 or 1 for baseline mode";
229 return false;
230 }
231 }
232
233 // Unused fields, only for value checking.
234 uint8_t spectral_selection_start;
235 uint8_t spectral_selection_end;
236 uint8_t point_transform;
237 READ_U8_OR_RETURN_FALSE(&spectral_selection_start);
238 READ_U8_OR_RETURN_FALSE(&spectral_selection_end);
239 READ_U8_OR_RETURN_FALSE(&point_transform);
240 if (spectral_selection_start != 0 || spectral_selection_end != 63) {
241 DLOG(ERROR) << "Spectral selection should be 0,63 for baseline mode";
242 return false;
243 }
244 if (point_transform != 0) {
245 DLOG(ERROR) << "Point transform should be 0 for baseline mode";
246 return false;
247 }
248
249 return true;
250 }
251
252 bool JpegParser::ParseSOI(const char* buffer,
253 size_t length,
254 JpegParseResult* result) {
255 // Spec B.2.1 High-level syntax
256 DCHECK(buffer);
257 DCHECK(result);
258 BigEndianReader reader(buffer, length);
259 uint8_t marker1;
260 uint8_t marker2;
261 bool has_marker_dqt = false;
262 bool has_marker_sos = false;
263
264 // Once reached SOS, all neccesary data are parsed.
265 while (!has_marker_sos) {
266 READ_U8_OR_RETURN_FALSE(&marker1);
267 if (marker1 != MARKER1)
268 return false;
269
270 do {
271 READ_U8_OR_RETURN_FALSE(&marker2);
272 } while (marker2 == MARKER1); // skip fill bytes
273
274 uint16_t size;
275 READ_U16_OR_RETURN_FALSE(&size);
276 if (reader.remaining() < size) {
277 DLOG(ERROR) << "Ill-formed JPEG. Remaining size (" << reader.remaining()
278 << ") is smaller than header specified (" << size << ")";
279 return false;
280 }
281
282 // The size includes the size field itself.
283 if (size < sizeof(size)) {
284 DLOG(ERROR) << "Ill-formed JPEG. Segment size (" << size
285 << ") is smaller than size field (" << sizeof(size) << ")";
286 return false;
287 }
288 size -= sizeof(size);
289
290 switch (marker2) {
291 case SOF0:
292 if (!ParseSOF(reader.ptr(), size, result)) {
293 DLOG(ERROR) << "ParseSOF failed";
294 return false;
295 }
296 break;
297 case DQT:
298 if (!ParseDQT(reader.ptr(), size, result)) {
299 DLOG(ERROR) << "ParseDQT failed";
300 return false;
301 }
302 has_marker_dqt = true;
303 break;
304 case DHT:
305 if (!ParseDHT(reader.ptr(), size, result)) {
306 DLOG(ERROR) << "ParseDHT failed";
307 return false;
308 }
309 break;
310 case DRI:
311 if (!ParseDRI(reader.ptr(), size, result)) {
312 DLOG(ERROR) << "ParseDRI failed";
313 return false;
314 }
315 break;
316 case SOS:
317 if (!ParseSOS(reader.ptr(), size, result)) {
318 DLOG(ERROR) << "ParseSOS failed";
319 return false;
320 }
321 has_marker_sos = true;
322 break;
323 default:
324 DVLOG(4) << "unknown marker " << static_cast<int>(marker2);
325 break;
326 }
327 reader.Skip(size);
328 }
329
330 if (!has_marker_dqt) {
331 DLOG(ERROR) << "No DQT marker found";
332 return false;
333 }
334
335 // Scan data follows scan header immediately.
336 result->scan.data = reinterpret_cast<const uint8_t*>(reader.ptr());
337 result->scan.data_size = reader.remaining();
338
339 return true;
340 }
341
342 bool JpegParser::Parse(const uint8_t* buffer,
343 size_t length,
344 JpegParseResult* result) {
345 DCHECK(buffer);
346 DCHECK(result);
347 BigEndianReader reader(reinterpret_cast<const char*>(buffer), length);
348 memset(result, 0, sizeof(JpegParseResult));
349
350 uint8_t marker1, marker2;
351 READ_U8_OR_RETURN_FALSE(&marker1);
352 READ_U8_OR_RETURN_FALSE(&marker2);
353 if (marker1 != MARKER1 || marker2 != SOI) {
354 LOG(ERROR) << "Not a JPEG";
355 return false;
356 }
357
358 return ParseSOI(reader.ptr(), reader.remaining(), result);
359 }
360
361 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698