OLD | NEW |
---|---|
(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 | |
OLD | NEW |