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

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 6 years 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 namespace content {
11
12 VaapiJpegParser::VaapiJpegParser(const uint8_t* buffer, size_t length)
13 : buffer_(buffer), length_(length) {
14 }
15
16 VaapiJpegParser::~VaapiJpegParser() {
17 }
18
19 bool VaapiJpegParser::ParseSOF(BigEndianReader reader) {
20 // Spec B.2.2 Frame header syntax
21 uint8_t precision;
22
23 if (!reader.ReadU8(&precision))
24 return false;
25 if (!reader.ReadU16(&result_.visible_height))
26 return false;
27 if (!reader.ReadU16(&result_.visible_width))
28 return false;
29 if (!reader.ReadU8(&result_.num_component))
30 return false;
31
32 if (precision != 8) {
33 DLOG(ERROR) << "Only support 8 bit precision, not "
34 << static_cast<int>(precision) << " bit";
35 return false;
36 }
37 if (result_.num_component != 3 ||
wuchengli 2014/12/17 09:03:02 Follow the (read) order of precesion, width/height
kcwu 2014/12/24 11:32:37 Done.
38 result_.num_component >= arraysize(result_.components)) {
39 DLOG(ERROR) << "num_component=" << static_cast<int>(result_.num_component)
40 << " is not supported";
41 return false;
42 }
43
44 // Size 64k*64k is the maximum in the JPEG standard. VAAPI doesn't support
45 // larger than
46 // 16k*16k.
wuchengli 2014/12/17 09:03:02 combine with the previous line
kcwu 2014/12/24 11:32:37 Done.
47 if (result_.visible_height > 16384 || result_.visible_width > 16384) {
48 DLOG(ERROR) << "VAAPI don't support size(" << result_.visible_width << "*"
49 << result_.visible_height << ") larger than 16k*16k";
50 return false;
51 }
52
53 for (int i = 0; i < result_.num_component; i++) {
54 JpegComponent& component = result_.components[i];
55 if (!reader.ReadU8(&component.id))
56 return false;
57 if (component.id > result_.num_component) {
58 DLOG(ERROR) << "component id (" << static_cast<int>(component.id)
59 << ") should be <= num_component ("
60 << static_cast<int>(result_.num_component) << ")";
61 return false;
62 }
63 uint8_t hv;
64 if (!reader.ReadU8(&hv))
65 return false;
66 component.horizontal_sampling_factor = hv / 16;
67 component.vertical_sampling_factor = hv % 16;
68 if (!reader.ReadU8(&component.quantization_table_selector))
69 return false;
70 }
71
72 if (result_.components[0].horizontal_sampling_factor <
73 result_.components[1].horizontal_sampling_factor ||
74 result_.components[0].horizontal_sampling_factor <
75 result_.components[2].horizontal_sampling_factor) {
76 DLOG(ERROR) << "VAAPI don't supports horizontal sampling factor of Y"
77 << " smaller than Cb and Cr";
78 return false;
79 }
80 if (result_.components[0].vertical_sampling_factor <
81 result_.components[1].vertical_sampling_factor ||
82 result_.components[0].vertical_sampling_factor <
83 result_.components[2].vertical_sampling_factor) {
84 DLOG(ERROR) << "VAAPI don't supports vertical sampling factor of Y"
85 << " smaller than Cb and Cr";
86 return false;
87 }
88
89 return true;
90 }
91
92 bool VaapiJpegParser::ParseDQT(BigEndianReader reader) {
93 // Spec B.2.4.1 Quantization table-specification syntax
94 while (reader.remaining() > 0) {
95 uint8_t tmp;
96 if (!reader.ReadU8(&tmp))
97 return false;
98 uint8_t precision = tmp / 16;
99 uint8_t table_id = tmp % 16;
100 if (precision != 0) {
101 DLOG(ERROR) << "16 bits quantization table is not supported";
102 return false;
103 }
104 if (table_id >= kJpegQuantizationTableNum)
wuchengli 2014/12/17 09:03:02 add a DLOG
kcwu 2014/12/24 11:32:37 Done.
105 return false;
106
107 if (!reader.ReadBytes(&result_.q_table[table_id].value,
108 sizeof(result_.q_table[table_id].value)))
109 return false;
110 result_.q_table[table_id].valid = true;
111 }
112 return true;
113 }
114
115 bool VaapiJpegParser::ParseDHT(BigEndianReader reader) {
116 // Spec B.2.4.2 Huffman table-specification syntax
117 while (reader.remaining() > 0) {
118 uint8_t t;
wuchengli 2014/12/17 09:03:02 nit: s/t/tmp/ to be consistent with ParseDQT
kcwu 2014/12/24 11:32:37 Done.
119 if (!reader.ReadU8(&t))
120 return false;
121 int table_class = t / 16;
122 int table_id = t % 16;
123 if (table_class >= 2) {
124 DLOG(ERROR) << "Invalid table class: " << table_class;
125 return false;
126 }
127 if (table_id >= 2) {
128 DLOG(ERROR) << "Table id(" << table_id << ") >= 2 is invalid for "
129 "baseline profile";
130 return false;
131 }
132
133 JpegHuffmanTable* table;
134 if (table_class == 1)
135 table = &result_.ac_table[table_id];
136 else
137 table = &result_.dc_table[table_id];
138
139 size_t count = 0;
140 if (!reader.ReadBytes(&table->code_length, sizeof(table->code_length)))
141 return false;
142 for (size_t i = 0; i < arraysize(table->code_length); i++)
143 count += table->code_length[i];
144
145 if (count > sizeof(table->code_value)) {
146 DLOG(ERROR) << "Number of code values is invalid: " << count;
147 return false;
148 }
149 if (!reader.ReadBytes(&table->code_value, count))
150 return false;
151 table->valid = true;
152 }
153 return true;
154 }
155
156 bool VaapiJpegParser::ParseDRI(BigEndianReader reader) {
157 // Spec B.2.4.4 Restart interval definition syntax
158 return reader.ReadU16(&result_.restart_interval) && reader.remaining() == 0;
159 }
160
161 bool VaapiJpegParser::ParseSOS(BigEndianReader reader) {
162 // Spec B.2.3 Scan header syntax
163 if (!reader.ReadU8(&result_.scan.num_component))
164 return false;
165 if (result_.scan.num_component != result_.num_component) {
166 DLOG(ERROR) << "The number of scan components ("
167 << static_cast<int>(result_.scan.num_component)
168 << ") mismatches the number of image components ("
169 << static_cast<int>(result_.num_component) << ")";
170 return false;
171 }
172
173 for (int i = 0; i < result_.scan.num_component; i++) {
174 JpegScan::Component* component = &result_.scan.components[i];
175 if (!reader.ReadU8(&component->component_selector))
176 return false;
177 uint8_t tmp;
178 if (!reader.ReadU8(&tmp))
179 return false;
180 component->dc_selector = tmp / 16;
181 component->ac_selector = tmp % 16;
182 if (component->component_selector != result_.components[i].id) {
183 DLOG(ERROR) << "component selector mismatches image component id";
184 return false;
185 }
186 if (component->dc_selector >= kJpegHuffmanTableNum_baseline) {
187 DLOG(ERROR) << "DC selector (" << static_cast<int>(component->dc_selector)
188 << ") should be 0 or 1 for baseline mode";
189 return false;
190 }
191 if (component->ac_selector >= kJpegHuffmanTableNum_baseline) {
192 DLOG(ERROR) << "AC selector (" << static_cast<int>(component->ac_selector)
193 << ") should be 0 or 1 for baseline mode";
194 return false;
195 }
196 }
197
198 // unused fields, only for value checking
199 uint8_t spectral_selection_start;
200 uint8_t spectral_selection_end;
201 uint8_t point_transform;
202 if (!reader.ReadU8(&spectral_selection_start))
203 return false;
204 if (!reader.ReadU8(&spectral_selection_end))
205 return false;
206 if (!reader.ReadU8(&point_transform))
207 return false;
208 if (spectral_selection_start != 0 || spectral_selection_end != 63) {
209 DLOG(ERROR) << "Spectral selection should be 0,63 for baseline mode";
210 return false;
211 }
212 if (point_transform != 0) {
213 DLOG(ERROR) << "Point transform should be 0 for baseline mode";
214 return false;
215 }
216
217 return true;
218 }
219
220 bool VaapiJpegParser::ParseSOI(BigEndianReader reader) {
221 // Spec B.2.1 High-level syntax
222 uint8_t marker1;
223 uint8_t marker2;
224 bool has_marker_dqt = false;
225 bool has_marker_sos = false;
226
227 // Once reached SOS, all neccesary data are parsed.
228 while (!has_marker_sos) {
229 if (!reader.ReadU8(&marker1) || marker1 != MARKER1)
230 return false;
231
232 do {
233 if (!reader.ReadU8(&marker2))
234 return false;
235 } while (marker2 == MARKER1); // skip padding
wuchengli 2014/12/17 09:03:02 s/padding/fill bytes/ according to the spec.
kcwu 2014/12/24 11:32:37 Done.
236
237 uint16_t size;
238 if (!reader.ReadU16(&size))
239 return false;
240 if (reader.remaining() < size) {
241 DLOG(ERROR) << "Ill-formed JPEG. Remain size (" << reader.remaining()
wuchengli 2014/12/17 09:03:02 s/Remain/Remaining/
kcwu 2014/12/24 11:32:37 Done.
242 << ") is smaller than header specified (" << size << ")";
243 return false;
244 }
245
246 // The size includes the size field itself.
247 if (size < sizeof(size)) {
248 DLOG(ERROR) << "Ill-formed JPEG. Segment size (" << size
249 << ") is smaller than size field (" << sizeof(size) << ")";
250 return false;
251 }
252 size -= sizeof(size);
253
254 switch (marker2) {
255 case SOF0:
256 if (!ParseSOF(BigEndianReader(reader.ptr(), size))) {
257 DLOG(ERROR) << "ParseSOF failed";
258 return false;
259 }
260 break;
261 case DQT:
262 if (!ParseDQT(BigEndianReader(reader.ptr(), size))) {
263 DLOG(ERROR) << "ParseDQT failed";
264 return false;
265 }
266 has_marker_dqt = true;
267 break;
268 case DHT:
269 if (!ParseDHT(BigEndianReader(reader.ptr(), size))) {
270 DLOG(ERROR) << "ParseDHT failed";
271 return false;
272 }
273 break;
274 case DRI:
275 if (!ParseDRI(BigEndianReader(reader.ptr(), size))) {
276 DLOG(ERROR) << "ParseDRI failed";
277 return false;
278 }
279 break;
280 case SOS:
281 if (!ParseSOS(BigEndianReader(reader.ptr(), size))) {
282 DLOG(ERROR) << "ParseSOS failed";
283 return false;
284 }
285 has_marker_sos = true;
286 break;
287 default:
288 DVLOG(4) << "unknown marker " << static_cast<int>(marker2);
289 break;
290 }
291 reader.Skip(size);
292 }
293
294 if (!has_marker_dqt) {
295 DLOG(ERROR) << "No DQT marker found";
296 return false;
297 }
298
299 // Scan data follows scan header immediately.
300 result_.scan.data = reader.ptr();
301 result_.scan.data_size = reader.remaining();
302
303 return true;
304 }
305
306 const JpegParseResult* VaapiJpegParser::Parse() {
307 BigEndianReader reader(reinterpret_cast<const char*>(buffer_), length_);
308 memset(&result_, 0, sizeof(result_));
309
310 uint8_t marker1, marker2;
311 if (!reader.ReadU8(&marker1) || marker1 != MARKER1 ||
312 !reader.ReadU8(&marker2) || marker2 != SOI) {
313 LOG(ERROR) << "Not a JPEG";
314 return NULL;
315 }
316
317 if (ParseSOI(BigEndianReader(reader.ptr(), reader.remaining())))
318 return &result_;
319
320 return NULL;
321 }
322
323 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698