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

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

Powered by Google App Engine
This is Rietveld 408576698