mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 18:35:41 +01:00 
			
		
		
		
	* make (*put)() hook return a bool for abort request.
* add an enum for VP8Status() to make things clearer Change-Id: I458aeabab93f95d28e8ee10be699b677c04b4acb
This commit is contained in:
		| @@ -44,7 +44,8 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) { | ||||
|     dec->mem_size_ = 0; | ||||
|     dec->mem_ = (uint8_t*)malloc(needed); | ||||
|     if (dec->mem_ == NULL) { | ||||
|       return VP8SetError(dec, 1, "no memory during frame initialization."); | ||||
|       return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, | ||||
|                          "no memory during frame initialization."); | ||||
|     } | ||||
|     dec->mem_size_ = needed; | ||||
|   } | ||||
| @@ -210,7 +211,7 @@ void VP8StoreBlock(VP8Decoder* const dec) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void VP8FinishRow(VP8Decoder* const dec, VP8Io* io) { | ||||
| int VP8FinishRow(VP8Decoder* const dec, VP8Io* io) { | ||||
|   const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; | ||||
|   const int ysize = extra_y_rows * dec->cache_y_stride_; | ||||
|   const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_; | ||||
| @@ -246,7 +247,9 @@ void VP8FinishRow(VP8Decoder* const dec, VP8Io* io) { | ||||
|     } | ||||
|     io->mb_y = y_start; | ||||
|     io->mb_h = y_end - y_start; | ||||
|     io->put(io); | ||||
|     if (!io->put(io)) { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|     // rotate top samples | ||||
|   if (!last_row) { | ||||
| @@ -254,6 +257,7 @@ void VP8FinishRow(VP8Decoder* const dec, VP8Io* io) { | ||||
|     memcpy(udst, udst + 8 * dec->cache_uv_stride_, uvsize); | ||||
|     memcpy(vdst, vdst + 8 * dec->cache_uv_stride_, uvsize); | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| // VP8Decoder | ||||
|  | ||||
| static void SetOk(VP8Decoder* const dec) { | ||||
|   dec->status_ = 0; | ||||
|   dec->status_ = VP8_STATUS_OK; | ||||
|   dec->error_msg_ = "OK"; | ||||
| } | ||||
|  | ||||
| @@ -35,8 +35,8 @@ VP8Decoder* VP8New() { | ||||
|   return dec; | ||||
| } | ||||
|  | ||||
| int VP8Status(VP8Decoder* const dec) { | ||||
|   if (!dec) return 2; | ||||
| VP8StatusCode VP8Status(VP8Decoder* const dec) { | ||||
|   if (!dec) return VP8_STATUS_INVALID_PARAM; | ||||
|   return dec->status_; | ||||
| } | ||||
|  | ||||
| @@ -53,7 +53,8 @@ void VP8Delete(VP8Decoder* const dec) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| int VP8SetError(VP8Decoder* const dec, int error, const char *msg) { | ||||
| int VP8SetError(VP8Decoder* const dec, | ||||
|                 VP8StatusCode error, const char * const msg) { | ||||
|   dec->status_ = error; | ||||
|   dec->error_msg_ = msg; | ||||
|   dec->ready_ = 0; | ||||
| @@ -189,13 +190,15 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|   } | ||||
|   SetOk(dec); | ||||
|   if (io == NULL) { | ||||
|     return VP8SetError(dec, 2, "null VP8Io passed to VP8GetHeaders()"); | ||||
|     return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, | ||||
|                        "null VP8Io passed to VP8GetHeaders()"); | ||||
|   } | ||||
|  | ||||
|   buf = (uint8_t *)io->data; | ||||
|   buf_size = io->data_size; | ||||
|   if (buf == NULL || buf_size <= 4) { | ||||
|     return VP8SetError(dec, 2, "Not enough data to parse frame header"); | ||||
|     return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||
|                        "Not enough data to parse frame header"); | ||||
|   } | ||||
|  | ||||
|   // Skip over valid RIFF headers | ||||
| @@ -203,18 +206,22 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|     uint32_t riff_size; | ||||
|     uint32_t chunk_size; | ||||
|     if (buf_size < 20 + 4) { | ||||
|       return VP8SetError(dec, 2, "RIFF: Truncated header."); | ||||
|       return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||
|                          "RIFF: Truncated header."); | ||||
|     } | ||||
|     if (memcmp(buf + 8, "WEBP", 4)) {   // wrong image file signature | ||||
|       return VP8SetError(dec, 2, "RIFF: WEBP signature not found."); | ||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                          "RIFF: WEBP signature not found."); | ||||
|     } | ||||
|     riff_size = get_le32(buf + 4); | ||||
|     if (memcmp(buf + 12, "VP8 ", 4)) { | ||||
|       return VP8SetError(dec, 2, "RIFF: Invalid compression format."); | ||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                          "RIFF: Invalid compression format."); | ||||
|     } | ||||
|     chunk_size = get_le32(buf + 16); | ||||
|     if ((chunk_size > riff_size + 8) || (chunk_size & 1)) { | ||||
|       return VP8SetError(dec, 2, "RIFF: Inconsistent size information."); | ||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                          "RIFF: Inconsistent size information."); | ||||
|     } | ||||
|     buf += 20; | ||||
|     buf_size -= 20; | ||||
| @@ -236,10 +243,12 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|   if (frm_hdr->key_frame_) { | ||||
|     // Paragraph 9.2 | ||||
|     if (buf_size < 7) { | ||||
|       return VP8SetError(dec, 2, "cannot parse picture header"); | ||||
|       return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||
|                          "cannot parse picture header"); | ||||
|     } | ||||
|     if (buf[0] != 0x9d || buf[1] != 0x01 || buf[2] != 0x2a) { | ||||
|       return VP8SetError(dec, 2, "Bad code word"); | ||||
|       return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                          "Bad code word"); | ||||
|     } | ||||
|     pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff; | ||||
|     pic_hdr->xscale_ = buf[4] >> 6;   // ratio: 1, 5/4 5/3 or 2 | ||||
| @@ -261,7 +270,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|   br = &dec->br_; | ||||
|   VP8Init(br, buf, buf_size); | ||||
|   if (frm_hdr->partition_length_ > buf_size) { | ||||
|     return VP8SetError(dec, 2, "bad partition length"); | ||||
|     return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||
|                        "bad partition length"); | ||||
|   } | ||||
|   buf += frm_hdr->partition_length_; | ||||
|   buf_size -= frm_hdr->partition_length_; | ||||
| @@ -270,14 +280,17 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|     pic_hdr->clamp_type_ = VP8Get(br); | ||||
|   } | ||||
|   if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) { | ||||
|     return VP8SetError(dec, 2, "cannot parse segment header"); | ||||
|     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                        "cannot parse segment header"); | ||||
|   } | ||||
|   // Filter specs | ||||
|   if (!ParseFilterHeader(br, dec)) { | ||||
|     return VP8SetError(dec, 2, "cannot parse filter header"); | ||||
|     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                        "cannot parse filter header"); | ||||
|   } | ||||
|   if (!ParsePartitions(dec, buf, buf_size)) { | ||||
|     return VP8SetError(dec, 2, "cannot parse partitions"); | ||||
|     return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                        "cannot parse partitions"); | ||||
|   } | ||||
|  | ||||
|   // quantizer change | ||||
| @@ -298,7 +311,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) { | ||||
|     dec->buffer_flags_ |= VP8Get(br) << 6;    // sign bias golden | ||||
|     dec->buffer_flags_ |= VP8Get(br) << 7;    // sign bias alt ref | ||||
| #else | ||||
|     return VP8SetError(dec, 2, "Not a key frame."); | ||||
|     return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE, | ||||
|                        "Not a key frame."); | ||||
| #endif | ||||
|   } else { | ||||
|     dec->buffer_flags_ = 0x003 | 0x100; | ||||
| @@ -500,7 +514,6 @@ static int ParseResiduals(VP8Decoder* const dec, | ||||
| // Main loop | ||||
|  | ||||
| static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { | ||||
|   int ok = 1; | ||||
|   VP8BitReader* const br = &dec->br_; | ||||
|   VP8BitReader* token_br; | ||||
|  | ||||
| @@ -530,8 +543,8 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { | ||||
|  | ||||
|       if (!info->skip_) { | ||||
|         if (!ParseResiduals(dec, info, token_br)) { | ||||
|           ok = 0; | ||||
|           break; | ||||
|           return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR, | ||||
|                              "Residual parsing failed."); | ||||
|         } | ||||
|       } else { | ||||
|         left->nz_ = info->nz_ = 0; | ||||
| @@ -546,13 +559,13 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { | ||||
|       // Store data and save block's filtering params | ||||
|       VP8StoreBlock(dec); | ||||
|     } | ||||
|     if (!ok) { | ||||
|       break; | ||||
|     if (!VP8FinishRow(dec, io)) { | ||||
|       return VP8SetError(dec, VP8_STATUS_USER_ABORT, | ||||
|                          "Output aborted."); | ||||
|     } | ||||
|     VP8FinishRow(dec, io); | ||||
|     if (dec->br_.eof_ || token_br->eof_) { | ||||
|       ok = 0; | ||||
|       break; | ||||
|       return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, | ||||
|                          "Premature end-of-file encountered."); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -563,7 +576,7 @@ static int ParseFrame(VP8Decoder* const dec, VP8Io* io) { | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   return ok; | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| // Main entry point | ||||
| @@ -572,7 +585,8 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { | ||||
|     return 0; | ||||
|   } | ||||
|   if (io == NULL) { | ||||
|     return VP8SetError(dec, 2, "NULL VP8Io parameter in VP8Decode()."); | ||||
|     return VP8SetError(dec, VP8_STATUS_INVALID_PARAM, | ||||
|                        "NULL VP8Io parameter in VP8Decode()."); | ||||
|   } | ||||
|  | ||||
|   if (!dec->ready_) { | ||||
| @@ -585,13 +599,15 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { | ||||
|   // will allocate memory and prepare everything. | ||||
|   if (!VP8InitFrame(dec, io)) { | ||||
|     VP8Clear(dec); | ||||
|     return VP8SetError(dec, 3, "Allocation failed"); | ||||
|     return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY, | ||||
|                        "Allocation failed"); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   if (io->setup && !io->setup(io)) { | ||||
|     VP8Clear(dec); | ||||
|     return VP8SetError(dec, 3, "Frame setup failed"); | ||||
|     return VP8SetError(dec, VP8_STATUS_USER_ABORT, | ||||
|                        "Frame setup failed"); | ||||
|   } | ||||
|  | ||||
|   // Main decoding loop | ||||
| @@ -602,7 +618,7 @@ int VP8Decode(VP8Decoder* const dec, VP8Io* const io) { | ||||
|     } | ||||
|     if (!ret) { | ||||
|       VP8Clear(dec); | ||||
|       return VP8SetError(dec, 3, "Frame decoding failed"); | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -162,7 +162,7 @@ typedef struct { | ||||
| // VP8Decoder: the main opaque structure handed over to user | ||||
|  | ||||
| struct VP8Decoder { | ||||
|   int status_;    // 0 = OK | ||||
|   VP8StatusCode status_; | ||||
|   int ready_;     // true if ready to decode a picture with VP8Decode() | ||||
|   const char* error_msg_;  // set when status_ is not OK. | ||||
|  | ||||
| @@ -246,7 +246,8 @@ struct VP8Decoder { | ||||
| // internal functions. Not public. | ||||
|  | ||||
| // in vp8.c | ||||
| int VP8SetError(VP8Decoder* const dec, int error, const char *msg); | ||||
| int VP8SetError(VP8Decoder* const dec, | ||||
|                 VP8StatusCode error, const char * const msg); | ||||
|  | ||||
| // in tree.c | ||||
| void VP8ResetProba(VP8Proba* const proba); | ||||
| @@ -262,8 +263,8 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io); | ||||
| void VP8ReconstructBlock(VP8Decoder* const dec); | ||||
| // Store a block, along with filtering params | ||||
| void VP8StoreBlock(VP8Decoder* const dec); | ||||
| // Finalize and transmit a complete row | ||||
| void VP8FinishRow(VP8Decoder* const dec, VP8Io* io); | ||||
| // Finalize and transmit a complete row. Return false in case of user-abort. | ||||
| int VP8FinishRow(VP8Decoder* const dec, VP8Io* io); | ||||
|  | ||||
| // in dsp.c | ||||
| typedef void (*VP8Idct)(const int16_t* coeffs, uint8_t* dst); | ||||
|   | ||||
| @@ -188,14 +188,16 @@ typedef struct { | ||||
|   CSP_MODE mode; | ||||
| } Params; | ||||
|  | ||||
| static void CustomPut(const VP8Io* io) { | ||||
| static int CustomPut(const VP8Io* io) { | ||||
|   Params *p = (Params*)io->opaque; | ||||
|   const int w = io->width; | ||||
|   const int mb_h = io->mb_h; | ||||
|   const int uv_w = (w + 1) / 2; | ||||
|   assert(!(io->mb_y & 1)); | ||||
|  | ||||
|   if (w <= 0 || mb_h <= 0) return; | ||||
|   if (w <= 0 || mb_h <= 0) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if (p->mode == MODE_YUV) { | ||||
|     uint8_t* const y_dst = p->output + io->mb_y * p->stride; | ||||
| @@ -282,6 +284,7 @@ static void CustomPut(const VP8Io* io) { | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -96,4 +96,4 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, uint32_t data_size, | ||||
| }    // extern "C" | ||||
| #endif | ||||
|  | ||||
| #endif  // WEBP_WEBP_DECODE_H_ | ||||
| #endif  /* WEBP_WEBP_DECODE_H_ */ | ||||
|   | ||||
| @@ -53,8 +53,9 @@ struct VP8Io { | ||||
|  | ||||
|   // called when fresh samples are available. Currently, samples are in | ||||
|   // YUV420 format, and can be up to width x 24 in size (depending on the | ||||
|   // in-loop filtering level, e.g.). | ||||
|   void (*put)(const VP8Io* io); | ||||
|   // in-loop filtering level, e.g.). Should return false in case of error | ||||
|   // or abort request. | ||||
|   int (*put)(const VP8Io* io); | ||||
|  | ||||
|   // called just before starting to decode the blocks. | ||||
|   // Should returns 0 in case of error. | ||||
| @@ -86,15 +87,23 @@ void VP8InitIo(VP8Io* const io); | ||||
| int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io); | ||||
|  | ||||
| // Decode a picture. Will call VP8GetHeaders() if it wasn't done already. | ||||
| // Returns false in case of error. | ||||
| int VP8Decode(VP8Decoder* const dec, VP8Io* const io); | ||||
|  | ||||
| // Enumeration of the codes returned by VP8Status() | ||||
| typedef enum { | ||||
|   VP8_STATUS_OK = 0, | ||||
|   VP8_STATUS_OUT_OF_MEMORY, | ||||
|   VP8_STATUS_INVALID_PARAM, | ||||
|   VP8_STATUS_BITSTREAM_ERROR, | ||||
|   VP8_STATUS_UNSUPPORTED_FEATURE, | ||||
|   VP8_STATUS_SUSPENDED, | ||||
|   VP8_STATUS_USER_ABORT, | ||||
|   VP8_STATUS_NOT_ENOUGH_DATA, | ||||
| } VP8StatusCode; | ||||
|  | ||||
| // Return current status of the decoder: | ||||
| //  0 = OK | ||||
| //  1 = OUT_OF_MEMORY | ||||
| //  2 = INVALID_PARAM | ||||
| //  3 = BITSTREAM_ERROR | ||||
| //  4 = UNSUPPORTED_FEATURE | ||||
| int VP8Status(VP8Decoder* const dec); | ||||
| VP8StatusCode VP8Status(VP8Decoder* const dec); | ||||
|  | ||||
| // return readable string corresponding to the last status. | ||||
| const char* VP8StatusMessage(VP8Decoder* const dec); | ||||
| @@ -112,4 +121,4 @@ void VP8Delete(VP8Decoder* const dec); | ||||
| }    // extern "C" | ||||
| #endif | ||||
|  | ||||
| #endif  // WEBP_WEBP_DECODE_VP8_H_ | ||||
| #endif  /* WEBP_WEBP_DECODE_VP8_H_ */ | ||||
|   | ||||
| @@ -22,6 +22,7 @@ typedef unsigned short uint16_t; | ||||
| typedef signed   int int32_t; | ||||
| typedef unsigned int uint32_t; | ||||
| typedef unsigned long long int uint64_t; | ||||
| typedef long long int int64_t; | ||||
| #define inline __forceinline | ||||
| #endif  /* _MSC_VER */ | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user