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/big_endian.h" | |
wuchengli
2014/12/08 09:25:10
vaapi_jpeg_parser.h already includes this. remove
kcwu
2014/12/16 06:23:53
Done.
| |
6 #include "base/logging.h" | |
7 #include "content/common/gpu/media/vaapi_jpeg_parser.h" | |
8 | |
9 using base::BigEndianReader; | |
10 | |
11 namespace content { | |
12 | |
13 VaapiJpegParser::VaapiJpegParser(const uint8_t* buffer, size_t length) | |
14 : buffer_(buffer), length_(length) { | |
15 } | |
16 | |
17 VaapiJpegParser::~VaapiJpegParser() { | |
18 } | |
19 | |
20 bool VaapiJpegParser::ParseSOF(BigEndianReader reader) { | |
21 // Spec B.2.2 Frame header syntax | |
22 uint8_t precision; | |
23 | |
24 if (!reader.ReadU8(&precision)) | |
25 return false; | |
26 if (!reader.ReadU16(&result_.visible_height)) | |
27 return false; | |
28 if (!reader.ReadU16(&result_.visible_width)) | |
29 return false; | |
30 if (!reader.ReadU8(&result_.num_component)) | |
31 return false; | |
32 | |
33 if (precision != 8) { | |
34 DLOG(ERROR) << "Only support 8 bit precision"; | |
wuchengli
2014/12/08 09:25:11
print the actual precision
kcwu
2014/12/16 06:23:54
Done.
| |
35 return false; | |
36 } | |
37 if (result_.num_component != 3 || | |
38 result_.num_component >= arraysize(result_.components)) | |
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:53
Done.
| |
39 return false; | |
40 | |
41 // 64k*64k is max. in the JPEG standard. VAAPI doesn't support larger than | |
wuchengli
2014/12/08 09:25:10
s/max./the maximum/. s/64k*64k/Size 64k*64k/
kcwu
2014/12/16 06:23:53
Done.
| |
42 // 16k*16k. | |
43 if (result_.visible_height > 16384 || result_.visible_width > 16384) { | |
wuchengli
2014/12/08 09:25:10
Should 16384 come from va.h or somewhere else?
kcwu
2014/12/16 06:23:53
There is no contant from va.h for this. It's heard
| |
44 DLOG(ERROR) << "VAAPI don't support size larger than 16k*16k"; | |
wuchengli
2014/12/08 09:25:10
print the actual size
kcwu
2014/12/16 06:23:54
Done.
| |
45 return false; | |
46 } | |
47 | |
48 for (int i = 0; i < result_.num_component; i++) { | |
49 JpegComponent* component = &result_.components[i]; | |
wuchengli
2014/12/08 09:25:10
nit: use JpegComponent&?
kcwu
2014/12/16 06:23:53
Done.
| |
50 if (!reader.ReadU8(&component->id)) | |
51 return false; | |
52 if (component->id > result_.num_component) { | |
53 DLOG(ERROR) << "Only allow component id <= num_component: " | |
wuchengli
2014/12/08 09:25:11
Print both numbers at the end is not very clear. M
kcwu
2014/12/16 06:23:54
Done.
| |
54 << static_cast<int>(component->id) << "," | |
55 << static_cast<int>(result_.num_component); | |
56 return false; | |
57 } | |
58 uint8_t hv; | |
wuchengli
2014/12/08 09:25:10
Is hv a common Jpeg terminology? If not, use more
kcwu
2014/12/16 06:23:54
It's not so meaningful to give a name for this. Th
| |
59 if (!reader.ReadU8(&hv)) | |
60 return false; | |
61 component->horizontal_sampling_factor = hv / 16; | |
62 component->vertical_sampling_factor = hv % 16; | |
63 if (!reader.ReadU8(&component->quantization_table_selector)) | |
64 return false; | |
65 } | |
66 | |
67 if (result_.components[0].horizontal_sampling_factor < | |
68 result_.components[1].horizontal_sampling_factor || | |
69 result_.components[0].horizontal_sampling_factor < | |
70 result_.components[2].horizontal_sampling_factor) { | |
71 DLOG(ERROR) << "VAAPI don't supports horizontal sampling factor of Y" | |
72 << " smaller than Cb and Cr"; | |
73 return false; | |
74 } | |
75 if (result_.components[0].vertical_sampling_factor < | |
76 result_.components[1].vertical_sampling_factor || | |
77 result_.components[0].vertical_sampling_factor < | |
78 result_.components[2].vertical_sampling_factor) { | |
79 DLOG(ERROR) << "VAAPI don't supports vertical sampling factor of Y" | |
80 << " smaller than Cb and Cr"; | |
81 return false; | |
82 } | |
83 | |
84 return true; | |
85 } | |
86 | |
87 bool VaapiJpegParser::ParseDQT(BigEndianReader reader) { | |
88 // Spec B.2.4.1 Quantization table-specification syntax | |
89 while (reader.remaining() > 0) { | |
90 uint8_t tmp; | |
91 if (!reader.ReadU8(&tmp)) | |
92 return false; | |
93 uint8_t precision = tmp / 16; | |
94 uint8_t table_id = tmp % 16; | |
95 if (precision != 0) { | |
96 DLOG(ERROR) << "16 bits quantization table is not supported"; | |
97 return false; | |
98 } | |
99 if (table_id >= kJpegQuantizationTableNum) | |
100 return false; | |
101 | |
102 if (!reader.ReadBytes(&result_.q_table[table_id].value, | |
103 sizeof(result_.q_table[table_id].value))) | |
104 return false; | |
105 result_.q_table[table_id].valid = true; | |
106 } | |
107 return true; | |
108 } | |
109 | |
110 bool VaapiJpegParser::ParseDHT(BigEndianReader reader) { | |
111 // Spec B.2.4.2 Huffman table-specification syntax | |
112 while (reader.remaining() > 0) { | |
113 uint8_t t; | |
114 if (!reader.ReadU8(&t)) | |
115 return false; | |
116 int table_class = t / 16; | |
117 int table_id = t % 16; | |
118 if (table_class >= 2) // invalid | |
wuchengli
2014/12/08 09:25:10
Add DLOG. Add DLOG for all non reader.ReadU8 failu
kcwu
2014/12/16 06:23:54
Done.
| |
119 return false; | |
120 if (table_id >= 2) // only support baseline | |
wuchengli
2014/12/08 09:25:10
Add DLOG
kcwu
2014/12/16 06:23:54
Done.
| |
121 return false; | |
122 | |
123 bool is_ac_table = (table_class == 1); | |
124 JpegHuffmanTable* table; | |
125 if (is_ac_table) | |
wuchengli
2014/12/08 09:25:10
just use table_class == 1 here?
kcwu
2014/12/16 06:23:54
Done.
| |
126 table = &result_.ac_table[table_id]; | |
127 else | |
128 table = &result_.dc_table[table_id]; | |
129 | |
130 size_t count = 0; | |
131 if (!reader.ReadBytes(&table->code_length, sizeof(table->code_length))) | |
132 return false; | |
133 for (unsigned i = 0; i < arraysize(table->code_length); i++) | |
wuchengli
2014/12/08 09:25:10
s/unsigned/size_t/
kcwu
2014/12/16 06:23:53
Done.
| |
134 count += table->code_length[i]; | |
135 | |
136 if (count > sizeof(table->code_value)) | |
wuchengli
2014/12/08 09:25:11
add DLOG
kcwu
2014/12/16 06:23:53
Done.
| |
137 return false; | |
138 if (!reader.ReadBytes(&table->code_value, count)) | |
139 return false; | |
140 table->valid = true; | |
141 } | |
142 return true; | |
143 } | |
144 | |
145 bool VaapiJpegParser::ParseDRI(BigEndianReader reader) { | |
146 // Spec B.2.4.4 Restart interval definition syntax | |
147 return reader.ReadU16(&result_.restart_interval) && reader.remaining() == 0; | |
148 } | |
149 | |
150 bool VaapiJpegParser::ParseSOS(BigEndianReader reader) { | |
151 // Spec B.2.3 Scan header syntax | |
152 if (!reader.ReadU8(&result_.scan.num_component)) | |
153 return false; | |
154 if (result_.scan.num_component != result_.num_component) | |
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
| |
155 return false; | |
156 | |
157 for (int i = 0; i < result_.scan.num_component; i++) { | |
158 JpegScan::Component* component = &result_.scan.components[i]; | |
159 if (!reader.ReadU8(&component->component_selector)) | |
160 return false; | |
161 uint8_t tmp; | |
162 if (!reader.ReadU8(&tmp)) | |
163 return false; | |
164 component->dc_selector = tmp / 16; | |
165 component->ac_selector = tmp % 16; | |
166 if (component->component_selector != result_.components[i].id) | |
167 return false; | |
168 if (component->dc_selector >= kJpegHuffmanTableNum) | |
169 return false; | |
170 if (component->ac_selector >= kJpegHuffmanTableNum) | |
171 return false; | |
172 } | |
173 | |
174 // unused fields, only for value checking | |
175 uint8_t spectral_selection_start; | |
176 uint8_t spectral_selection_end; | |
177 uint8_t point_transform; | |
178 if (!reader.ReadU8(&spectral_selection_start)) | |
179 return false; | |
180 if (!reader.ReadU8(&spectral_selection_end)) | |
181 return false; | |
182 if (!reader.ReadU8(&point_transform)) | |
183 return false; | |
184 if (spectral_selection_start != 0 || spectral_selection_end != 63) { | |
185 DLOG(ERROR) << "Spectral selection should be 0,63 for baseline mode"; | |
186 return false; | |
187 } | |
188 if (point_transform != 0) { | |
189 DLOG(ERROR) << "Point transform should be 0 for baseline mode"; | |
190 return false; | |
191 } | |
192 | |
193 return true; | |
194 } | |
195 | |
196 bool VaapiJpegParser::ParseSOI(BigEndianReader reader) { | |
197 // Spec B.2.1 High-level syntax | |
198 uint8_t marker1; | |
199 uint8_t marker2; | |
200 bool has_marker_dqt = false; | |
201 bool has_marker_sos = false; | |
202 | |
203 // Once reached SOS, all neccesary data are parsed. | |
204 while (!has_marker_sos) { | |
205 if (!reader.ReadU8(&marker1) || marker1 != MARKER1) | |
206 return false; | |
207 | |
208 do { | |
209 if (!reader.ReadU8(&marker2)) | |
210 return false; | |
211 } while (marker2 == MARKER1); // skip padding | |
212 | |
213 uint16_t size; | |
214 if (!reader.ReadU16(&size)) | |
215 return false; | |
216 if (reader.remaining() < size) | |
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
| |
217 return false; | |
218 | |
219 // The size includes the size field itself. | |
220 if (size < sizeof(size)) | |
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
| |
221 return false; | |
222 size -= sizeof(size); | |
223 | |
224 switch (marker2) { | |
225 case SOF0: | |
226 if (!ParseSOF(BigEndianReader(reader.ptr(), size))) { | |
227 DLOG(ERROR) << "ParseSOF failed"; | |
228 return false; | |
229 } | |
230 break; | |
231 case DQT: | |
232 if (!ParseDQT(BigEndianReader(reader.ptr(), size))) { | |
233 DLOG(ERROR) << "ParseDQT failed"; | |
234 return false; | |
235 } | |
236 has_marker_dqt = true; | |
237 break; | |
238 case DHT: | |
239 if (!ParseDHT(BigEndianReader(reader.ptr(), size))) { | |
240 DLOG(ERROR) << "ParseDHT failed"; | |
241 return false; | |
242 } | |
243 break; | |
244 case DRI: | |
245 if (!ParseDRI(BigEndianReader(reader.ptr(), size))) { | |
246 DLOG(ERROR) << "ParseDRI failed"; | |
247 return false; | |
248 } | |
249 break; | |
250 case SOS: | |
251 if (!ParseSOS(BigEndianReader(reader.ptr(), size))) { | |
252 DLOG(ERROR) << "ParseSOS failed"; | |
253 return false; | |
254 } | |
255 has_marker_sos = true; | |
256 break; | |
257 default: | |
258 DVLOG(4) << "unknown marker " << static_cast<int>(marker2); | |
wuchengli
2014/12/08 09:25:10
Why do we need this cast?
kcwu
2014/12/16 06:23:53
marker2 is char. It will print the character if no
| |
259 break; | |
260 } | |
261 reader.Skip(size); | |
262 } | |
263 | |
264 if (!has_marker_dqt) { | |
265 DLOG(ERROR) << "No DQT marker found"; | |
266 return false; | |
267 } | |
268 | |
269 // Scan data is following scan header immediately. | |
wuchengli
2014/12/08 09:25:11
s/is following/follows/
kcwu
2014/12/16 06:23:54
Done.
| |
270 result_.scan.data = reader.ptr(); | |
271 result_.scan.data_size = reader.remaining(); | |
272 | |
273 return true; | |
274 } | |
275 | |
276 bool VaapiJpegParser::Parse() { | |
277 BigEndianReader reader(reinterpret_cast<const char*>(buffer_), length_); | |
278 memset(&result_, 0, sizeof(result_)); | |
279 | |
280 uint8_t marker1; | |
281 uint8_t marker2; | |
wuchengli
2014/12/08 09:25:10
nit: combine with the previous line
kcwu
2014/12/16 06:23:53
Done.
| |
282 if (!reader.ReadU8(&marker1) || marker1 != MARKER1 || | |
283 !reader.ReadU8(&marker2) || marker2 != SOI) { | |
284 LOG(ERROR) << "Not a JPEG"; | |
285 return false; | |
286 } | |
287 | |
288 return ParseSOI(BigEndianReader(reader.ptr(), reader.remaining())); | |
289 } | |
290 | |
291 } // namespace content | |
OLD | NEW |