mirror of
https://github.com/webmproject/libwebp.git
synced 2025-10-01 07:01:16 +02:00
Merge "Add fbounds-safety annotations in quant_levels_dec_utils.c/.h
." into main
This commit is contained in:
@@ -29,6 +29,7 @@ WEBP_ASSUME_UNSAFE_INDEXABLE_ABI
|
|||||||
#define FIX 16 // fix-point precision for averaging
|
#define FIX 16 // fix-point precision for averaging
|
||||||
#define LFIX 2 // extra precision for look-up table
|
#define LFIX 2 // extra precision for look-up table
|
||||||
#define LUT_SIZE ((1 << (8 + LFIX)) - 1) // look-up table size
|
#define LUT_SIZE ((1 << (8 + LFIX)) - 1) // look-up table size
|
||||||
|
#define CORRECTION_LUT_SIZE (1 + 2 * LUT_SIZE)
|
||||||
|
|
||||||
#if defined(USE_DITHERING)
|
#if defined(USE_DITHERING)
|
||||||
|
|
||||||
@@ -46,11 +47,11 @@ static const uint8_t kOrderedDither[DSIZE][DSIZE] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int width, height; // dimension
|
int width, height; // dimension
|
||||||
int stride; // stride in bytes
|
int stride; // stride in bytes
|
||||||
int row; // current input row being processed
|
int row; // current input row being processed
|
||||||
uint8_t* src; // input pointer
|
uint8_t* WEBP_INDEXABLE src; // input pointer
|
||||||
uint8_t* dst; // output pointer
|
uint8_t* WEBP_INDEXABLE dst; // output pointer
|
||||||
|
|
||||||
int radius; // filter radius (=delay)
|
int radius; // filter radius (=delay)
|
||||||
int scale; // normalization factor, in FIX bits precision
|
int scale; // normalization factor, in FIX bits precision
|
||||||
@@ -58,18 +59,19 @@ typedef struct {
|
|||||||
void* mem; // all memory
|
void* mem; // all memory
|
||||||
|
|
||||||
// various scratch buffers
|
// various scratch buffers
|
||||||
uint16_t* start;
|
uint16_t* WEBP_INDEXABLE start;
|
||||||
uint16_t* cur;
|
uint16_t* WEBP_INDEXABLE cur;
|
||||||
uint16_t* end;
|
uint16_t* WEBP_BIDI_INDEXABLE end;
|
||||||
uint16_t* top;
|
uint16_t* WEBP_INDEXABLE top;
|
||||||
uint16_t* average;
|
uint16_t* WEBP_COUNTED_BY(width) average;
|
||||||
|
|
||||||
// input levels distribution
|
// input levels distribution
|
||||||
int num_levels; // number of quantized levels
|
int num_levels; // number of quantized levels
|
||||||
int min, max; // min and max level values
|
int min, max; // min and max level values
|
||||||
int min_level_dist; // smallest distance between two consecutive levels
|
int min_level_dist; // smallest distance between two consecutive levels
|
||||||
|
|
||||||
int16_t* correction; // size = 1 + 2*LUT_SIZE -> ~4k memory
|
// size = 1 + 2*LUT_SIZE -> ~4k memory
|
||||||
|
int16_t* WEBP_COUNTED_BY_OR_NULL(CORRECTION_LUT_SIZE) correction;
|
||||||
} SmoothParams;
|
} SmoothParams;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -82,11 +84,11 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
|
|||||||
|
|
||||||
// vertical accumulation
|
// vertical accumulation
|
||||||
static void VFilter(SmoothParams* const p) {
|
static void VFilter(SmoothParams* const p) {
|
||||||
const uint8_t* src = p->src;
|
const uint8_t* WEBP_INDEXABLE src = p->src;
|
||||||
const int w = p->width;
|
const int w = p->width;
|
||||||
uint16_t* const cur = p->cur;
|
uint16_t* const WEBP_INDEXABLE cur = p->cur;
|
||||||
const uint16_t* const top = p->top;
|
const uint16_t* const WEBP_INDEXABLE top = p->top;
|
||||||
uint16_t* const out = p->end;
|
uint16_t* const WEBP_INDEXABLE out = p->end;
|
||||||
uint16_t sum = 0; // all arithmetic is modulo 16bit
|
uint16_t sum = 0; // all arithmetic is modulo 16bit
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
@@ -111,8 +113,8 @@ static void VFilter(SmoothParams* const p) {
|
|||||||
// horizontal accumulation. We use mirror replication of missing pixels, as it's
|
// horizontal accumulation. We use mirror replication of missing pixels, as it's
|
||||||
// a little easier to implement (surprisingly).
|
// a little easier to implement (surprisingly).
|
||||||
static void HFilter(SmoothParams* const p) {
|
static void HFilter(SmoothParams* const p) {
|
||||||
const uint16_t* const in = p->end;
|
const uint16_t* const WEBP_INDEXABLE in = p->end;
|
||||||
uint16_t* const out = p->average;
|
uint16_t* const WEBP_INDEXABLE out = p->average;
|
||||||
const uint32_t scale = p->scale;
|
const uint32_t scale = p->scale;
|
||||||
const int w = p->width;
|
const int w = p->width;
|
||||||
const int r = p->radius;
|
const int r = p->radius;
|
||||||
@@ -135,13 +137,16 @@ static void HFilter(SmoothParams* const p) {
|
|||||||
|
|
||||||
// emit one filtered output row
|
// emit one filtered output row
|
||||||
static void ApplyFilter(SmoothParams* const p) {
|
static void ApplyFilter(SmoothParams* const p) {
|
||||||
const uint16_t* const average = p->average;
|
const uint16_t* const WEBP_INDEXABLE average = p->average;
|
||||||
const int w = p->width;
|
const int w = p->width;
|
||||||
const int16_t* const correction = p->correction;
|
// correction is WEBP_COUNTED_BY, pointing to the start of the LUT.
|
||||||
|
// We need the middle pointer for negative indexing.
|
||||||
|
const int16_t* const WEBP_BIDI_INDEXABLE correction =
|
||||||
|
p->correction + LUT_SIZE;
|
||||||
#if defined(USE_DITHERING)
|
#if defined(USE_DITHERING)
|
||||||
const uint8_t* const dither = kOrderedDither[p->row % DSIZE];
|
const uint8_t* const dither = kOrderedDither[p->row % DSIZE];
|
||||||
#endif
|
#endif
|
||||||
uint8_t* const dst = p->dst;
|
uint8_t* const WEBP_INDEXABLE dst = p->dst;
|
||||||
int x;
|
int x;
|
||||||
for (x = 0; x < w; ++x) {
|
for (x = 0; x < w; ++x) {
|
||||||
const int v = dst[x];
|
const int v = dst[x];
|
||||||
@@ -160,7 +165,8 @@ static void ApplyFilter(SmoothParams* const p) {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Initialize correction table
|
// Initialize correction table
|
||||||
|
|
||||||
static void InitCorrectionLUT(int16_t* const lut, int min_dist) {
|
static void InitCorrectionLUT(
|
||||||
|
int16_t* const WEBP_COUNTED_BY(CORRECTION_LUT_SIZE) lut_ptr, int min_dist) {
|
||||||
// The correction curve is:
|
// The correction curve is:
|
||||||
// f(x) = x for x <= threshold2
|
// f(x) = x for x <= threshold2
|
||||||
// f(x) = 0 for x >= threshold1
|
// f(x) = 0 for x >= threshold1
|
||||||
@@ -171,6 +177,9 @@ static void InitCorrectionLUT(int16_t* const lut, int min_dist) {
|
|||||||
const int threshold2 = (3 * threshold1) >> 2;
|
const int threshold2 = (3 * threshold1) >> 2;
|
||||||
const int max_threshold = threshold2 << DFIX;
|
const int max_threshold = threshold2 << DFIX;
|
||||||
const int delta = threshold1 - threshold2;
|
const int delta = threshold1 - threshold2;
|
||||||
|
// lut_ptr is WEBP_COUNTED_BY, pointing to the start of the LUT.
|
||||||
|
// We need the middle pointer (lut) for negative indexing.
|
||||||
|
int16_t* const WEBP_BIDI_INDEXABLE lut = lut_ptr + LUT_SIZE;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i <= LUT_SIZE; ++i) {
|
for (i = 1; i <= LUT_SIZE; ++i) {
|
||||||
int c = (i <= threshold2) ? (i << DFIX)
|
int c = (i <= threshold2) ? (i << DFIX)
|
||||||
@@ -186,7 +195,7 @@ static void InitCorrectionLUT(int16_t* const lut, int min_dist) {
|
|||||||
static void CountLevels(SmoothParams* const p) {
|
static void CountLevels(SmoothParams* const p) {
|
||||||
int i, j, last_level;
|
int i, j, last_level;
|
||||||
uint8_t used_levels[256] = {0};
|
uint8_t used_levels[256] = {0};
|
||||||
const uint8_t* data = p->src;
|
const uint8_t* WEBP_INDEXABLE data = p->src;
|
||||||
p->min = 255;
|
p->min = 255;
|
||||||
p->max = 0;
|
p->max = 0;
|
||||||
for (j = 0; j < p->height; ++j) {
|
for (j = 0; j < p->height; ++j) {
|
||||||
@@ -216,15 +225,16 @@ static void CountLevels(SmoothParams* const p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all params.
|
// Initialize all params.
|
||||||
static int InitParams(uint8_t* const data, int width, int height, int stride,
|
static int InitParams(uint8_t* WEBP_SIZED_BY((size_t)stride* height) const data,
|
||||||
int radius, SmoothParams* const p) {
|
int width, int height, int stride, int radius,
|
||||||
|
SmoothParams* const p) {
|
||||||
const int R = 2 * radius + 1; // total size of the kernel
|
const int R = 2 * radius + 1; // total size of the kernel
|
||||||
|
|
||||||
const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start);
|
const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start);
|
||||||
const size_t size_m = width * sizeof(*p->average);
|
const size_t size_m = width * sizeof(*p->average);
|
||||||
const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction);
|
const size_t size_lut = CORRECTION_LUT_SIZE * sizeof(*p->correction);
|
||||||
const size_t total_size = size_scratch_m + size_m + size_lut;
|
const size_t total_size = size_scratch_m + size_m + size_lut;
|
||||||
uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size);
|
uint8_t* WEBP_BIDI_INDEXABLE mem = (uint8_t*)WebPSafeMalloc(1U, total_size);
|
||||||
|
|
||||||
if (mem == NULL) return 0;
|
if (mem == NULL) return 0;
|
||||||
p->mem = (void*)mem;
|
p->mem = (void*)mem;
|
||||||
@@ -236,10 +246,10 @@ static int InitParams(uint8_t* const data, int width, int height, int stride,
|
|||||||
WEBP_UNSAFE_MEMSET(p->top, 0, width * sizeof(*p->top));
|
WEBP_UNSAFE_MEMSET(p->top, 0, width * sizeof(*p->top));
|
||||||
mem += size_scratch_m;
|
mem += size_scratch_m;
|
||||||
|
|
||||||
|
p->width = width;
|
||||||
p->average = (uint16_t*)mem;
|
p->average = (uint16_t*)mem;
|
||||||
mem += size_m;
|
mem += size_m;
|
||||||
|
|
||||||
p->width = width;
|
|
||||||
p->height = height;
|
p->height = height;
|
||||||
p->stride = stride;
|
p->stride = stride;
|
||||||
p->src = data;
|
p->src = data;
|
||||||
@@ -251,8 +261,9 @@ static int InitParams(uint8_t* const data, int width, int height, int stride,
|
|||||||
// analyze the input distribution so we can best-fit the threshold
|
// analyze the input distribution so we can best-fit the threshold
|
||||||
CountLevels(p);
|
CountLevels(p);
|
||||||
|
|
||||||
// correction table
|
// correction table. p->correction is WEBP_COUNTED_BY(CORRECTION_LUT_SIZE).
|
||||||
p->correction = ((int16_t*)mem) + LUT_SIZE;
|
// It points to the start of the buffer.
|
||||||
|
p->correction = ((int16_t*)mem);
|
||||||
InitCorrectionLUT(p->correction, p->min_level_dist);
|
InitCorrectionLUT(p->correction, p->min_level_dist);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -260,8 +271,9 @@ static int InitParams(uint8_t* const data, int width, int height, int stride,
|
|||||||
|
|
||||||
static void CleanupParams(SmoothParams* const p) { WebPSafeFree(p->mem); }
|
static void CleanupParams(SmoothParams* const p) { WebPSafeFree(p->mem); }
|
||||||
|
|
||||||
int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
|
int WebPDequantizeLevels(uint8_t* WEBP_SIZED_BY((size_t)stride* height)
|
||||||
int strength) {
|
const data,
|
||||||
|
int width, int height, int stride, int strength) {
|
||||||
int radius = 4 * strength / 100;
|
int radius = 4 * strength / 100;
|
||||||
|
|
||||||
if (strength < 0 || strength > 100) return 0;
|
if (strength < 0 || strength > 100) return 0;
|
||||||
|
@@ -28,8 +28,9 @@ extern "C" {
|
|||||||
// Strength is in [0..100] and controls the amount of dithering applied.
|
// Strength is in [0..100] and controls the amount of dithering applied.
|
||||||
// Returns false in case of error (data is NULL, invalid parameters,
|
// Returns false in case of error (data is NULL, invalid parameters,
|
||||||
// malloc failure, ...).
|
// malloc failure, ...).
|
||||||
int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
|
int WebPDequantizeLevels(uint8_t* WEBP_SIZED_BY((size_t)stride* height)
|
||||||
int strength);
|
const data,
|
||||||
|
int width, int height, int stride, int strength);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
Reference in New Issue
Block a user