1 // Copyright 2015 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 "media/parsers/jpeg_parser.h"
6
7 #include "base/big_endian.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10
11 using base::BigEndianReader;
12
13 #define READ_U8_OR_RETURN_FALSE(out) \
14 do { \
15 uint8_t _out; \
16 if (!reader.ReadU8(&_out)) { \
17 DVLOG(1) \
18 << "Error in stream: unexpected EOS while trying to read " #out; \
19 return false; \
20 } \
21 *(out) = _out; \
22 } while (0)
23
24 #define READ_U16_OR_RETURN_FALSE(out) \
25 do { \
26 uint16_t _out; \
27 if (!reader.ReadU16(&_out)) { \
28 DVLOG(1) \
29 << "Error in stream: unexpected EOS while trying to read " #out; \
30 return false; \
31 } \
32 *(out) = _out; \
33 } while (0)
34
35 namespace media {
36
37 const JpegHuffmanTable kDefaultDcTable[kJpegMaxHuffmanTableNumBaseline] = {
38 // luminance DC coefficients
39 {
40 true,
41 {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
42 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
43 0x0b},
44 },
45 // chrominance DC coefficients
46 {
47 true,
48 {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
49 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb},
50 },
51 };
52
53 const JpegHuffmanTable kDefaultAcTable[kJpegMaxHuffmanTableNumBaseline] = {
54 // luminance AC coefficients
55 {
56 true,
57 {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d},
58 {0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,
59 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
60 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
61 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
62 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
63 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
64 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,
65 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
66 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
67 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
68 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
69 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
70 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,
71 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa},
72 },
73 // chrominance AC coefficients
74 {
75 true,
76 {0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77},
77 {0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
78 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
79 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
80 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
81 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
82 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
83 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
84 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
85 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
86 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
87 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
88 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
89 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
90 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa},
91 },
92 };
93
94 const uint8_t kZigZag8x8[64] = {
95 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
96 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
97 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
98 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63};
99
100 const JpegQuantizationTable kDefaultQuantTable[2] = {
101 // Table K.1 Luminance quantization table values.
102 {
103 true,
104 {16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55,
105 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62,
106 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92,
107 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99},
108 },
109 // Table K.2 Chrominance quantization table values.
110 {
111 true,
112 {17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99,
113 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99,
114 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
115 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
116 },
117 };
118
InRange(int value,int a,int b)119 static bool InRange(int value, int a, int b) {
120 return a <= value && value <= b;
121 }
122
123 // Round up |value| to multiple of |mul|. |value| must be non-negative.
124 // |mul| must be positive.
RoundUp(int value,int mul)125 static int RoundUp(int value, int mul) {
126 DCHECK_GE(value, 0);
127 DCHECK_GE(mul, 1);
128 return (value + mul - 1) / mul * mul;
129 }
130
131 // |frame_header| is already initialized to 0 in ParseJpegPicture.
ParseSOF(const char * buffer,size_t length,JpegFrameHeader * frame_header)132 static bool ParseSOF(const char* buffer,
133 size_t length,
134 JpegFrameHeader* frame_header) {
135 // Spec B.2.2 Frame header syntax
136 DCHECK(buffer);
137 DCHECK(frame_header);
138 BigEndianReader reader(buffer, length);
139
140 uint8_t precision;
141 READ_U8_OR_RETURN_FALSE(&precision);
142 READ_U16_OR_RETURN_FALSE(&frame_header->visible_height);
143 READ_U16_OR_RETURN_FALSE(&frame_header->visible_width);
144 READ_U8_OR_RETURN_FALSE(&frame_header->num_components);
145
146 if (precision != 8) {
147 DLOG(ERROR) << "Only support 8-bit precision, not "
148 << static_cast<int>(precision) << " bit for baseline";
149 return false;
150 }
151 if (!InRange(frame_header->num_components, 1,
152 base::size(frame_header->components))) {
153 DLOG(ERROR) << "num_components="
154 << static_cast<int>(frame_header->num_components)
155 << " is not supported";
156 return false;
157 }
158
159 int max_h_factor = 0;
160 int max_v_factor = 0;
161 for (size_t i = 0; i < frame_header->num_components; i++) {
162 JpegComponent& component = frame_header->components[i];
163 READ_U8_OR_RETURN_FALSE(&component.id);
164 if (component.id > frame_header->num_components) {
165 DLOG(ERROR) << "component id (" << static_cast<int>(component.id)
166 << ") should be <= num_components ("
167 << static_cast<int>(frame_header->num_components) << ")";
168 return false;
169 }
170 uint8_t hv;
171 READ_U8_OR_RETURN_FALSE(&hv);
172 component.horizontal_sampling_factor = hv / 16;
173 component.vertical_sampling_factor = hv % 16;
174 if (component.horizontal_sampling_factor > max_h_factor)
175 max_h_factor = component.horizontal_sampling_factor;
176 if (component.vertical_sampling_factor > max_v_factor)
177 max_v_factor = component.vertical_sampling_factor;
178 if (!InRange(component.horizontal_sampling_factor, 1, 4)) {
179 DVLOG(1) << "Invalid horizontal sampling factor "
180 << static_cast<int>(component.horizontal_sampling_factor);
181 return false;
182 }
183 if (!InRange(component.vertical_sampling_factor, 1, 4)) {
184 DVLOG(1) << "Invalid vertical sampling factor "
185 << static_cast<int>(component.horizontal_sampling_factor);
186 return false;
187 }
188 READ_U8_OR_RETURN_FALSE(&component.quantization_table_selector);
189 }
190
191 // The size of data unit is 8*8 and the coded size should be extended
192 // to complete minimum coded unit, MCU. See Spec A.2.
193 frame_header->coded_width =
194 RoundUp(frame_header->visible_width, max_h_factor * 8);
195 frame_header->coded_height =
196 RoundUp(frame_header->visible_height, max_v_factor * 8);
197
198 return true;
199 }
200
201 // |q_table| is already initialized to 0 in ParseJpegPicture.
ParseDQT(const char * buffer,size_t length,JpegQuantizationTable * q_table)202 static bool ParseDQT(const char* buffer,
203 size_t length,
204 JpegQuantizationTable* q_table) {
205 // Spec B.2.4.1 Quantization table-specification syntax
206 DCHECK(buffer);
207 DCHECK(q_table);
208 BigEndianReader reader(buffer, length);
209 while (reader.remaining() > 0) {
210 uint8_t precision_and_table_id;
211 READ_U8_OR_RETURN_FALSE(&precision_and_table_id);
212 uint8_t precision = precision_and_table_id / 16;
213 uint8_t table_id = precision_and_table_id % 16;
214 if (!InRange(precision, 0, 1)) {
215 DVLOG(1) << "Invalid precision " << static_cast<int>(precision);
216 return false;
217 }
218 if (precision == 1) { // 1 means 16-bit precision
219 DLOG(ERROR) << "An 8-bit DCT-based process shall not use a 16-bit "
220 << "precision quantization table";
221 return false;
222 }
223 if (table_id >= kJpegMaxQuantizationTableNum) {
224 DLOG(ERROR) << "Quantization table id (" << static_cast<int>(table_id)
225 << ") exceeded " << kJpegMaxQuantizationTableNum;
226 return false;
227 }
228
229 if (!reader.ReadBytes(&q_table[table_id].value,
230 sizeof(q_table[table_id].value)))
231 return false;
232 q_table[table_id].valid = true;
233 }
234 return true;
235 }
236
237 // |dc_table| and |ac_table| are already initialized to 0 in ParseJpegPicture.
ParseDHT(const char * buffer,size_t length,JpegHuffmanTable * dc_table,JpegHuffmanTable * ac_table)238 static bool ParseDHT(const char* buffer,
239 size_t length,
240 JpegHuffmanTable* dc_table,
241 JpegHuffmanTable* ac_table) {
242 // Spec B.2.4.2 Huffman table-specification syntax
243 DCHECK(buffer);
244 DCHECK(dc_table);
245 DCHECK(ac_table);
246 BigEndianReader reader(buffer, length);
247 while (reader.remaining() > 0) {
248 uint8_t table_class_and_id;
249 READ_U8_OR_RETURN_FALSE(&table_class_and_id);
250 int table_class = table_class_and_id / 16;
251 int table_id = table_class_and_id % 16;
252 if (!InRange(table_class, 0, 1)) {
253 DVLOG(1) << "Invalid table class " << table_class;
254 return false;
255 }
256 if (table_id >= 2) {
257 DLOG(ERROR) << "Table id(" << table_id
258 << ") >= 2 is invalid for baseline profile";
259 return false;
260 }
261
262 JpegHuffmanTable* table;
263 if (table_class == 1)
264 table = &ac_table[table_id];
265 else
266 table = &dc_table[table_id];
267
268 size_t count = 0;
269 if (!reader.ReadBytes(&table->code_length, sizeof(table->code_length)))
270 return false;
271 for (size_t i = 0; i < base::size(table->code_length); i++)
272 count += table->code_length[i];
273
274 if (!InRange(count, 0, sizeof(table->code_value))) {
275 DVLOG(1) << "Invalid code count " << count;
276 return false;
277 }
278 if (!reader.ReadBytes(&table->code_value, count))
279 return false;
280 table->valid = true;
281 }
282 return true;
283 }
284
ParseDRI(const char * buffer,size_t length,uint16_t * restart_interval)285 static bool ParseDRI(const char* buffer,
286 size_t length,
287 uint16_t* restart_interval) {
288 // Spec B.2.4.4 Restart interval definition syntax
289 DCHECK(buffer);
290 DCHECK(restart_interval);
291 BigEndianReader reader(buffer, length);
292 return reader.ReadU16(restart_interval) && reader.remaining() == 0;
293 }
294
295 // |scan| is already initialized to 0 in ParseJpegPicture.
ParseSOS(const char * buffer,size_t length,const JpegFrameHeader & frame_header,JpegScanHeader * scan)296 static bool ParseSOS(const char* buffer,
297 size_t length,
298 const JpegFrameHeader& frame_header,
299 JpegScanHeader* scan) {
300 // Spec B.2.3 Scan header syntax
301 DCHECK(buffer);
302 DCHECK(scan);
303 BigEndianReader reader(buffer, length);
304 READ_U8_OR_RETURN_FALSE(&scan->num_components);
305 if (scan->num_components != frame_header.num_components) {
306 DLOG(ERROR) << "The number of scan components ("
307 << static_cast<int>(scan->num_components)
308 << ") mismatches the number of image components ("
309 << static_cast<int>(frame_header.num_components) << ")";
310 return false;
311 }
312
313 for (int i = 0; i < scan->num_components; i++) {
314 JpegScanHeader::Component* component = &scan->components[i];
315 READ_U8_OR_RETURN_FALSE(&component->component_selector);
316 uint8_t dc_and_ac_selector;
317 READ_U8_OR_RETURN_FALSE(&dc_and_ac_selector);
318 component->dc_selector = dc_and_ac_selector / 16;
319 component->ac_selector = dc_and_ac_selector % 16;
320 if (component->component_selector != frame_header.components[i].id) {
321 DLOG(ERROR) << "component selector mismatches image component id";
322 return false;
323 }
324 if (component->dc_selector >= kJpegMaxHuffmanTableNumBaseline) {
325 DLOG(ERROR) << "DC selector (" << static_cast<int>(component->dc_selector)
326 << ") should be 0 or 1 for baseline mode";
327 return false;
328 }
329 if (component->ac_selector >= kJpegMaxHuffmanTableNumBaseline) {
330 DLOG(ERROR) << "AC selector (" << static_cast<int>(component->ac_selector)
331 << ") should be 0 or 1 for baseline mode";
332 return false;
333 }
334 }
335
336 // Unused fields, only for value checking.
337 uint8_t spectral_selection_start;
338 uint8_t spectral_selection_end;
339 uint8_t point_transform;
340 READ_U8_OR_RETURN_FALSE(&spectral_selection_start);
341 READ_U8_OR_RETURN_FALSE(&spectral_selection_end);
342 READ_U8_OR_RETURN_FALSE(&point_transform);
343 if (spectral_selection_start != 0 || spectral_selection_end != 63) {
344 DLOG(ERROR) << "Spectral selection should be 0,63 for baseline mode";
345 return false;
346 }
347 if (point_transform != 0) {
348 DLOG(ERROR) << "Point transform should be 0 for baseline mode";
349 return false;
350 }
351
352 return true;
353 }
354
355 // |eoi_begin_ptr| will point to the beginning of the EOI marker (the FF byte)
356 // and |eoi_end_ptr| will point to the end of image (right after the end of the
357 // EOI marker) after search succeeds. Returns true on EOI marker found, or false
358 // otherwise.
SearchEOI(const char * buffer,size_t length,const char ** eoi_begin_ptr,const char ** eoi_end_ptr)359 static bool SearchEOI(const char* buffer,
360 size_t length,
361 const char** eoi_begin_ptr,
362 const char** eoi_end_ptr) {
363 DCHECK(buffer);
364 DCHECK(eoi_begin_ptr);
365 DCHECK(eoi_end_ptr);
366 BigEndianReader reader(buffer, length);
367 uint8_t marker2;
368
369 while (reader.remaining() > 0) {
370 const char* marker1_ptr = static_cast<const char*>(
371 memchr(reader.ptr(), JPEG_MARKER_PREFIX, reader.remaining()));
372 if (!marker1_ptr)
373 return false;
374 reader.Skip(marker1_ptr - reader.ptr() + 1);
375
376 do {
377 READ_U8_OR_RETURN_FALSE(&marker2);
378 } while (marker2 == JPEG_MARKER_PREFIX); // skip fill bytes
379
380 switch (marker2) {
381 // Compressed data escape.
382 case 0x00:
383 break;
384 // Restart
385 case JPEG_RST0:
386 case JPEG_RST1:
387 case JPEG_RST2:
388 case JPEG_RST3:
389 case JPEG_RST4:
390 case JPEG_RST5:
391 case JPEG_RST6:
392 case JPEG_RST7:
393 break;
394 case JPEG_EOI:
395 *eoi_begin_ptr = marker1_ptr;
396 *eoi_end_ptr = reader.ptr();
397 return true;
398 default:
399 // Skip for other markers.
400 uint16_t size;
401 READ_U16_OR_RETURN_FALSE(&size);
402 if (size < sizeof(size)) {
403 DLOG(ERROR) << "Ill-formed JPEG. Segment size (" << size
404 << ") is smaller than size field (" << sizeof(size)
405 << ")";
406 return false;
407 }
408 size -= sizeof(size);
409
410 if (!reader.Skip(size)) {
411 DLOG(ERROR) << "Ill-formed JPEG. Remaining size ("
412 << reader.remaining()
413 << ") is smaller than header specified (" << size << ")";
414 return false;
415 }
416 break;
417 }
418 }
419 return false;
420 }
421
422 // |result| is already initialized to 0 in ParseJpegPicture.
ParseSOI(const char * buffer,size_t length,JpegParseResult * result)423 static bool ParseSOI(const char* buffer,
424 size_t length,
425 JpegParseResult* result) {
426 // Spec B.2.1 High-level syntax
427 DCHECK(buffer);
428 DCHECK(result);
429 BigEndianReader reader(buffer, length);
430 uint8_t marker1;
431 uint8_t marker2;
432 bool has_marker_dqt = false;
433 bool has_marker_sos = false;
434
435 // Once reached SOS, all neccesary data are parsed.
436 while (!has_marker_sos) {
437 READ_U8_OR_RETURN_FALSE(&marker1);
438 if (marker1 != JPEG_MARKER_PREFIX)
439 return false;
440
441 do {
442 READ_U8_OR_RETURN_FALSE(&marker2);
443 } while (marker2 == JPEG_MARKER_PREFIX); // skip fill bytes
444
445 uint16_t size;
446 READ_U16_OR_RETURN_FALSE(&size);
447 // The size includes the size field itself.
448 if (size < sizeof(size)) {
449 DLOG(ERROR) << "Ill-formed JPEG. Segment size (" << size
450 << ") is smaller than size field (" << sizeof(size) << ")";
451 return false;
452 }
453 size -= sizeof(size);
454
455 if (reader.remaining() < size) {
456 DLOG(ERROR) << "Ill-formed JPEG. Remaining size (" << reader.remaining()
457 << ") is smaller than header specified (" << size << ")";
458 return false;
459 }
460
461 switch (marker2) {
462 case JPEG_SOF0:
463 if (!ParseSOF(reader.ptr(), size, &result->frame_header)) {
464 DLOG(ERROR) << "ParseSOF failed";
465 return false;
466 }
467 break;
468 case JPEG_SOF1:
469 case JPEG_SOF2:
470 case JPEG_SOF3:
471 case JPEG_SOF5:
472 case JPEG_SOF6:
473 case JPEG_SOF7:
474 case JPEG_SOF9:
475 case JPEG_SOF10:
476 case JPEG_SOF11:
477 case JPEG_SOF13:
478 case JPEG_SOF14:
479 case JPEG_SOF15:
480 DLOG(ERROR) << "Only SOF0 (baseline) is supported, but got SOF"
481 << (marker2 - JPEG_SOF0);
482 return false;
483 case JPEG_DQT:
484 if (!ParseDQT(reader.ptr(), size, result->q_table)) {
485 DLOG(ERROR) << "ParseDQT failed";
486 return false;
487 }
488 has_marker_dqt = true;
489 break;
490 case JPEG_DHT:
491 if (!ParseDHT(reader.ptr(), size, result->dc_table, result->ac_table)) {
492 DLOG(ERROR) << "ParseDHT failed";
493 return false;
494 }
495 break;
496 case JPEG_DRI:
497 if (!ParseDRI(reader.ptr(), size, &result->restart_interval)) {
498 DLOG(ERROR) << "ParseDRI failed";
499 return false;
500 }
501 break;
502 case JPEG_SOS:
503 if (!ParseSOS(reader.ptr(), size, result->frame_header,
504 &result->scan)) {
505 DLOG(ERROR) << "ParseSOS failed";
506 return false;
507 }
508 has_marker_sos = true;
509 break;
510 default:
511 DVLOG(4) << "unknown marker " << static_cast<int>(marker2);
512 break;
513 }
514 reader.Skip(size);
515 }
516
517 if (!has_marker_dqt) {
518 DLOG(ERROR) << "No DQT marker found";
519 return false;
520 }
521
522 // Scan data follows scan header immediately.
523 result->data = reader.ptr();
524 result->data_size = reader.remaining();
525 return true;
526 }
527
ParseJpegPicture(const uint8_t * buffer,size_t length,JpegParseResult * result)528 bool ParseJpegPicture(const uint8_t* buffer,
529 size_t length,
530 JpegParseResult* result) {
531 DCHECK(buffer);
532 DCHECK(result);
533 BigEndianReader reader(reinterpret_cast<const char*>(buffer), length);
534 memset(result, 0, sizeof(JpegParseResult));
535
536 uint8_t marker1, marker2;
537 READ_U8_OR_RETURN_FALSE(&marker1);
538 READ_U8_OR_RETURN_FALSE(&marker2);
539 if (marker1 != JPEG_MARKER_PREFIX || marker2 != JPEG_SOI) {
540 DLOG(ERROR) << "Not a JPEG";
541 return false;
542 }
543
544 if (!ParseSOI(reader.ptr(), reader.remaining(), result))
545 return false;
546
547 // Update the sizes: |result->data_size| should not include the EOI marker or
548 // beyond.
549 BigEndianReader eoi_reader(result->data, result->data_size);
550 const char* eoi_begin_ptr = nullptr;
551 const char* eoi_end_ptr = nullptr;
552 if (!SearchEOI(eoi_reader.ptr(), eoi_reader.remaining(), &eoi_begin_ptr,
553 &eoi_end_ptr)) {
554 DLOG(ERROR) << "SearchEOI failed";
555 return false;
556 }
557 DCHECK(eoi_begin_ptr);
558 DCHECK(eoi_end_ptr);
559 result->data_size = eoi_begin_ptr - result->data;
560 result->image_size = eoi_end_ptr - reinterpret_cast<const char*>(buffer);
561 return true;
562 }
563
564 // TODO(andrescj): this function no longer seems necessary. Fix call sites to
565 // use ParseJpegPicture() directly.
ParseJpegStream(const uint8_t * buffer,size_t length,JpegParseResult * result)566 bool ParseJpegStream(const uint8_t* buffer,
567 size_t length,
568 JpegParseResult* result) {
569 DCHECK(buffer);
570 DCHECK(result);
571 return ParseJpegPicture(buffer, length, result);
572 }
573
574 } // namespace media
575