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