mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	Merge "reorganize chunk-parsing code"
This commit is contained in:
		| @@ -20,9 +20,8 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #define RIFF_HEADER_SIZE 20 | #define RIFF_HEADER_SIZE 12 | ||||||
| #define VP8_HEADER_SIZE 10 | #define VP8_HEADER_SIZE 10 | ||||||
| #define WEBP_HEADER_SIZE (RIFF_HEADER_SIZE + VP8_HEADER_SIZE) |  | ||||||
| #define CHUNK_SIZE 4096 | #define CHUNK_SIZE 4096 | ||||||
| #define MAX_MB_SIZE 4096 | #define MAX_MB_SIZE 4096 | ||||||
|  |  | ||||||
| @@ -245,16 +244,40 @@ static VP8StatusCode DecodeHeader(WebPIDecoder* const idec) { | |||||||
|   const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; |   const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; | ||||||
|   uint32_t curr_size = MemDataSize(&idec->mem_); |   uint32_t curr_size = MemDataSize(&idec->mem_); | ||||||
|   uint32_t chunk_size; |   uint32_t chunk_size; | ||||||
|  |   uint32_t riff_size; | ||||||
|  |   int is_vp8x_chunk = 0; | ||||||
|  |   int is_vp8_chunk = 0; | ||||||
|  |  | ||||||
|   if (curr_size < WEBP_HEADER_SIZE) { |   if (curr_size < RIFF_HEADER_SIZE) { | ||||||
|     return VP8_STATUS_SUSPENDED; |     return VP8_STATUS_SUSPENDED; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Validate and Skip over RIFF header |   if (!WebPCheckAndSkipRIFFHeader(&data, &curr_size, &riff_size)) { | ||||||
|   chunk_size = WebPCheckRIFFHeader(&data, &curr_size); |     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);  // Wrong RIFF Header. | ||||||
|   if (chunk_size == 0 || |   } | ||||||
|       curr_size < VP8_HEADER_SIZE || |  | ||||||
|       !VP8GetInfo(data, curr_size, chunk_size, NULL, NULL, NULL)) { |   if (!VP8XGetInfo(&data, &curr_size, &is_vp8x_chunk, NULL, NULL, NULL)) { | ||||||
|  |     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);  // Wrong VP8X Chunk. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (is_vp8x_chunk == -1) { | ||||||
|  |     return VP8_STATUS_SUSPENDED;  // Not enough data bytes to process chunk. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!VP8CheckAndSkipHeader(&data, &curr_size, &is_vp8_chunk, &chunk_size, | ||||||
|  |                              riff_size)) { | ||||||
|  |     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);  // Invalid VP8 header. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ((is_vp8_chunk == -1) && (chunk_size == 0)){ | ||||||
|  |     return VP8_STATUS_SUSPENDED;  // Not enough data bytes to extract chunk_size | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (curr_size < VP8_HEADER_SIZE) { | ||||||
|  |     return VP8_STATUS_SUSPENDED;  // Not enough data bytes to extract VP8 Header | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!VP8GetInfo(data, curr_size, chunk_size, NULL, NULL, NULL)) { | ||||||
|     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); |     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										137
									
								
								src/dec/vp8.c
									
									
									
									
									
								
							
							
						
						
									
										137
									
								
								src/dec/vp8.c
									
									
									
									
									
								
							| @@ -11,11 +11,15 @@ | |||||||
