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