mirror of
https://github.com/webmproject/libwebp.git
synced 2025-12-23 21:46:26 +01:00
Merge "Fix -fbounds-safety errors in dec." into main
This commit is contained in:
@@ -423,10 +423,12 @@ target_include_directories(webputils PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||
add_library(webp $<TARGET_OBJECTS:webpdecode> $<TARGET_OBJECTS:webpdsp>
|
||||
$<TARGET_OBJECTS:webpencode> $<TARGET_OBJECTS:webputils>)
|
||||
if(WEBP_ENABLE_FBOUNDS_SAFETY)
|
||||
# Enable -fbounds-safety only for webputils for now.
|
||||
# Enable -fbounds-safety only for webputils and webpdecode(r) for now.
|
||||
add_definitions(-DWEBP_SUPPORT_FBOUNDS_SAFETY=1)
|
||||
target_compile_options(webputils PRIVATE -fbounds-safety)
|
||||
target_compile_options(webputilsdecode PRIVATE -fbounds-safety)
|
||||
target_compile_options(webpdecode PRIVATE -fbounds-safety)
|
||||
target_compile_options(webpdecoder PRIVATE -fbounds-safety)
|
||||
endif()
|
||||
|
||||
target_link_libraries(webp sharpyuv)
|
||||
|
||||
@@ -106,7 +106,12 @@ WEBP_NODISCARD static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
|
||||
ok = (alpha_data_size >= alpha_decoded_size);
|
||||
} else {
|
||||
assert(dec->method == ALPHA_LOSSLESS_COMPRESSION);
|
||||
ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size);
|
||||
{
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_alpha_data =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, alpha_data,
|
||||
alpha_data_size);
|
||||
ok = VP8LDecodeAlphaHeader(dec, bounded_alpha_data, alpha_data_size);
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
@@ -225,7 +230,11 @@ WEBP_NODISCARD const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
||||
if (dec->alpha_dithering > 0) {
|
||||
uint8_t* const alpha =
|
||||
dec->alpha_plane + io->crop_top * width + io->crop_left;
|
||||
if (!WebPDequantizeLevels(alpha, io->crop_right - io->crop_left,
|
||||
uint8_t* WEBP_BIDI_INDEXABLE const bounded_alpha =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||
uint8_t*, alpha,
|
||||
(size_t)width*(io->crop_bottom - io->crop_top));
|
||||
if (!WebPDequantizeLevels(bounded_alpha, io->crop_right - io->crop_left,
|
||||
io->crop_bottom - io->crop_top, width,
|
||||
dec->alpha_dithering)) {
|
||||
goto Error;
|
||||
|
||||
@@ -144,20 +144,30 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
|
||||
// parse the partitions). The bitreader is only used meaningfully when
|
||||
// there is enough data to begin parsing partition 0.
|
||||
if (last_start != NULL) {
|
||||
VP8BitReaderSetBuffer(&dec->parts[last_part], last_start,
|
||||
mem->buf + mem->end - last_start);
|
||||
const size_t part_size = mem->buf + mem->end - last_start;
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_last_start =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, last_start,
|
||||
part_size);
|
||||
VP8BitReaderSetBuffer(&dec->parts[last_part], bounded_last_start,
|
||||
part_size);
|
||||
}
|
||||
}
|
||||
if (NeedCompressedAlpha(idec)) {
|
||||
ALPHDecoder* const alph_dec = dec->alph_dec;
|
||||
dec->alpha_data += offset;
|
||||
dec->alpha_data_size = dec->alpha_data_size;
|
||||
if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) {
|
||||
if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) {
|
||||
VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec;
|
||||
size_t data_size;
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE bounded_alpha_data;
|
||||
|
||||
assert(dec->alpha_data_size >= ALPHA_HEADER_LEN);
|
||||
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br,
|
||||
dec->alpha_data + ALPHA_HEADER_LEN,
|
||||
dec->alpha_data_size - ALPHA_HEADER_LEN);
|
||||
data_size = dec->alpha_data_size - ALPHA_HEADER_LEN;
|
||||
bounded_alpha_data = WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||
const uint8_t*, dec->alpha_data + ALPHA_HEADER_LEN, data_size);
|
||||
VP8LBitReaderSetBuffer(&alph_vp8l_dec->br, bounded_alpha_data,
|
||||
data_size);
|
||||
} else { // alph_dec->method == ALPHA_NO_COMPRESSION
|
||||
// Nothing special to do in this case.
|
||||
}
|
||||
@@ -165,7 +175,10 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
|
||||
}
|
||||
} else { // Resize lossless bitreader
|
||||
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
|
||||
VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem));
|
||||
const size_t data_size = MemDataSize(mem);
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_new_base =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, new_base, data_size);
|
||||
VP8LBitReaderSetBuffer(&dec->br, bounded_new_base, data_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,7 +341,8 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
|
||||
VP8StatusCode status;
|
||||
WebPHeaderStructure headers;
|
||||
|
||||
headers.data = data;
|
||||
headers.data =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, data, curr_size);
|
||||
headers.data_size = curr_size;
|
||||
headers.have_all_data = 0;
|
||||
status = WebPParseHeaders(&headers);
|
||||
@@ -371,8 +385,13 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
|
||||
// Not enough data bytes to extract VP8 Frame Header.
|
||||
return VP8_STATUS_SUSPENDED;
|
||||
}
|
||||
if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) {
|
||||
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
{
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, data, curr_size);
|
||||
if (!VP8GetInfo(bounded_data, curr_size, idec->chunk_size, &width,
|
||||
&height)) {
|
||||
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
bits = data[0] | (data[1] << 8) | (data[2] << 16);
|
||||
@@ -399,7 +418,8 @@ static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
|
||||
}
|
||||
if (mem->mode == MEM_MODE_APPEND) {
|
||||
// We copy and grab ownership of the partition #0 data.
|
||||
uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
|
||||
uint8_t* WEBP_BIDI_INDEXABLE const part0_buf =
|
||||
(uint8_t*)WebPSafeMalloc(1ULL, part_size);
|
||||
if (part0_buf == NULL) {
|
||||
return VP8_STATUS_OUT_OF_MEMORY;
|
||||
}
|
||||
@@ -660,8 +680,8 @@ WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
|
||||
return NewDecoder(output_buffer, NULL);
|
||||
}
|
||||
|
||||
WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
|
||||
WebPDecoderConfig* config) {
|
||||
WebPIDecoder* WebPIDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, WebPDecoderConfig* config) {
|
||||
WebPIDecoder* idec;
|
||||
WebPBitstreamFeatures tmp_features;
|
||||
WebPBitstreamFeatures* const features =
|
||||
@@ -710,13 +730,16 @@ void WebPIDelete(WebPIDecoder* idec) {
|
||||
//------------------------------------------------------------------------------
|
||||
// Wrapper toward WebPINewDecoder
|
||||
|
||||
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
|
||||
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size)
|
||||
output_buffer,
|
||||
size_t output_buffer_size, int output_stride) {
|
||||
const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
|
||||
WebPIDecoder* idec;
|
||||
|
||||
if (csp >= MODE_YUV) return NULL;
|
||||
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
||||
output_buffer = NULL;
|
||||
output_buffer_size = 0;
|
||||
output_stride = 0;
|
||||
} else { // A buffer was passed. Validate the other params.
|
||||
@@ -734,18 +757,27 @@ WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
|
||||
return idec;
|
||||
}
|
||||
|
||||
WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
|
||||
size_t v_size, int v_stride, uint8_t* a,
|
||||
size_t a_size, int a_stride) {
|
||||
WebPIDecoder* WebPINewYUVA(uint8_t* WEBP_COUNTED_BY(luma_size) luma,
|
||||
size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
|
||||
int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
|
||||
size_t v_size, int v_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size,
|
||||
int a_stride) {
|
||||
const int is_external_memory = (luma != NULL) ? 1 : 0;
|
||||
WebPIDecoder* idec;
|
||||
WEBP_CSP_MODE colorspace;
|
||||
|
||||
if (is_external_memory == 0) { // Overwrite parameters to sane values.
|
||||
luma_size = u_size = v_size = a_size = 0;
|
||||
luma = NULL;
|
||||
luma_size = 0;
|
||||
u = NULL;
|
||||
u_size = 0;
|
||||
v = NULL;
|
||||
v_size = 0;
|
||||
a = NULL;
|
||||
a_size = 0;
|
||||
luma_stride = u_stride = v_stride = a_stride = 0;
|
||||
u = v = a = NULL;
|
||||
colorspace = MODE_YUVA;
|
||||
} else { // A luma buffer was passed. Validate the other parameters.
|
||||
if (u == NULL || v == NULL) return NULL;
|
||||
@@ -777,8 +809,10 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
|
||||
return idec;
|
||||
}
|
||||
|
||||
WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
|
||||
WebPIDecoder* WebPINewYUV(uint8_t* WEBP_COUNTED_BY(luma_size) luma,
|
||||
size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
|
||||
int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
|
||||
size_t v_size, int v_stride) {
|
||||
return WebPINewYUVA(luma, luma_size, luma_stride, u, u_size, u_stride, v,
|
||||
v_size, v_stride, NULL, 0, 0);
|
||||
@@ -797,7 +831,8 @@ static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
|
||||
return VP8_STATUS_SUSPENDED;
|
||||
}
|
||||
|
||||
VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
|
||||
VP8StatusCode WebPIAppend(WebPIDecoder* idec,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size) {
|
||||
VP8StatusCode status;
|
||||
if (idec == NULL || data == NULL) {
|
||||
@@ -818,7 +853,8 @@ VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
|
||||
return IDecode(idec);
|
||||
}
|
||||
|
||||
VP8StatusCode WebPIUpdate(WebPIDecoder* idec, const uint8_t* data,
|
||||
VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size) {
|
||||
VP8StatusCode status;
|
||||
if (idec == NULL || data == NULL) {
|
||||
|
||||
@@ -311,7 +311,7 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
|
||||
uint64_t total_size;
|
||||
size_t rescaler_size;
|
||||
rescaler_t* work;
|
||||
rescaler_t* WEBP_BIDI_INDEXABLE work;
|
||||
WebPRescaler* scalers;
|
||||
const int num_rescalers = has_alpha ? 4 : 3;
|
||||
|
||||
@@ -325,11 +325,11 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
if (p->memory == NULL) {
|
||||
work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
if (work == NULL) {
|
||||
return 0; // memory error
|
||||
}
|
||||
work = (rescaler_t*)p->memory;
|
||||
p->memory = work;
|
||||
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size -
|
||||
rescaler_size);
|
||||
@@ -499,8 +499,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
const int uv_in_height = (io->mb_h + 1) >> 1;
|
||||
// scratch memory for one rescaler
|
||||
const size_t work_size = 2 * (size_t)out_width;
|
||||
rescaler_t* work; // rescalers work area
|
||||
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
||||
rescaler_t* WEBP_BIDI_INDEXABLE work; // rescalers work area
|
||||
uint8_t* WEBP_BIDI_INDEXABLE
|
||||
tmp; // tmp storage for scaled YUV444 samples before RGB conversion
|
||||
uint64_t tmp_size1, tmp_size2, total_size;
|
||||
size_t rescaler_size;
|
||||
WebPRescaler* scalers;
|
||||
@@ -515,11 +516,11 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->memory = WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
if (p->memory == NULL) {
|
||||
work = (rescaler_t*)WebPSafeMalloc(1ULL, (size_t)total_size);
|
||||
if (work == NULL) {
|
||||
return 0; // memory error
|
||||
}
|
||||
work = (rescaler_t*)p->memory;
|
||||
p->memory = work;
|
||||
tmp = (uint8_t*)(work + tmp_size1);
|
||||
|
||||
scalers = (WebPRescaler*)WEBP_ALIGN((const uint8_t*)work + total_size -
|
||||
|
||||
@@ -113,13 +113,14 @@ int VP8SetError(VP8Decoder* const dec, VP8StatusCode error,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int VP8CheckSignature(const uint8_t* const data, size_t data_size) {
|
||||
int VP8CheckSignature(const uint8_t* const WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size) {
|
||||
return (data_size >= 3 && data[0] == 0x9d && data[1] == 0x01 &&
|
||||
data[2] == 0x2a);
|
||||
}
|
||||
|
||||
int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
|
||||
int* const width, int* const height) {
|
||||
int VP8GetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
size_t chunk_size, int* const width, int* const height) {
|
||||
if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
|
||||
return 0; // not enough data
|
||||
}
|
||||
@@ -218,12 +219,13 @@ static int ParseSegmentHeader(VP8BitReader* br, VP8SegmentHeader* hdr,
|
||||
// If we don't even have the partitions' sizes, then VP8_STATUS_NOT_ENOUGH_DATA
|
||||
// is returned, and this is an unrecoverable error.
|
||||
// If the partitions were positioned ok, VP8_STATUS_OK is returned.
|
||||
static VP8StatusCode ParsePartitions(VP8Decoder* const dec, const uint8_t* buf,
|
||||
static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
|
||||
const uint8_t* WEBP_COUNTED_BY(size) buf,
|
||||
size_t size) {
|
||||
VP8BitReader* const br = &dec->br;
|
||||
const uint8_t* sz = buf;
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE sz = buf;
|
||||
const uint8_t* buf_end = buf + size;
|
||||
const uint8_t* part_start;
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE part_start;
|
||||
size_t size_left = size;
|
||||
size_t last_part;
|
||||
size_t p;
|
||||
@@ -279,8 +281,8 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
|
||||
|
||||
// Topmost call
|
||||
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
const uint8_t* buf;
|
||||
size_t buf_size;
|
||||
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
|
||||
VP8FrameHeader* frm_hdr;
|
||||
VP8PictureHeader* pic_hdr;
|
||||
VP8BitReader* br;
|
||||
@@ -294,8 +296,9 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
||||
return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
|
||||
"null VP8Io passed to VP8GetHeaders()");
|
||||
}
|
||||
buf = io->data;
|
||||
buf_size = io->data_size;
|
||||
buf =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, io->data, io->data_size);
|
||||
if (buf_size < 4) {
|
||||
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA, "Truncated header.");
|
||||
}
|
||||
|
||||
@@ -160,24 +160,27 @@ void VP8Delete(VP8Decoder* const dec);
|
||||
// Miscellaneous VP8/VP8L bitstream probing functions.
|
||||
|
||||
// Returns true if the next 3 bytes in data contain the VP8 signature.
|
||||
WEBP_EXTERN int VP8CheckSignature(const uint8_t* const data, size_t data_size);
|
||||
WEBP_EXTERN int VP8CheckSignature(
|
||||
const uint8_t* const WEBP_COUNTED_BY(data_size) data, size_t data_size);
|
||||
|
||||
// Validates the VP8 data-header and retrieves basic header information viz
|
||||
// width and height. Returns 0 in case of formatting error. *width/*height
|
||||
// can be passed NULL.
|
||||
WEBP_EXTERN int VP8GetInfo(
|
||||
const uint8_t* data,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, // data available so far
|
||||
size_t chunk_size, // total data size expected in the chunk
|
||||
int* const width, int* const height);
|
||||
|
||||
// Returns true if the next byte(s) in data is a VP8L signature.
|
||||
WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const data, size_t size);
|
||||
WEBP_EXTERN int VP8LCheckSignature(const uint8_t* const WEBP_COUNTED_BY(size)
|
||||
data,
|
||||
size_t size);
|
||||
|
||||
// Validates the VP8L data-header and retrieves basic header information viz
|
||||
// width, height and alpha. Returns 0 in case of formatting error.
|
||||
// width/height/has_alpha can be passed NULL.
|
||||
WEBP_EXTERN int VP8LGetInfo(const uint8_t* data,
|
||||
WEBP_EXTERN int VP8LGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, // data available so far
|
||||
int* const width, int* const height,
|
||||
int* const has_alpha);
|
||||
|
||||
@@ -263,7 +263,8 @@ struct VP8Decoder {
|
||||
|
||||
// Alpha
|
||||
struct ALPHDecoder* alph_dec; // alpha-plane decoder object
|
||||
const uint8_t* alpha_data; // compressed alpha data (if present)
|
||||
const uint8_t* WEBP_COUNTED_BY(alpha_data_size)
|
||||
alpha_data; // compressed alpha data (if present)
|
||||
size_t alpha_data_size;
|
||||
int is_alpha_decoded; // true if alpha_data is decoded in alpha_plane
|
||||
uint8_t* alpha_plane_mem; // memory allocated for alpha_plane
|
||||
|
||||
@@ -104,7 +104,8 @@ static int DecodeImageStream(int xsize, int ysize, int is_level0,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int VP8LCheckSignature(const uint8_t* const data, size_t size) {
|
||||
int VP8LCheckSignature(const uint8_t* const WEBP_COUNTED_BY(size) data,
|
||||
size_t size) {
|
||||
return (size >= VP8L_FRAME_HEADER_SIZE && data[0] == VP8L_MAGIC_BYTE &&
|
||||
(data[4] >> 5) == 0); // version
|
||||
}
|
||||
@@ -119,8 +120,9 @@ static int ReadImageInfo(VP8LBitReader* const br, int* const width,
|
||||
return !br->eos;
|
||||
}
|
||||
|
||||
int VP8LGetInfo(const uint8_t* data, size_t data_size, int* const width,
|
||||
int* const height, int* const has_alpha) {
|
||||
int VP8LGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* const width, int* const height,
|
||||
int* const has_alpha) {
|
||||
if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
|
||||
return 0; // not enough data
|
||||
} else if (!VP8LCheckSignature(data, data_size)) {
|
||||
@@ -248,10 +250,14 @@ static int ReadHuffmanCodeLengths(VP8LDecoder* const dec,
|
||||
int max_symbol;
|
||||
int prev_code_len = DEFAULT_CODE_LENGTH;
|
||||
HuffmanTables tables;
|
||||
const int* WEBP_BIDI_INDEXABLE const bounded_code_lengths =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(
|
||||
const int*, code_length_code_lengths,
|
||||
NUM_CODE_LENGTH_CODES * sizeof(*code_length_code_lengths));
|
||||
|
||||
if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
|
||||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
|
||||
code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
|
||||
!VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS, bounded_code_lengths,
|
||||
NUM_CODE_LENGTH_CODES)) {
|
||||
goto End;
|
||||
}
|
||||
|
||||
@@ -338,8 +344,11 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
||||
|
||||
ok = ok && !br->eos;
|
||||
if (ok) {
|
||||
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS, code_lengths,
|
||||
alphabet_size);
|
||||
const int* WEBP_BIDI_INDEXABLE const bounded_code_lengths =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const int*, code_lengths,
|
||||
alphabet_size * sizeof(int));
|
||||
size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
|
||||
bounded_code_lengths, alphabet_size);
|
||||
}
|
||||
if (!ok || size == 0) {
|
||||
return VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
@@ -553,13 +562,15 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
|
||||
const int in_height = io->mb_h;
|
||||
const int out_height = io->scaled_height;
|
||||
const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
|
||||
rescaler_t* work; // Rescaler work area.
|
||||
rescaler_t* WEBP_BIDI_INDEXABLE work; // Rescaler work area.
|
||||
const uint64_t scaled_data_size = (uint64_t)out_width;
|
||||
uint32_t* scaled_data; // Temporary storage for scaled BGRA data.
|
||||
uint32_t* WEBP_BIDI_INDEXABLE
|
||||
scaled_data; // Temporary storage for scaled BGRA data.
|
||||
const uint64_t memory_size = sizeof(*dec->rescaler) +
|
||||
work_size * sizeof(*work) +
|
||||
scaled_data_size * sizeof(*scaled_data);
|
||||
uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
|
||||
uint8_t* WEBP_BIDI_INDEXABLE memory =
|
||||
(uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
|
||||
if (memory == NULL) {
|
||||
return VP8LSetError(dec, VP8_STATUS_OUT_OF_MEMORY);
|
||||
}
|
||||
@@ -1684,7 +1695,8 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row,
|
||||
}
|
||||
|
||||
int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
|
||||
const uint8_t* const data, size_t data_size) {
|
||||
const uint8_t* const WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size) {
|
||||
int ok = 0;
|
||||
VP8LDecoder* dec = VP8LNew();
|
||||
|
||||
@@ -1763,7 +1775,12 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
|
||||
|
||||
dec->io = io;
|
||||
dec->status = VP8_STATUS_OK;
|
||||
VP8LInitBitReader(&dec->br, io->data, io->data_size);
|
||||
{
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, io->data,
|
||||
io->data_size);
|
||||
VP8LInitBitReader(&dec->br, bounded_data, io->data_size);
|
||||
}
|
||||
if (!ReadImageInfo(&dec->br, &width, &height, &has_alpha)) {
|
||||
VP8LSetError(dec, VP8_STATUS_BITSTREAM_ERROR);
|
||||
goto Error;
|
||||
|
||||
@@ -105,9 +105,9 @@ struct ALPHDecoder; // Defined in dec/alphai.h.
|
||||
|
||||
// Decodes image header for alpha data stored using lossless compression.
|
||||
// Returns false in case of error.
|
||||
WEBP_NODISCARD int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
|
||||
const uint8_t* const data,
|
||||
size_t data_size);
|
||||
WEBP_NODISCARD int VP8LDecodeAlphaHeader(
|
||||
struct ALPHDecoder* const alph_dec,
|
||||
const uint8_t* const WEBP_COUNTED_BY(data_size) data, size_t data_size);
|
||||
|
||||
// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
|
||||
// already decoded in previous call(s), it will resume decoding from where it
|
||||
|
||||
@@ -61,9 +61,11 @@ WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
|
||||
// and VP8_STATUS_OK otherwise.
|
||||
// In case there are not enough bytes (partial RIFF container), return 0 for
|
||||
// *riff_size. Else return the RIFF size extracted from the header.
|
||||
static VP8StatusCode ParseRIFF(const uint8_t** const data,
|
||||
size_t* const data_size, int have_all_data,
|
||||
size_t* const riff_size) {
|
||||
static VP8StatusCode ParseRIFF(const uint8_t* WEBP_COUNTED_BY(*data_size) *
|
||||
WEBP_SINGLE const data,
|
||||
size_t* WEBP_SINGLE const data_size,
|
||||
int have_all_data,
|
||||
size_t* WEBP_SINGLE const riff_size) {
|
||||
assert(data != NULL);
|
||||
assert(data_size != NULL);
|
||||
assert(riff_size != NULL);
|
||||
@@ -86,8 +88,8 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
|
||||
}
|
||||
// We have a RIFF container. Skip it.
|
||||
*riff_size = size;
|
||||
*data += RIFF_HEADER_SIZE;
|
||||
*data_size -= RIFF_HEADER_SIZE;
|
||||
*data += RIFF_HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
return VP8_STATUS_OK;
|
||||
@@ -100,10 +102,13 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
|
||||
// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
|
||||
// *height_ptr and *flags_ptr are set to the corresponding values extracted
|
||||
// from the VP8X chunk.
|
||||
static VP8StatusCode ParseVP8X(const uint8_t** const data,
|
||||
size_t* const data_size, int* const found_vp8x,
|
||||
int* const width_ptr, int* const height_ptr,
|
||||
uint32_t* const flags_ptr) {
|
||||
static VP8StatusCode ParseVP8X(const uint8_t* WEBP_COUNTED_BY(*data_size) *
|
||||
WEBP_SINGLE const data,
|
||||
size_t* WEBP_SINGLE const data_size,
|
||||
int* WEBP_SINGLE const found_vp8x,
|
||||
int* WEBP_SINGLE const width_ptr,
|
||||
int* WEBP_SINGLE const height_ptr,
|
||||
uint32_t* WEBP_SINGLE const flags_ptr) {
|
||||
const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
|
||||
assert(data != NULL);
|
||||
assert(data_size != NULL);
|
||||
@@ -138,8 +143,8 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
|
||||
if (width_ptr != NULL) *width_ptr = width;
|
||||
if (height_ptr != NULL) *height_ptr = height;
|
||||
// Skip over VP8X header bytes.
|
||||
*data += vp8x_size;
|
||||
*data_size -= vp8x_size;
|
||||
*data += vp8x_size;
|
||||
*found_vp8x = 1;
|
||||
}
|
||||
return VP8_STATUS_OK;
|
||||
@@ -152,13 +157,13 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
|
||||
// VP8_STATUS_OK otherwise.
|
||||
// If an alpha chunk is found, *alpha_data and *alpha_size are set
|
||||
// appropriately.
|
||||
static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
|
||||
size_t* const data_size,
|
||||
size_t const riff_size,
|
||||
const uint8_t** const alpha_data,
|
||||
size_t* const alpha_size) {
|
||||
const uint8_t* buf;
|
||||
static VP8StatusCode ParseOptionalChunks(
|
||||
const uint8_t* WEBP_COUNTED_BY(*data_size) * WEBP_SINGLE const data,
|
||||
size_t* WEBP_SINGLE const data_size, size_t const riff_size,
|
||||
const uint8_t* WEBP_COUNTED_BY(*alpha_size) * WEBP_SINGLE const alpha_data,
|
||||
size_t* WEBP_SINGLE const alpha_size) {
|
||||
size_t buf_size;
|
||||
const uint8_t* WEBP_COUNTED_BY(buf_size) buf;
|
||||
uint32_t total_size = TAG_SIZE + // "WEBP".
|
||||
CHUNK_HEADER_SIZE + // "VP8Xnnnn".
|
||||
VP8X_CHUNK_SIZE; // data.
|
||||
@@ -176,8 +181,8 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
|
||||
uint32_t chunk_size;
|
||||
uint32_t disk_chunk_size; // chunk_size with padding
|
||||
|
||||
*data = buf;
|
||||
*data_size = buf_size;
|
||||
*data = buf;
|
||||
|
||||
if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
|
||||
return VP8_STATUS_NOT_ENOUGH_DATA;
|
||||
@@ -227,16 +232,20 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
|
||||
// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
|
||||
// extracted from the VP8/VP8L chunk header.
|
||||
// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
|
||||
static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
|
||||
size_t* const data_size, int have_all_data,
|
||||
size_t riff_size, size_t* const chunk_size,
|
||||
int* const is_lossless) {
|
||||
const uint8_t* const data = *data_ptr;
|
||||
static VP8StatusCode ParseVP8Header(const uint8_t* WEBP_COUNTED_BY(*data_size) *
|
||||
WEBP_SINGLE const data_ptr,
|
||||
size_t* WEBP_SINGLE const data_size,
|
||||
int have_all_data, size_t riff_size,
|
||||
size_t* WEBP_SINGLE const chunk_size,
|
||||
int* WEBP_SINGLE const is_lossless) {
|
||||
const size_t local_data_size = *data_size;
|
||||
const uint8_t* WEBP_COUNTED_BY(local_data_size) const data = *data_ptr;
|
||||
const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
|
||||
const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
|
||||
const uint32_t minimal_size =
|
||||
TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
|
||||
// "WEBP" + "VP8Lnnnn"
|
||||
(void)local_data_size;
|
||||
assert(data != NULL);
|
||||
assert(data_size != NULL);
|
||||
assert(chunk_size != NULL);
|
||||
@@ -257,8 +266,8 @@ static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
|
||||
}
|
||||
// Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
|
||||
*chunk_size = size;
|
||||
*data_ptr += CHUNK_HEADER_SIZE;
|
||||
*data_size -= CHUNK_HEADER_SIZE;
|
||||
*data_ptr += CHUNK_HEADER_SIZE;
|
||||
*is_lossless = is_vp8l;
|
||||
} else {
|
||||
// Raw VP8/VP8L bitstream (no header).
|
||||
@@ -282,12 +291,13 @@ static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
|
||||
// RIFF + VP8X + (optional chunks) + VP8(L)
|
||||
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
static VP8StatusCode ParseHeadersInternal(const uint8_t* data, size_t data_size,
|
||||
int* const width, int* const height,
|
||||
int* const has_alpha,
|
||||
int* const has_animation,
|
||||
int* const format,
|
||||
WebPHeaderStructure* const headers) {
|
||||
static VP8StatusCode ParseHeadersInternal(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size_param) data_param,
|
||||
size_t data_size_param, int* const width, int* const height,
|
||||
int* const has_alpha, int* const has_animation, int* const format,
|
||||
WebPHeaderStructure* const headers) {
|
||||
size_t data_size = data_size_param;
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data = data_param;
|
||||
int canvas_width = 0;
|
||||
int canvas_height = 0;
|
||||
int image_width = 0;
|
||||
@@ -348,11 +358,16 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data, size_t data_size,
|
||||
// Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
|
||||
if ((found_riff && found_vp8x) ||
|
||||
(!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
|
||||
size_t local_alpha_data_size = 0;
|
||||
const uint8_t* WEBP_COUNTED_BY(local_alpha_data_size) local_alpha_data =
|
||||
NULL;
|
||||
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
|
||||
&hdrs.alpha_data, &hdrs.alpha_data_size);
|
||||
&local_alpha_data, &local_alpha_data_size);
|
||||
if (status != VP8_STATUS_OK) {
|
||||
goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
|
||||
}
|
||||
hdrs.alpha_data = local_alpha_data;
|
||||
hdrs.alpha_data_size = local_alpha_data_size;
|
||||
}
|
||||
|
||||
// Skip over VP8/VP8L header.
|
||||
@@ -423,8 +438,13 @@ VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
|
||||
int has_animation = 0;
|
||||
assert(headers != NULL);
|
||||
// fill out headers, ignore width/height/has_alpha.
|
||||
status = ParseHeadersInternal(headers->data, headers->data_size, NULL, NULL,
|
||||
NULL, &has_animation, NULL, headers);
|
||||
{
|
||||
const uint8_t* WEBP_BIDI_INDEXABLE const bounded_data =
|
||||
WEBP_UNSAFE_FORGE_BIDI_INDEXABLE(const uint8_t*, headers->data,
|
||||
headers->data_size);
|
||||
status = ParseHeadersInternal(bounded_data, headers->data_size, NULL, NULL,
|
||||
NULL, &has_animation, NULL, headers);
|
||||
}
|
||||
if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
|
||||
// The WebPDemux API + libwebp can be used to decode individual
|
||||
// uncomposited frames or the WebPAnimDecoder can be used to fully
|
||||
@@ -449,9 +469,9 @@ void WebPResetDecParams(WebPDecParams* const params) {
|
||||
// "Into" decoding variants
|
||||
|
||||
// Main flow
|
||||
WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
|
||||
size_t data_size,
|
||||
WebPDecParams* const params) {
|
||||
WEBP_NODISCARD static VP8StatusCode DecodeInto(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
|
||||
WebPDecParams* const params) {
|
||||
VP8StatusCode status;
|
||||
VP8Io io;
|
||||
WebPHeaderStructure headers;
|
||||
@@ -531,11 +551,10 @@ WEBP_NODISCARD static VP8StatusCode DecodeInto(const uint8_t* const data,
|
||||
}
|
||||
|
||||
// Helpers
|
||||
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
|
||||
const uint8_t* const data,
|
||||
size_t data_size,
|
||||
uint8_t* const rgba,
|
||||
int stride, size_t size) {
|
||||
WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(
|
||||
WEBP_CSP_MODE colorspace,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) const data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) const rgba, int stride, size_t size) {
|
||||
WebPDecParams params;
|
||||
WebPDecBuffer buf;
|
||||
if (rgba == NULL || !WebPInitDecBuffer(&buf)) {
|
||||
@@ -554,34 +573,47 @@ WEBP_NODISCARD static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
|
||||
return rgba;
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
|
||||
uint8_t* output, size_t size, int stride) {
|
||||
uint8_t* WebPDecodeRGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
|
||||
int stride) {
|
||||
return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
|
||||
uint8_t* output, size_t size, int stride) {
|
||||
uint8_t* WebPDecodeRGBAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
|
||||
int stride) {
|
||||
return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
|
||||
uint8_t* output, size_t size, int stride) {
|
||||
uint8_t* WebPDecodeARGBInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
|
||||
int stride) {
|
||||
return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
|
||||
uint8_t* output, size_t size, int stride) {
|
||||
uint8_t* WebPDecodeBGRInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
|
||||
int stride) {
|
||||
return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
|
||||
uint8_t* output, size_t size, int stride) {
|
||||
uint8_t* WebPDecodeBGRAInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(size) output, size_t size,
|
||||
int stride) {
|
||||
return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, uint8_t* luma,
|
||||
size_t luma_size, int luma_stride, uint8_t* u,
|
||||
size_t u_size, int u_stride, uint8_t* v,
|
||||
uint8_t* WebPDecodeYUVInto(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(luma_size) luma,
|
||||
size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size,
|
||||
int u_stride, uint8_t* WEBP_COUNTED_BY(v_size) v,
|
||||
size_t v_size, int v_stride) {
|
||||
WebPDecParams params;
|
||||
WebPDecBuffer output;
|
||||
@@ -608,7 +640,8 @@ uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size, uint8_t* luma,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
|
||||
const uint8_t* const data,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
const data,
|
||||
size_t data_size, int* const width,
|
||||
int* const height,
|
||||
WebPDecBuffer* const keep_info) {
|
||||
@@ -640,34 +673,34 @@ WEBP_NODISCARD static uint8_t* Decode(WEBP_CSP_MODE mode,
|
||||
return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
uint8_t* WebPDecodeRGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
return Decode(MODE_RGB, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
uint8_t* WebPDecodeRGBA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
return Decode(MODE_RGBA, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
uint8_t* WebPDecodeARGB(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
return Decode(MODE_ARGB, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
uint8_t* WebPDecodeBGR(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
return Decode(MODE_BGR, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
uint8_t* WebPDecodeBGRA(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
return Decode(MODE_BGRA, data, data_size, width, height, NULL);
|
||||
}
|
||||
|
||||
uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height, uint8_t** u, uint8_t** v, int* stride,
|
||||
int* uv_stride) {
|
||||
uint8_t* WebPDecodeYUV(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height, uint8_t** u,
|
||||
uint8_t** v, int* stride, int* uv_stride) {
|
||||
// data, width and height are checked by Decode().
|
||||
if (u == NULL || v == NULL || stride == NULL || uv_stride == NULL) {
|
||||
return NULL;
|
||||
@@ -695,7 +728,9 @@ static void DefaultFeatures(WebPBitstreamFeatures* const features) {
|
||||
WEBP_UNSAFE_MEMSET(features, 0, sizeof(*features));
|
||||
}
|
||||
|
||||
static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
|
||||
static VP8StatusCode GetFeatures(const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
const data,
|
||||
size_t data_size,
|
||||
WebPBitstreamFeatures* const features) {
|
||||
if (features == NULL || data == NULL) {
|
||||
return VP8_STATUS_INVALID_PARAM;
|
||||
@@ -711,8 +746,8 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
|
||||
//------------------------------------------------------------------------------
|
||||
// WebPGetInfo()
|
||||
|
||||
int WebPGetInfo(const uint8_t* data, size_t data_size, int* width,
|
||||
int* height) {
|
||||
int WebPGetInfo(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, int* width, int* height) {
|
||||
WebPBitstreamFeatures features;
|
||||
|
||||
if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
|
||||
@@ -802,7 +837,9 @@ int WebPValidateDecoderConfig(const WebPDecoderConfig* config) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
|
||||
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
data,
|
||||
size_t data_size,
|
||||
WebPBitstreamFeatures* features,
|
||||
int version) {
|
||||
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
|
||||
@@ -814,8 +851,8 @@ VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
|
||||
return GetFeatures(data, data_size, features);
|
||||
}
|
||||
|
||||
VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
||||
WebPDecoderConfig* config) {
|
||||
VP8StatusCode WebPDecode(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, WebPDecoderConfig* config) {
|
||||
WebPDecParams params;
|
||||
VP8StatusCode status;
|
||||
|
||||
|
||||
@@ -61,15 +61,16 @@ void WebPResetDecParams(WebPDecParams* const params);
|
||||
|
||||
// Structure storing a description of the RIFF headers.
|
||||
typedef struct {
|
||||
const uint8_t* data; // input buffer
|
||||
size_t data_size; // input buffer size
|
||||
int have_all_data; // true if all data is known to be available
|
||||
size_t offset; // offset to main data chunk (VP8 or VP8L)
|
||||
const uint8_t* alpha_data; // points to alpha chunk (if present)
|
||||
size_t alpha_data_size; // alpha chunk size
|
||||
size_t compressed_size; // VP8/VP8L compressed data size
|
||||
size_t riff_size; // size of the riff payload (or 0 if absent)
|
||||
int is_lossless; // true if a VP8L chunk is present
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data; // input buffer
|
||||
size_t data_size; // input buffer size
|
||||
int have_all_data; // true if all data is known to be available
|
||||
size_t offset; // offset to main data chunk (VP8 or VP8L)
|
||||
const uint8_t* WEBP_COUNTED_BY(alpha_data_size)
|
||||
alpha_data; // points to alpha chunk (if present)
|
||||
size_t alpha_data_size; // alpha chunk size
|
||||
size_t compressed_size; // VP8/VP8L compressed data size
|
||||
size_t riff_size; // size of the riff payload (or 0 if absent)
|
||||
int is_lossless; // true if a VP8L chunk is present
|
||||
} WebPHeaderStructure;
|
||||
|
||||
// Skips over all valid chunks prior to the first VP8/VP8L frame header.
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
#include "src/webp/config.h"
|
||||
#endif
|
||||
|
||||
#include "src/dec/common_dec.h"
|
||||
#include "src/dsp/cpu.h"
|
||||
#include "src/utils/bounds_safety.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "src/webp/types.h"
|
||||
|
||||
WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
|
||||
@@ -229,9 +231,9 @@ extern VP8WHT VP8TransformWHT;
|
||||
// *dst is the destination block, with stride BPS. Boundary samples are
|
||||
// assumed accessible when needed.
|
||||
typedef void (*VP8PredFunc)(uint8_t* dst);
|
||||
extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
|
||||
extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
|
||||
extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
|
||||
extern VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
|
||||
extern VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
|
||||
extern VP8PredFunc VP8PredLuma4[NUM_BMODES];
|
||||
|
||||
// clipping tables (for filtering)
|
||||
extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127]
|
||||
@@ -294,7 +296,7 @@ typedef void (*WebPUpsampleLinePairFunc)(
|
||||
#ifdef FANCY_UPSAMPLING
|
||||
|
||||
// Fancy upsampling functions to convert YUV to RGB(A) modes
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
|
||||
extern WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
|
||||
|
||||
#endif // FANCY_UPSAMPLING
|
||||
|
||||
@@ -311,7 +313,7 @@ void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
|
||||
int width, int height, WebPSamplerRowFunc func);
|
||||
|
||||
// Sampling functions to convert rows of YUV to RGB(A)
|
||||
extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */];
|
||||
extern WebPSamplerRowFunc WebPSamplers[MODE_LAST];
|
||||
|
||||
// General function for converting two lines of ARGB or RGBA.
|
||||
// 'alpha_is_last' should be true if 0xff000000 is stored in memory as
|
||||
@@ -324,7 +326,7 @@ typedef void (*WebPYUV444Converter)(const uint8_t* WEBP_RESTRICT y,
|
||||
const uint8_t* WEBP_RESTRICT v,
|
||||
uint8_t* WEBP_RESTRICT dst, int len);
|
||||
|
||||
extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
|
||||
extern WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
|
||||
|
||||
// Must be called before using the WebPUpsamplers[] (and for premultiplied
|
||||
// colorspaces like rgbA, rgbA4444, etc)
|
||||
|
||||
@@ -52,39 +52,39 @@ WEBP_EXTERN int WebPGetDecoderVersion(void);
|
||||
// RIFF + VP8X + (optional chunks) + VP8(L)
|
||||
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN int WebPGetInfo(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
|
||||
// with the dimensions in *width and *height. The ordering of samples in
|
||||
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
|
||||
// The returned pointer should be deleted calling WebPFree().
|
||||
// Returns NULL in case of error.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBA(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGB(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRA(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
|
||||
// If the bitstream contains transparency, it is ignored.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGB(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height);
|
||||
|
||||
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
|
||||
// returned is the Y samples buffer. Upon return, *u and *v will point to
|
||||
@@ -96,11 +96,10 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGR(const uint8_t* data,
|
||||
// 'width' and 'height' may be NULL, the other pointers must not be.
|
||||
// Returns NULL in case of error.
|
||||
// (*) Also named Y'CbCr. See: https://en.wikipedia.org/wiki/YCbCr
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data,
|
||||
size_t data_size, int* width,
|
||||
int* height, uint8_t** u,
|
||||
uint8_t** v, int* stride,
|
||||
int* uv_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
int* width, int* height, uint8_t** u, uint8_t** v, int* stride,
|
||||
int* uv_stride);
|
||||
|
||||
// These five functions are variants of the above ones, that decode the image
|
||||
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
|
||||
@@ -111,27 +110,28 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUV(const uint8_t* data,
|
||||
// between scanlines. Hence, output_buffer_size is expected to be at least
|
||||
// output_stride x picture-height.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBAInto(
|
||||
const uint8_t* data, size_t data_size, uint8_t* output_buffer,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeARGBInto(
|
||||
const uint8_t* data, size_t data_size, uint8_t* output_buffer,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRAInto(
|
||||
const uint8_t* data, size_t data_size, uint8_t* output_buffer,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
|
||||
// RGB and BGR variants. Here too the transparency information, if present,
|
||||
// will be dropped and ignored.
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(const uint8_t* data,
|
||||
size_t data_size,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(const uint8_t* data,
|
||||
size_t data_size,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeRGBInto(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
|
||||
// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
|
||||
// into pre-allocated luma/chroma plane buffers. This function requires the
|
||||
@@ -141,9 +141,10 @@ WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeBGRInto(const uint8_t* data,
|
||||
// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
|
||||
// during decoding (or because some buffers were found to be too small).
|
||||
WEBP_NODISCARD WEBP_EXTERN uint8_t* WebPDecodeYUVInto(
|
||||
const uint8_t* data, size_t data_size, uint8_t* luma, size_t luma_size,
|
||||
int luma_stride, uint8_t* u, size_t u_size, int u_stride, uint8_t* v,
|
||||
size_t v_size, int v_stride);
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Output colorspaces and buffer
|
||||
@@ -312,10 +313,10 @@ WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewDecoder(
|
||||
// colorspace 'csp' is taken into account for allocating this buffer. All other
|
||||
// parameters are ignored.
|
||||
// Returns NULL if the allocation failed, or if some parameters are invalid.
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
|
||||
uint8_t* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
int output_stride);
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(
|
||||
WEBP_CSP_MODE csp,
|
||||
uint8_t* WEBP_COUNTED_BY(output_buffer_size) output_buffer,
|
||||
size_t output_buffer_size, int output_stride);
|
||||
|
||||
// This function allocates and initializes an incremental-decoder object, which
|
||||
// will output the raw luma/chroma samples into a preallocated planes if
|
||||
@@ -329,15 +330,17 @@ WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp,
|
||||
// MODE_YUVA) when decoding starts. All parameters are then ignored.
|
||||
// Returns NULL if the allocation failed or if a parameter is invalid.
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUVA(
|
||||
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size,
|
||||
int u_stride, uint8_t* v, size_t v_size, int v_stride, uint8_t* a,
|
||||
size_t a_size, int a_stride);
|
||||
uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(a_size) a, size_t a_size, int a_stride);
|
||||
|
||||
// Deprecated version of the above, without the alpha plane.
|
||||
// Kept for backward compatibility.
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPINewYUV(
|
||||
uint8_t* luma, size_t luma_size, int luma_stride, uint8_t* u, size_t u_size,
|
||||
int u_stride, uint8_t* v, size_t v_size, int v_stride);
|
||||
uint8_t* WEBP_COUNTED_BY(luma_size) luma, size_t luma_size, int luma_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(u_size) u, size_t u_size, int u_stride,
|
||||
uint8_t* WEBP_COUNTED_BY(v_size) v, size_t v_size, int v_stride);
|
||||
|
||||
// Deletes the WebPIDecoder object and associated memory. Must always be called
|
||||
// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
|
||||
@@ -346,7 +349,9 @@ WEBP_EXTERN void WebPIDelete(WebPIDecoder* idec);
|
||||
// Copies and decodes the next available data. Returns VP8_STATUS_OK when
|
||||
// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
|
||||
// data is expected. Returns error in other cases.
|
||||
WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
|
||||
WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
data,
|
||||
size_t data_size);
|
||||
|
||||
// A variant of the above function to be used when data buffer contains
|
||||
@@ -354,7 +359,9 @@ WEBP_EXTERN VP8StatusCode WebPIAppend(WebPIDecoder* idec, const uint8_t* data,
|
||||
// to the internal memory.
|
||||
// Note that the value of the 'data' pointer can change between calls to
|
||||
// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
|
||||
WEBP_EXTERN VP8StatusCode WebPIUpdate(WebPIDecoder* idec, const uint8_t* data,
|
||||
WEBP_EXTERN VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
data,
|
||||
size_t data_size);
|
||||
|
||||
// Returns the RGB/A image decoded so far. Returns NULL if output params
|
||||
@@ -441,8 +448,9 @@ struct WebPBitstreamFeatures {
|
||||
};
|
||||
|
||||
// Internal, version-checked, entry point
|
||||
WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t,
|
||||
WebPBitstreamFeatures*, int);
|
||||
WEBP_EXTERN VP8StatusCode
|
||||
WebPGetFeaturesInternal(const uint8_t* WEBP_COUNTED_BY(data_size),
|
||||
size_t data_size, WebPBitstreamFeatures*, int);
|
||||
|
||||
// Retrieve features from the bitstream. The *features structure is filled
|
||||
// with information gathered from the bitstream.
|
||||
@@ -455,8 +463,9 @@ WEBP_EXTERN VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t,
|
||||
// RIFF + VP8X + (optional chunks) + VP8(L)
|
||||
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
|
||||
static WEBP_INLINE VP8StatusCode WebPGetFeatures(
|
||||
const uint8_t* data, size_t data_size, WebPBitstreamFeatures* features) {
|
||||
static WEBP_INLINE VP8StatusCode
|
||||
WebPGetFeatures(const uint8_t* WEBP_COUNTED_BY(data_size) data,
|
||||
size_t data_size, WebPBitstreamFeatures* features) {
|
||||
return WebPGetFeaturesInternal(data, data_size, features,
|
||||
WEBP_DECODER_ABI_VERSION);
|
||||
}
|
||||
@@ -516,14 +525,16 @@ WEBP_NODISCARD WEBP_EXTERN int WebPValidateDecoderConfig(
|
||||
// The return WebPIDecoder object must always be deleted calling WebPIDelete().
|
||||
// Returns NULL in case of error (and config->status will then reflect
|
||||
// the error condition, if available).
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(const uint8_t* data,
|
||||
size_t data_size,
|
||||
WebPDecoderConfig* config);
|
||||
WEBP_NODISCARD WEBP_EXTERN WebPIDecoder* WebPIDecode(
|
||||
const uint8_t* WEBP_COUNTED_BY(data_size) data, size_t data_size,
|
||||
WebPDecoderConfig* config);
|
||||
|
||||
// Non-incremental version. This version decodes the full data at once, taking
|
||||
// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
|
||||
// if the decoding was successful). Note that 'config' cannot be NULL.
|
||||
WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
|
||||
WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* WEBP_COUNTED_BY(data_size)
|
||||
data,
|
||||
size_t data_size,
|
||||
WebPDecoderConfig* config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user