|  |  | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include "vp8i.h" | #include "vp8i.h" | ||||||
|  | #include "webpi.h" | ||||||
|  |  | ||||||
| #if defined(__cplusplus) || defined(c_plusplus) | #if defined(__cplusplus) || defined(c_plusplus) | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #define RIFF_HEADER_SIZE 12 | ||||||
|  | #define VP8X_HEADER_SIZE 20 | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| int WebPGetDecoderVersion(void) { | int WebPGetDecoderVersion(void) { | ||||||
| @@ -77,8 +81,40 @@ int VP8SetError(VP8Decoder* const dec, | |||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
|  |  | ||||||
| int VP8GetInfo(const uint8_t* data, | static inline uint32_t get_le32(const uint8_t* const data) { | ||||||
|                uint32_t data_size, uint32_t chunk_size, |   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int VP8CheckAndSkipHeader(const uint8_t** data_ptr, uint32_t* data_size_ptr, | ||||||
|  |                           int* is_vp8_chunk, uint32_t* chunk_size, | ||||||
|  |                           uint32_t riff_size) { | ||||||
|  |   if (!data_ptr || !data_size_ptr || !is_vp8_chunk || !chunk_size) { | ||||||
|  |     return 0;  // Invalid Args. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (*data_size_ptr >= 8) { | ||||||
|  |     if (!memcmp(*data_ptr, "VP8 ", 4)) { | ||||||
|  |       *is_vp8_chunk = 1; | ||||||
|  |       *chunk_size = get_le32(*data_ptr + 4); | ||||||
|  |       if ((riff_size >= RIFF_HEADER_SIZE) && | ||||||
|  |           (*chunk_size > riff_size - RIFF_HEADER_SIZE)) { | ||||||
|  |         return 0;  // Inconsistent size information. | ||||||
|  |       } | ||||||
|  |       // We have consumed 8 bytes from VP8 Header. Skip it. | ||||||
|  |       *data_ptr += 8; | ||||||
|  |       *data_size_ptr -= 8; | ||||||
|  |     } else { | ||||||
|  |       *is_vp8_chunk = 0; | ||||||
|  |       *chunk_size = 0; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     *is_vp8_chunk = -1;  // Insufficient data. | ||||||
|  |     *chunk_size = 0; | ||||||
|  |   } | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int VP8GetInfo(const uint8_t* data, uint32_t data_size, uint32_t chunk_size, | ||||||
|                int* width, int* height, int* has_alpha) { |                int* width, int* height, int* has_alpha) { | ||||||
|   if (data_size < 10) { |   if (data_size < 10) { | ||||||
|     return 0;         // not enough data |     return 0;         // not enough data | ||||||
| @@ -125,6 +161,40 @@ int VP8GetInfo(const uint8_t* data, | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int VP8XGetInfo(const uint8_t** data_ptr, uint32_t* data_size_ptr, | ||||||
|  |                 int* is_vp8x_chunk, int* width, int* height, uint32_t* flags) { | ||||||
|  |   if (!data_ptr || !data_size_ptr || !is_vp8x_chunk) { | ||||||
|  |     return 0;  // Invalid Args. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (*data_size_ptr >= VP8X_HEADER_SIZE) { | ||||||
|  |     if (!memcmp(*data_ptr, "VP8X", 4)) { | ||||||
|  |       const uint32_t chunk_size = get_le32(*data_ptr + 4); | ||||||
|  |       *is_vp8x_chunk = 1; | ||||||
|  |       if (chunk_size != (VP8X_HEADER_SIZE - 8)) { | ||||||
|  |         return 0;  // Wrong chunk size. | ||||||
|  |       } | ||||||
|  |       if (flags) { | ||||||
|  |         *flags = get_le32(*data_ptr + 8); | ||||||
|  |       } | ||||||
|  |       if (width) { | ||||||
|  |         *width = get_le32(*data_ptr + 12); | ||||||
|  |       } | ||||||
|  |       if (height) { | ||||||
|  |         *height = get_le32(*data_ptr + 16); | ||||||
|  |       } | ||||||
|  |       // We have consumed 20 bytes from VP8X Header. Skip it. | ||||||
|  |       *data_ptr += VP8X_HEADER_SIZE; | ||||||
|  |       *data_size_ptr -= VP8X_HEADER_SIZE; | ||||||
|  |     } else { | ||||||
|  |       *is_vp8x_chunk = 0; | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     *is_vp8x_chunk = -1;  // Insufficient data. | ||||||
|  |   } | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
| // Header parsing | // Header parsing | ||||||
|  |  | ||||||
| @@ -245,14 +315,14 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) { | |||||||
|   return !br->eof_; |   return !br->eof_; | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline uint32_t get_le32(const uint8_t* const data) { |  | ||||||
|   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Topmost call | // Topmost call | ||||||
| int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||||
|   uint8_t* buf; |   const uint8_t* buf; | ||||||
|   uint32_t buf_size; |   uint32_t buf_size; | ||||||
|  |   uint32_t riff_size; | ||||||
|  |   uint32_t chunk_size; | ||||||
|  |   int is_vp8x_chunk = 0; | ||||||
|  |   int is_vp8_chunk = 0; | ||||||
|   VP8FrameHeader* frm_hdr; |   VP8FrameHeader* frm_hdr; | ||||||
|   VP8PictureHeader* pic_hdr; |   VP8PictureHeader* pic_hdr; | ||||||
|   VP8BitReader* br; |   VP8BitReader* br; | ||||||
| @@ -274,34 +344,31 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | |||||||
|                        "Not enough data to parse frame header"); |                        "Not enough data to parse frame header"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Skip over valid RIFF headers |   // Skip over valid RIFF headers. | ||||||
|   if (!memcmp(buf, "RIFF", 4)) { |   if (!WebPCheckAndSkipRIFFHeader(&buf, &buf_size, &riff_size)) { | ||||||
|     uint32_t riff_size; |     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||||
|     uint32_t chunk_size; |                        "RIFF: Invalid RIFF container"); | ||||||
|     if (buf_size < 20 + 4) { |   } | ||||||
|       return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, |  | ||||||
|                          "RIFF: Truncated header."); |   if (!VP8XGetInfo(&buf, &buf_size, &is_vp8x_chunk, NULL, NULL, NULL)) { | ||||||
|     } |     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||||
|     if (memcmp(buf + 8, "WEBP", 4)) {   // wrong image file signature |                        "RIFF: Invalid VP8X container"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!VP8CheckAndSkipHeader(&buf, &buf_size, &is_vp8_chunk, &chunk_size, | ||||||
|  |                              riff_size)) { | ||||||
|  |     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||||
|  |                        "RIFF: Inconsistent size information."); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (is_vp8_chunk == -1) { | ||||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||||
|                          "RIFF: WEBP signature not found."); |                          "Not enough data to parse frame header."); | ||||||
|     } |   } | ||||||
|     riff_size = get_le32(buf + 4); |  | ||||||
|     if (riff_size < 12) { |   if (buf_size < 4) { | ||||||
|       return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, |     return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||||
|                          "RIFF: Truncated header."); |                        "RIFF: Truncated header."); | ||||||
|     } |  | ||||||
|     if (memcmp(buf + 12, "VP8 ", 4)) { |  | ||||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |  | ||||||
|                          "RIFF: Invalid compression format."); |  | ||||||
|     } |  | ||||||
|     chunk_size = get_le32(buf + 16); |  | ||||||
|     if (chunk_size > riff_size - 12) { |  | ||||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, |  | ||||||
|                          "RIFF: Inconsistent size information."); |  | ||||||
|     } |  | ||||||
|     buf += 20; |  | ||||||
|     buf_size -= 20; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Paragraph 9.1 |   // Paragraph 9.1 | ||||||
| @@ -437,7 +504,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | |||||||
|   if (dec->pic_hdr_.colorspace_) { |   if (dec->pic_hdr_.colorspace_) { | ||||||
|     const size_t kTrailerSize = 8; |     const size_t kTrailerSize = 8; | ||||||
|     const uint8_t kTrailerMarker = 0x01; |     const uint8_t kTrailerMarker = 0x01; | ||||||
|     uint8_t* const ext_buf = buf - kTrailerSize; |     const uint8_t* ext_buf = buf - kTrailerSize; | ||||||
|     size_t size; |     size_t size; | ||||||
|  |  | ||||||
|     if (frm_hdr->partition_length_ < kTrailerSize || |     if (frm_hdr->partition_length_ < kTrailerSize || | ||||||
|   | |||||||
| @@ -286,6 +286,20 @@ struct VP8Decoder { | |||||||
| // in vp8.c | // in vp8.c | ||||||
| int VP8SetError(VP8Decoder* const dec, | int VP8SetError(VP8Decoder* const dec, | ||||||
|                 VP8StatusCode error, const char * const msg); |                 VP8StatusCode error, const char * const msg); | ||||||
|  |  | ||||||
|  | // Validates the VP8 Header and skip over it. | ||||||
|  | // Returns 0 for invalid (chunk_size greater than riff_size) VP8 header. | ||||||
|  | // Else return 1. | ||||||
|  | // is_vp8_chunk is set to: | ||||||
|  | //   0, in case data bytes don't correspond to VP8 chunk. | ||||||
|  | //   1, in case data bytes correspond to VP8 chunk. | ||||||
|  | //   -1, in case not enough bytes (partial VP8 chunk) are passed. | ||||||
|  | // chunk_size is set to the chunk size extracted from the VP8 chunk header. For | ||||||
|  | // partial VP8 chunk, chunk_size is set to 0. | ||||||
|  | int VP8CheckAndSkipHeader(const uint8_t** data_ptr, uint32_t* data_size_ptr, | ||||||
|  |                           int* is_vp8_chunk, uint32_t* chunk_size, | ||||||
|  |                           uint32_t riff_size); | ||||||
|  |  | ||||||
| // Validates the VP8 data-header and retrieve basic header information viz width | // Validates the VP8 data-header and retrieve basic header information viz width | ||||||
| // and height. Returns 0 in case of formatting error. *width/*height/*has_alpha | // and height. Returns 0 in case of formatting error. *width/*height/*has_alpha | ||||||
| // can be passed NULL. | // can be passed NULL. | ||||||
| @@ -294,6 +308,17 @@ int VP8GetInfo(const uint8_t* data, | |||||||
|                uint32_t chunk_size,   // total data size expect in the chunk |                uint32_t chunk_size,   // total data size expect in the chunk | ||||||
|                int *width, int *height, int *has_alpha); |                int *width, int *height, int *has_alpha); | ||||||
|  |  | ||||||
|  | // Validates the VP8X Header and skip over it. | ||||||
|  | // Returns 0 for invalid VP8X header. Else return 1. | ||||||
|  | // is_vp8x_chunk is set to: | ||||||
|  | //   0, in case data bytes doesn't correspond to VP8X chunk. | ||||||
|  | //   1, in case data bytes correspond to VP8X chunk. | ||||||
|  | //   -1, in case not enough bytes (partial VP8X chunk) are passed. | ||||||
|  | // Width, Height & Flags are set to the corresponding fields extracted from the | ||||||
|  | // VP8X chunk. | ||||||
|  | int VP8XGetInfo(const uint8_t** data_ptr, uint32_t* data_size_ptr, | ||||||
|  |                 int* is_vp8x_chunk, int* width, int* height, uint32_t* flags); | ||||||
|  |  | ||||||
| // in tree.c | // in tree.c | ||||||
| void VP8ResetProba(VP8Proba* const proba); | void VP8ResetProba(VP8Proba* const proba); | ||||||
| void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec); | void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec); | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								src/dec/webp.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/dec/webp.c
									
									
									
									
									
								
							| @@ -17,16 +17,26 @@ | |||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #define RIFF_HEADER_SIZE 12 | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
| // RIFF layout is: | // RIFF layout is: | ||||||
| //   0ffset  tag | //   0ffset  tag | ||||||
| //   0...3   "RIFF" 4-byte tag | //   0...3   "RIFF" 4-byte tag | ||||||
| //   4...7   size of image data (including metadata) starting at offset 8 | //   4...7   size of image data (including metadata) starting at offset 8 | ||||||
| //   8...11  "WEBP"   our form-type signature | //   8...11  "WEBP"   our form-type signature | ||||||
|  | // The RIFF container (12 bytes) is followed by appropriate chunks: | ||||||
| //   12..15  "VP8 ": 4-bytes tags, describing the raw video format used | //   12..15  "VP8 ": 4-bytes tags, describing the raw video format used | ||||||
| //   16..19  size of the raw VP8 image data, starting at offset 20 | //   16..19  size of the raw VP8 image data, starting at offset 20 | ||||||
| //   20....  the VP8 bytes | //   20....  the VP8 bytes | ||||||
| // There can be extra chunks after the "VP8 " chunk (ICMT, ICOP, ...) | // Or, | ||||||
|  | //   12..15  "VP8X": 4-bytes tags, describing the extended-VP8 chunk. | ||||||
|  | //   16..19  size of the VP8X chunk starting at offset 8. | ||||||
|  | //   20..23  VP8X flags bit-map corresponding to the chunk-types present. | ||||||
|  | //   24..27  Width of the Canvas Image. | ||||||
|  | //   28..31  Height of the Canvas Image. | ||||||
|  | // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, | ||||||
|  | // META  ...) | ||||||
| // All 32-bits sizes are in little-endian order. | // All 32-bits sizes are in little-endian order. | ||||||
| // Note: chunk data must be padded to multiple of 2 in size | // Note: chunk data must be padded to multiple of 2 in size | ||||||
|  |  | ||||||
| @@ -34,33 +44,25 @@ static inline uint32_t get_le32(const uint8_t* const data) { | |||||||
|   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); |   return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||||||
| } | } | ||||||
|  |  | ||||||
| // If a RIFF container is detected, validate it and skip over it. | uint32_t WebPCheckAndSkipRIFFHeader(const uint8_t** data_ptr, | ||||||
| uint32_t WebPCheckRIFFHeader(const uint8_t** data_ptr, |                                     uint32_t* data_size_ptr, | ||||||
|                              uint32_t* data_size_ptr) { |                                     uint32_t* riff_size) { | ||||||
|   uint32_t chunk_size = 0xffffffffu; |   if (*data_size_ptr >= RIFF_HEADER_SIZE && !memcmp(*data_ptr, "RIFF", 4)) { | ||||||
|   if (*data_size_ptr >= 10 + 20 && !memcmp(*data_ptr, "RIFF", 4)) { |  | ||||||
|     if (memcmp(*data_ptr + 8, "WEBP", 4)) { |     if (memcmp(*data_ptr + 8, "WEBP", 4)) { | ||||||
|       return 0;  // wrong image file signature |       return 0;  // Wrong image file signature. | ||||||
|     } else { |     } else { | ||||||
|       const uint32_t riff_size = get_le32(*data_ptr + 4); |       *riff_size = get_le32(*data_ptr + 4); | ||||||
|       if (riff_size < 12) { |       if (*riff_size < RIFF_HEADER_SIZE) { | ||||||
|         return 0;   // we should have at least one chunk |         return 0;   // We should have at least one chunk. | ||||||
|       } |  | ||||||
|       if (memcmp(*data_ptr + 12, "VP8 ", 4)) { |  | ||||||
|         return 0;   // invalid compression format |  | ||||||
|       } |  | ||||||
|       chunk_size = get_le32(*data_ptr + 16); |  | ||||||
|       if (chunk_size > riff_size - 12) { |  | ||||||
|         return 0;  // inconsistent size information. |  | ||||||
|       } |       } | ||||||
|       // We have a RIFF container. Skip it. |       // We have a RIFF container. Skip it. | ||||||
|       *data_ptr += 20; |       *data_ptr += RIFF_HEADER_SIZE; | ||||||
|       *data_size_ptr -= 20; |       *data_size_ptr -= RIFF_HEADER_SIZE; | ||||||
|       // Note: we don't report error for odd-sized chunks. |  | ||||||
|     } |     } | ||||||
|     return chunk_size; |   } else { | ||||||
|  |     *riff_size = 0;  // Did not get full RIFF Header. | ||||||
|   } |   } | ||||||
|   return *data_size_ptr; |   return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
| @@ -268,19 +270,6 @@ uint8_t* WebPDecodeYUV(const uint8_t* data, uint32_t data_size, | |||||||
|   return out; |   return out; | ||||||
| } | } | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- |  | ||||||
| // WebPGetInfo() |  | ||||||
|  |  | ||||||
| int WebPGetInfo(const uint8_t* data, uint32_t data_size, |  | ||||||
|                 int* width, int* height) { |  | ||||||
|   const uint32_t chunk_size = WebPCheckRIFFHeader(&data, &data_size); |  | ||||||
|   if (!chunk_size) { |  | ||||||
|     return 0;         // unsupported RIFF header |  | ||||||
|   } |  | ||||||
|   // Validate raw video data |  | ||||||
|   return VP8GetInfo(data, data_size, chunk_size, width, height, NULL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void DefaultFeatures(WebPBitstreamFeatures* const features) { | static void DefaultFeatures(WebPBitstreamFeatures* const features) { | ||||||
|   assert(features); |   assert(features); | ||||||
|   memset(features, 0, sizeof(*features)); |   memset(features, 0, sizeof(*features)); | ||||||
| @@ -289,25 +278,77 @@ static void DefaultFeatures(WebPBitstreamFeatures* const features) { | |||||||
|  |  | ||||||
| static VP8StatusCode GetFeatures(const uint8_t** data, uint32_t* data_size, | static VP8StatusCode GetFeatures(const uint8_t** data, uint32_t* data_size, | ||||||
|                                  WebPBitstreamFeatures* const features) { |                                  WebPBitstreamFeatures* const features) { | ||||||
|   uint32_t chunk_size; |   uint32_t chunk_size = 0; | ||||||
|  |   uint32_t riff_size = 0; | ||||||
|  |   uint32_t flags = 0; | ||||||
|  |   int is_vp8x_chunk = 0; | ||||||
|  |   int is_vp8_chunk = 0; | ||||||
|  |  | ||||||
|   if (features == NULL) { |   if (features == NULL) { | ||||||
|     return VP8_STATUS_INVALID_PARAM; |     return VP8_STATUS_INVALID_PARAM; | ||||||
|   } |   } | ||||||
|   DefaultFeatures(features); |   DefaultFeatures(features); | ||||||
|  |  | ||||||
|   if (data == NULL || *data == NULL || data_size == 0) { |   if (data == NULL || *data == NULL || data_size == 0) { | ||||||
|     return VP8_STATUS_INVALID_PARAM; |     return VP8_STATUS_INVALID_PARAM; | ||||||
|   } |   } | ||||||
|   chunk_size = WebPCheckRIFFHeader(data, data_size); |  | ||||||
|   if (chunk_size == 0) { |   if (!WebPCheckAndSkipRIFFHeader(data, data_size, &riff_size)) { | ||||||
|     return VP8_STATUS_BITSTREAM_ERROR;   // unsupported RIFF header |     return VP8_STATUS_BITSTREAM_ERROR;   // Wrong RIFF Header. | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if (!VP8XGetInfo(data, data_size, &is_vp8x_chunk, | ||||||
|  |                    &features->width, &features->height, &flags)) { | ||||||
|  |     return VP8_STATUS_BITSTREAM_ERROR;  // Wrong VP8X Chunk-header. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (is_vp8x_chunk > 0) { | ||||||
|  |     return VP8_STATUS_OK; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!VP8CheckAndSkipHeader(data, data_size, &is_vp8_chunk, &chunk_size, | ||||||
|  |                              riff_size)) { | ||||||
|  |     return VP8_STATUS_BITSTREAM_ERROR;  // Invalid VP8 header. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (is_vp8_chunk == -1) { | ||||||
|  |     return VP8_STATUS_BITSTREAM_ERROR;   // Insufficient data-bytes. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!is_vp8_chunk) { | ||||||
|  |     chunk_size = *data_size;  // No VP8 chunk wrapper over raw VP8 data. | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Validates raw VP8 data. | ||||||
|   if (!VP8GetInfo(*data, *data_size, chunk_size, |   if (!VP8GetInfo(*data, *data_size, chunk_size, | ||||||
|                   &features->width, &features->height, &features->has_alpha)) { |                   &features->width, &features->height, &features->has_alpha)) { | ||||||
|     return VP8_STATUS_BITSTREAM_ERROR; |     return VP8_STATUS_BITSTREAM_ERROR; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return VP8_STATUS_OK; |   return VP8_STATUS_OK; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //----------------------------------------------------------------------------- | ||||||
|  | // WebPGetInfo() | ||||||
|  |  | ||||||
|  | int WebPGetInfo(const uint8_t* data, uint32_t data_size, | ||||||
|  |                 int* width, int* height) { | ||||||
|  |   WebPBitstreamFeatures features; | ||||||
|  |  | ||||||
|  |   if (GetFeatures(&data, &data_size, &features) != VP8_STATUS_OK) { | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (width) { | ||||||
|  |     *width  = features.width; | ||||||
|  |   } | ||||||
|  |   if (height) { | ||||||
|  |     *height = features.height; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
| //----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||||
| // Advance decoding API | // Advance decoding API | ||||||
|  |  | ||||||
|   | |||||||
| @@ -76,10 +76,13 @@ void WebPInitUpsamplersSSE2(void); | |||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| // Misc utils | // Misc utils | ||||||
|  |  | ||||||
| // If a RIFF container is detected, validate it and skip over it. Returns | // Validates the RIFF container (if detected) and skip over it. | ||||||
| // VP8 bit-stream size if RIFF header is valid else returns 0 | // If a RIFF container is detected, returns 0 for invalid header. Else return 1. | ||||||
| uint32_t WebPCheckRIFFHeader(const uint8_t** data_ptr, | // In case there are not enough bytes (partial RIFF container), return 0 for | ||||||
|                              uint32_t* data_size_ptr); | // riff_size. Else return the riff_size extracted from the header. | ||||||
|  | uint32_t WebPCheckAndSkipRIFFHeader(const uint8_t** data_ptr, | ||||||
|  |                                     uint32_t* data_size_ptr, | ||||||
|  |                                     uint32_t* riff_size_ptr); | ||||||
|  |  | ||||||
| // Initializes VP8Io with custom setup, io and teardown functions. The default | // Initializes VP8Io with custom setup, io and teardown functions. The default | ||||||
| // hooks will use the supplied 'params' as io->opaque handle. | // hooks will use the supplied 'params' as io->opaque handle. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user