* 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:
Pascal Massimino 2011-02-16 14:33:16 -08:00
parent 73c973e6da
commit 746a4820b9
7 changed files with 83 additions and 49 deletions

View File

@ -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;
}
//-----------------------------------------------------------------------------

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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;
}
//-----------------------------------------------------------------------------

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 */