mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +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:
parent
73c973e6da
commit
746a4820b9
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user