cosmetics & warnings

- remove some unused functions
- move global arrays from data to read only section
- explicitly cast malloc returns; not specifically necessary, but helps
  show intent
- miscellaneous formatting

Change-Id: Ib15fe5b37fe6c29c369ad928bdc3a7290cd13c84
This commit is contained in:
James Zern 2012-01-27 17:39:47 -08:00
parent b9600308e8
commit a0b2736d79
18 changed files with 280 additions and 299 deletions

View File

@ -443,7 +443,7 @@ static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
typedef enum { typedef enum {
PNG = 0, PNG = 0,
JPEG, JPEG,
UNSUPPORTED, UNSUPPORTED
} InputFileFormat; } InputFileFormat;
static InputFileFormat GetImageType(FILE* in_file) { static InputFileFormat GetImageType(FILE* in_file) {

View File

@ -140,38 +140,38 @@ static void WebPDataFree(WebPData* const webpdata) {
memset(webpdata, 0, sizeof(*webpdata)); memset(webpdata, 0, sizeof(*webpdata));
} }
#define RETURN_IF_ERROR(ERR_MSG) \ #define RETURN_IF_ERROR(ERR_MSG) \
if (err != WEBP_MUX_OK) { \ if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG); \ fprintf(stderr, ERR_MSG); \
return err; \ return err; \
} }
#define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \ #define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \
if (err != WEBP_MUX_OK) { \ if (err != WEBP_MUX_OK) { \
fprintf(stderr, ERR_MSG, FORMAT_STR); \ fprintf(stderr, ERR_MSG, FORMAT_STR); \
return err; \ return err; \
} }
#define ERROR_GOTO1(ERR_MSG, LABEL) \ #define ERROR_GOTO1(ERR_MSG, LABEL) \
do { \ do { \
fprintf(stderr, ERR_MSG); \ fprintf(stderr, ERR_MSG); \
ok = 0; \ ok = 0; \
goto LABEL; \ goto LABEL; \
} while (0) } while (0)
#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \ #define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
do { \ do { \
fprintf(stderr, ERR_MSG, FORMAT_STR); \ fprintf(stderr, ERR_MSG, FORMAT_STR); \
ok = 0; \ ok = 0; \
goto LABEL; \ goto LABEL; \
} while (0) } while (0)
#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \ #define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
do { \ do { \
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \ fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
ok = 0; \ ok = 0; \
goto LABEL; \ goto LABEL; \
} while (0) } while (0)
static WebPMuxError DisplayInfo(const WebPMux* mux) { static WebPMuxError DisplayInfo(const WebPMux* mux) {
uint32_t flag; uint32_t flag;

View File

@ -19,54 +19,7 @@ extern "C" {
#define ALIGN_MASK (32 - 1) #define ALIGN_MASK (32 - 1)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line. // Filtering
//
// Reason is: the deblocking filter cannot deblock the bottom horizontal edges
// immediately, and needs to wait for first few rows of the next macroblock to
// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending
// on strength).
// With two threads, the vertical positions of the rows being decoded are:
// Decode: [ 0..15][16..31][32..47][48..63][64..79][...
// Deblock: [ 0..11][12..27][28..43][44..59][...
// If we use two threads and two caches of 16 pixels, the sequence would be:
// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][...
// Deblock: [ 0..11][12..27!!][-4..11][12..27][...
// The problem occurs during row [12..15!!] that both the decoding and
// deblocking threads are writing simultaneously.
// With 3 cache lines, one get a safe write pattern:
// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0..
// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28...
// Note that multi-threaded output _without_ deblocking can make use of two
// cache lines of 16 pixels only, since there's no lagging behind. The decoding
// and output process have non-concurrent writing:
// Decode: [ 0..15][16..31][ 0..15][16..31][...
// io->put: [ 0..15][16..31][ 0..15][...
#define MT_CACHE_LINES 3
#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case
// Initialize multi/single-thread worker
static int InitThreadContext(VP8Decoder* const dec) {
dec->cache_id_ = 0;
if (dec->use_threads_) {
WebPWorker* const worker = &dec->worker_;
if (!WebPWorkerReset(worker)) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"thread initialization failed.");
}
worker->data1 = dec;
worker->data2 = (void*)&dec->thread_ctx_.io_;
worker->hook = (WebPWorkerHook)VP8FinishRow;
dec->num_caches_ =
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
} else {
dec->num_caches_ = ST_CACHE_LINES;
}
return 1;
}
//------------------------------------------------------------------------------
// Memory setup
// kFilterExtraRows[] = How many extra lines are needed on the MB boundary // kFilterExtraRows[] = How many extra lines are needed on the MB boundary
// for caching, given a filtering level. // for caching, given a filtering level.
@ -75,124 +28,6 @@ static int InitThreadContext(VP8Decoder* const dec) {
// U/V, so it's 8 samples total (because of the 2x upsampling). // U/V, so it's 8 samples total (because of the 2x upsampling).
static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 }; static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 };
static int AllocateMemory(VP8Decoder* const dec) {
const int num_caches = dec->num_caches_;
const int mb_w = dec->mb_w_;
const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
const size_t top_size = (16 + 8 + 8) * mb_w;
const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
const size_t f_info_size =
(dec->filter_type_ > 0) ?
mb_w * (dec->use_threads_ ? 2 : 1) * sizeof(VP8FInfo)
: 0;
const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
const size_t coeffs_size = 384 * sizeof(*dec->coeffs_);
const size_t cache_height = (16 * num_caches
+ kFilterExtraRows[dec->filter_type_]) * 3 / 2;
const size_t cache_size = top_size * cache_height;
const size_t alpha_size =
dec->alpha_data_ ? (dec->pic_hdr_.width_ * dec->pic_hdr_.height_) : 0;
const size_t needed = intra_pred_mode_size
+ top_size + mb_info_size + f_info_size
+ yuv_size + coeffs_size
+ cache_size + alpha_size + ALIGN_MASK;
uint8_t* mem;
if (needed > dec->mem_size_) {
free(dec->mem_);
dec->mem_size_ = 0;
dec->mem_ = (uint8_t*)malloc(needed);
if (dec->mem_ == NULL) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"no memory during frame initialization.");
}
dec->mem_size_ = needed;
}
mem = (uint8_t*)dec->mem_;
dec->intra_t_ = (uint8_t*)mem;
mem += intra_pred_mode_size;
dec->y_t_ = (uint8_t*)mem;
mem += 16 * mb_w;
dec->u_t_ = (uint8_t*)mem;
mem += 8 * mb_w;
dec->v_t_ = (uint8_t*)mem;
mem += 8 * mb_w;
dec->mb_info_ = ((VP8MB*)mem) + 1;
mem += mb_info_size;
dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL;
mem += f_info_size;
dec->thread_ctx_.id_ = 0;
dec->thread_ctx_.f_info_ = dec->f_info_;
if (dec->use_threads_) {
// secondary cache line. The deblocking process need to make use of the
// filtering strength from previous macroblock row, while the new ones
// are being decoded in parallel. We'll just swap the pointers.
dec->thread_ctx_.f_info_ += mb_w;
}
mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
assert((yuv_size & ALIGN_MASK) == 0);
dec->yuv_b_ = (uint8_t*)mem;
mem += yuv_size;
dec->coeffs_ = (int16_t*)mem;
mem += coeffs_size;
dec->cache_y_stride_ = 16 * mb_w;
dec->cache_uv_stride_ = 8 * mb_w;
{
const int extra_rows = kFilterExtraRows[dec->filter_type_];
const int extra_y = extra_rows * dec->cache_y_stride_;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
dec->cache_y_ = ((uint8_t*)mem) + extra_y;
dec->cache_u_ = dec->cache_y_
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
dec->cache_v_ = dec->cache_u_
+ 8 * num_caches * dec->cache_uv_stride_ + extra_uv;
dec->cache_id_ = 0;
}
mem += cache_size;
// alpha plane
dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
mem += alpha_size;
// note: left-info is initialized once for all.
memset(dec->mb_info_ - 1, 0, mb_info_size);
// initialize top
memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
return 1;
}
static void InitIo(VP8Decoder* const dec, VP8Io* io) {
// prepare 'io'
io->mb_y = 0;
io->y = dec->cache_y_;
io->u = dec->cache_u_;
io->v = dec->cache_v_;
io->y_stride = dec->cache_y_stride_;
io->uv_stride = dec->cache_uv_stride_;
io->fancy_upsampling = 0; // default
io->a = NULL;
}
int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
if (!AllocateMemory(dec)) return 0;
InitIo(dec, io);
VP8DspInit(); // Init critical function pointers and look-up tables.
return 1;
}
//------------------------------------------------------------------------------
// Filtering
static WEBP_INLINE int hev_thresh_from_level(int level, int keyframe) { static WEBP_INLINE int hev_thresh_from_level(int level, int keyframe) {
if (keyframe) { if (keyframe) {
return (level >= 40) ? 2 : (level >= 15) ? 1 : 0; return (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
@ -326,7 +161,7 @@ void VP8StoreBlock(VP8Decoder* const dec) {
#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB #define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB
// Finalize and transmit a complete row. Return false in case of user-abort. // Finalize and transmit a complete row. Return false in case of user-abort.
int VP8FinishRow(VP8Decoder* const dec, VP8Io* io) { static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1; int ok = 1;
const VP8ThreadContext* const ctx = &dec->thread_ctx_; const VP8ThreadContext* const ctx = &dec->thread_ctx_;
const int extra_y_rows = kFilterExtraRows[dec->filter_type_]; const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
@ -419,7 +254,7 @@ int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
// ctx->id_ and ctx->f_info_ are already set // ctx->id_ and ctx->f_info_ are already set
ctx->mb_y_ = dec->mb_y_; ctx->mb_y_ = dec->mb_y_;
ctx->filter_row_ = dec->filter_row_; ctx->filter_row_ = dec->filter_row_;
ok = VP8FinishRow(dec, io); ok = FinishRow(dec, io);
} else { } else {
WebPWorker* const worker = &dec->worker_; WebPWorker* const worker = &dec->worker_;
// Finish previous job *before* updating context // Finish previous job *before* updating context
@ -513,6 +348,174 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
return ok; return ok;
} }
//------------------------------------------------------------------------------
// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line.
//
// Reason is: the deblocking filter cannot deblock the bottom horizontal edges
// immediately, and needs to wait for first few rows of the next macroblock to
// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending
// on strength).
// With two threads, the vertical positions of the rows being decoded are:
// Decode: [ 0..15][16..31][32..47][48..63][64..79][...
// Deblock: [ 0..11][12..27][28..43][44..59][...
// If we use two threads and two caches of 16 pixels, the sequence would be:
// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][...
// Deblock: [ 0..11][12..27!!][-4..11][12..27][...
// The problem occurs during row [12..15!!] that both the decoding and
// deblocking threads are writing simultaneously.
// With 3 cache lines, one get a safe write pattern:
// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0..
// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28...
// Note that multi-threaded output _without_ deblocking can make use of two
// cache lines of 16 pixels only, since there's no lagging behind. The decoding
// and output process have non-concurrent writing:
// Decode: [ 0..15][16..31][ 0..15][16..31][...
// io->put: [ 0..15][16..31][ 0..15][...
#define MT_CACHE_LINES 3
#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case
// Initialize multi/single-thread worker
static int InitThreadContext(VP8Decoder* const dec) {
dec->cache_id_ = 0;
if (dec->use_threads_) {
WebPWorker* const worker = &dec->worker_;
if (!WebPWorkerReset(worker)) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"thread initialization failed.");
}
worker->data1 = dec;
worker->data2 = (void*)&dec->thread_ctx_.io_;
worker->hook = (WebPWorkerHook)FinishRow;
dec->num_caches_ =
(dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
} else {
dec->num_caches_ = ST_CACHE_LINES;
}
return 1;
}
#undef MT_CACHE_LINES
#undef ST_CACHE_LINES
//------------------------------------------------------------------------------
// Memory setup
static int AllocateMemory(VP8Decoder* const dec) {
const int num_caches = dec->num_caches_;
const int mb_w = dec->mb_w_;
const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
const size_t top_size = (16 + 8 + 8) * mb_w;
const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
const size_t f_info_size =
(dec->filter_type_ > 0) ?
mb_w * (dec->use_threads_ ? 2 : 1) * sizeof(VP8FInfo)
: 0;
const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
const size_t coeffs_size = 384 * sizeof(*dec->coeffs_);
const size_t cache_height = (16 * num_caches
+ kFilterExtraRows[dec->filter_type_]) * 3 / 2;
const size_t cache_size = top_size * cache_height;
const size_t alpha_size =
dec->alpha_data_ ? (dec->pic_hdr_.width_ * dec->pic_hdr_.height_) : 0;
const size_t needed = intra_pred_mode_size
+ top_size + mb_info_size + f_info_size
+ yuv_size + coeffs_size
+ cache_size + alpha_size + ALIGN_MASK;
uint8_t* mem;
if (needed > dec->mem_size_) {
free(dec->mem_);
dec->mem_size_ = 0;
dec->mem_ = (uint8_t*)malloc(needed);
if (dec->mem_ == NULL) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"no memory during frame initialization.");
}
dec->mem_size_ = needed;
}
mem = (uint8_t*)dec->mem_;
dec->intra_t_ = (uint8_t*)mem;
mem += intra_pred_mode_size;
dec->y_t_ = (uint8_t*)mem;
mem += 16 * mb_w;
dec->u_t_ = (uint8_t*)mem;
mem += 8 * mb_w;
dec->v_t_ = (uint8_t*)mem;
mem += 8 * mb_w;
dec->mb_info_ = ((VP8MB*)mem) + 1;
mem += mb_info_size;
dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL;
mem += f_info_size;
dec->thread_ctx_.id_ = 0;
dec->thread_ctx_.f_info_ = dec->f_info_;
if (dec->use_threads_) {
// secondary cache line. The deblocking process need to make use of the
// filtering strength from previous macroblock row, while the new ones
// are being decoded in parallel. We'll just swap the pointers.
dec->thread_ctx_.f_info_ += mb_w;
}
mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
assert((yuv_size & ALIGN_MASK) == 0);
dec->yuv_b_ = (uint8_t*)mem;
mem += yuv_size;
dec->coeffs_ = (int16_t*)mem;
mem += coeffs_size;
dec->cache_y_stride_ = 16 * mb_w;
dec->cache_uv_stride_ = 8 * mb_w;
{
const int extra_rows = kFilterExtraRows[dec->filter_type_];
const int extra_y = extra_rows * dec->cache_y_stride_;
const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
dec->cache_y_ = ((uint8_t*)mem) + extra_y;
dec->cache_u_ = dec->cache_y_
+ 16 * num_caches * dec->cache_y_stride_ + extra_uv;
dec->cache_v_ = dec->cache_u_
+ 8 * num_caches * dec->cache_uv_stride_ + extra_uv;
dec->cache_id_ = 0;
}
mem += cache_size;
// alpha plane
dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
mem += alpha_size;
// note: left-info is initialized once for all.
memset(dec->mb_info_ - 1, 0, mb_info_size);
// initialize top
memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
return 1;
}
static void InitIo(VP8Decoder* const dec, VP8Io* io) {
// prepare 'io'
io->mb_y = 0;
io->y = dec->cache_y_;
io->u = dec->cache_u_;
io->v = dec->cache_v_;
io->y_stride = dec->cache_y_stride_;
io->uv_stride = dec->cache_uv_stride_;
io->fancy_upsampling = 0; // default
io->a = NULL;
}
int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
if (!AllocateMemory(dec)) return 0;
InitIo(dec, io);
VP8DspInit(); // Init critical function pointers and look-up tables.
return 1;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Main reconstruction function. // Main reconstruction function.

View File

@ -42,7 +42,7 @@ int VP8InitIoInternal(VP8Io* const io, int version) {
} }
VP8Decoder* VP8New(void) { VP8Decoder* VP8New(void) {
VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder)); VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
if (dec) { if (dec) {
SetOk(dec); SetOk(dec);
WebPWorkerInit(&dec->worker_); WebPWorkerInit(&dec->worker_);

View File

@ -316,14 +316,10 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical(). // Must always be called in pair with VP8EnterCritical().
// Returns false in case of error. // Returns false in case of error.
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io); int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
// Filter the decoded macroblock row (if needed)
int VP8FinishRow(VP8Decoder* const dec, VP8Io* io); // multi threaded call
// Process the last decoded row (filtering + output) // Process the last decoded row (filtering + output)
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io); int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
// Store a block, along with filtering params // Store a block, along with filtering params
void VP8StoreBlock(VP8Decoder* const dec); void VP8StoreBlock(VP8Decoder* const dec);
// Finalize and transmit a complete row. Return false in case of user-abort.
int VP8FinishRow(VP8Decoder* const dec, VP8Io* const io);
// To be called at the start of a new scanline, to initialize predictors. // To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec); void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data. // Decode one macroblock. Returns false if there is not enough data.

View File

@ -59,6 +59,7 @@ VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
// define a dummy function to enable turning off NEON at runtime by setting // define a dummy function to enable turning off NEON at runtime by setting
// VP8DecGetCPUInfo = NULL // VP8DecGetCPUInfo = NULL
static int armCPUInfo(CPUFeature feature) { static int armCPUInfo(CPUFeature feature) {
(void)feature;
return 1; return 1;
} }
VP8CPUInfo VP8GetCPUInfo = armCPUInfo; VP8CPUInfo VP8GetCPUInfo = armCPUInfo;

View File

@ -467,16 +467,16 @@ static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// default C implementations // default C implementations
VP8PredFunc VP8PredLuma4[/* NUM_BMODES */] = { const VP8PredFunc VP8PredLuma4[NUM_BMODES] = {
DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4 DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4
}; };
VP8PredFunc VP8PredLuma16[/*NUM_B_DC_MODES */] = { const VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES] = {
DC16, TM16, VE16, HE16, DC16, TM16, VE16, HE16,
DC16NoTop, DC16NoLeft, DC16NoTopLeft DC16NoTop, DC16NoLeft, DC16NoTopLeft
}; };
VP8PredFunc VP8PredChroma8[/*NUM_B_DC_MODES */] = { const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
DC8uv, TM8uv, VE8uv, HE8uv, DC8uv, TM8uv, VE8uv, HE8uv,
DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
}; };

View File

@ -71,8 +71,6 @@ extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16;
typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst); typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
extern VP8BlockCopy VP8Copy4x4; extern VP8BlockCopy VP8Copy4x4;
extern VP8BlockCopy VP8Copy8x8;
extern VP8BlockCopy VP8Copy16x16;
// Quantization // Quantization
struct VP8Matrix; // forward declaration struct VP8Matrix; // forward declaration
typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16], typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
@ -103,9 +101,9 @@ extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
// *dst is the destination block, with stride BPS. Boundary samples are // *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed. // assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst); typedef void (*VP8PredFunc)(uint8_t* dst);
extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */]; extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */]; extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */]; extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
// simple filter (only for luma) // simple filter (only for luma)
typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh); typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
@ -132,7 +130,7 @@ extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether
extern VP8ChromaFilterFunc VP8HFilter8i; extern VP8ChromaFilterFunc VP8HFilter8i;
// must be called before anything using the above // must be called before anything using the above
extern void VP8DspInit(void); void VP8DspInit(void);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// WebP I/O // WebP I/O

View File

@ -681,8 +681,6 @@ static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) {
} }
static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); } static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
static void Copy8x8(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 8); }
static void Copy16x16(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 16); }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Initialization // Initialization
@ -705,8 +703,6 @@ VP8WMetric VP8TDisto4x4;
VP8WMetric VP8TDisto16x16; VP8WMetric VP8TDisto16x16;
VP8QuantizeBlock VP8EncQuantizeBlock; VP8QuantizeBlock VP8EncQuantizeBlock;
VP8BlockCopy VP8Copy4x4; VP8BlockCopy VP8Copy4x4;
VP8BlockCopy VP8Copy8x8;
VP8BlockCopy VP8Copy16x16;
extern void VP8EncDspInitSSE2(void); extern void VP8EncDspInitSSE2(void);
@ -730,8 +726,6 @@ void VP8EncDspInit(void) {
VP8TDisto16x16 = Disto16x16; VP8TDisto16x16 = Disto16x16;
VP8EncQuantizeBlock = QuantizeBlock; VP8EncQuantizeBlock = QuantizeBlock;
VP8Copy4x4 = Copy4x4; VP8Copy4x4 = Copy4x4;
VP8Copy8x8 = Copy8x8;
VP8Copy16x16 = Copy16x16;
// If defined, use CPUInfo() to overwrite some pointers with faster versions. // If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo) { if (VP8GetCPUInfo) {

View File

@ -35,7 +35,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
const int w = enc->mb_w_; const int w = enc->mb_w_;
const int h = enc->mb_h_; const int h = enc->mb_h_;
const int majority_cnt_3_x_3_grid = 5; const int majority_cnt_3_x_3_grid = 5;
uint8_t* tmp = (uint8_t*)malloc(w * h * sizeof(uint8_t)); uint8_t* const tmp = (uint8_t*)malloc(w * h * sizeof(uint8_t));
if (tmp == NULL) return; if (tmp == NULL) return;
for (y = 1; y < h - 1; ++y) { for (y = 1; y < h - 1; ++y) {

View File

@ -332,7 +332,7 @@ int WebPPictureRescale(WebPPicture* const pic, int width, int height) {
tmp.height = height; tmp.height = height;
if (!WebPPictureAlloc(&tmp)) return 0; if (!WebPPictureAlloc(&tmp)) return 0;
work = malloc(2 * width * sizeof(int32_t)); work = (int32_t*)malloc(2 * width * sizeof(int32_t));
if (work == NULL) { if (work == NULL) {
WebPPictureFree(&tmp); WebPPictureFree(&tmp);
return 0; return 0;
@ -697,12 +697,12 @@ int WebPPictureDistortion(const WebPPicture* const pic1,
for (c = 0; c <= 4; ++c) { for (c = 0; c <= 4; ++c) {
if (type == 1) { if (type == 1) {
const double v = VP8SSIMGet(&stats[c]); const double v = VP8SSIMGet(&stats[c]);
result[c] = (v < 1.) ? -10.0 * log10(1. - v) result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v)
: kMinDistortion_dB; : kMinDistortion_dB);
} else { } else {
const double v = VP8SSIMGetSquaredError(&stats[c]); const double v = VP8SSIMGetSquaredError(&stats[c]);
result[c] = (v > 0.) ? -4.3429448 * log(v / (255 * 255.)) result[c] = (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.))
: kMinDistortion_dB; : kMinDistortion_dB);
} }
// Accumulate forward // Accumulate forward
if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]); if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]);

View File

@ -323,7 +323,7 @@ void VP8IteratorResetCosts(VP8EncIterator* const it);
typedef struct VP8Tokens VP8Tokens; typedef struct VP8Tokens VP8Tokens;
struct VP8Tokens { struct VP8Tokens {
uint16_t tokens_[MAX_NUM_TOKEN]; // bit#15: bit, bits 0..14: slot uint16_t tokens_[MAX_NUM_TOKEN]; // bit#15: bit, bits 0..14: slot
int left_; int left_;
VP8Tokens* next_; VP8Tokens* next_;
}; };
@ -352,7 +352,7 @@ static WEBP_INLINE int VP8AddToken(VP8TBuffer* const b,
return bit; return bit;
} }
#endif #endif // USE_TOKEN_BUFFER
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// VP8Encoder // VP8Encoder
@ -501,7 +501,9 @@ void VP8EncDeleteLayer(VP8Encoder* enc); // reclaim memory
// in filter.c // in filter.c
// SSIM utils // SSIM utils
typedef struct { double w, xm, ym, xxm, xym, yym; } DistoStats; typedef struct {
double w, xm, ym, xxm, xym, yym;
} DistoStats;
void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst); void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst);
void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1, void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1,
const uint8_t* src2, int stride2, const uint8_t* src2, int stride2,

View File

@ -62,15 +62,15 @@ void WebPMuxDelete(WebPMux* const mux) {
// Handy MACRO, makes MuxSet() very symmetric to MuxGet(). // Handy MACRO, makes MuxSet() very symmetric to MuxGet().
#define SWITCH_ID_LIST(ID, LIST) \ #define SWITCH_ID_LIST(ID, LIST) \
if (id == (ID)) { \ if (id == (ID)) { \
err = ChunkAssignDataImageInfo(&chunk, data, size, \ err = ChunkAssignDataImageInfo(&chunk, data, size, \
image_info, \ image_info, \
copy_data, kChunks[(ID)].chunkTag); \ copy_data, kChunks[(ID)].chunkTag); \
if (err == WEBP_MUX_OK) { \ if (err == WEBP_MUX_OK) { \
err = ChunkSetNth(&chunk, (LIST), nth); \ err = ChunkSetNth(&chunk, (LIST), nth); \
} \ } \
return err; \ return err; \
} }
static WebPMuxError MuxSet(WebPMux* const mux, TAG_ID id, uint32_t nth, static WebPMuxError MuxSet(WebPMux* const mux, TAG_ID id, uint32_t nth,
const uint8_t* data, uint32_t size, const uint8_t* data, uint32_t size,
@ -142,7 +142,7 @@ static WebPImageInfo* CreateImageInfo(uint32_t x_offset, uint32_t y_offset,
} }
// Create data for frame/tile given image_info. // Create data for frame/tile given image_info.
static WebPMuxError CreateDataFromImageInfo(WebPImageInfo* image_info, static WebPMuxError CreateDataFromImageInfo(const WebPImageInfo* image_info,
int is_frame, int is_frame,
uint8_t** data, uint32_t* size) { uint8_t** data, uint32_t* size) {
assert(data); assert(data);
@ -154,7 +154,7 @@ static WebPMuxError CreateDataFromImageInfo(WebPImageInfo* image_info,
if (*data == NULL) return WEBP_MUX_MEMORY_ERROR; if (*data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Fill in data according to frame/tile chunk format. // Fill in data according to frame/tile chunk format.
PutLE32(*data, image_info->x_offset_); PutLE32(*data + 0, image_info->x_offset_);
PutLE32(*data + 4, image_info->y_offset_); PutLE32(*data + 4, image_info->y_offset_);
if (is_frame) { if (is_frame) {
@ -168,17 +168,16 @@ static WebPMuxError CreateDataFromImageInfo(WebPImageInfo* image_info,
// Outputs image data given data from a webp file (including RIFF header). // Outputs image data given data from a webp file (including RIFF header).
static WebPMuxError GetImageData(const uint8_t* data, uint32_t size, static WebPMuxError GetImageData(const uint8_t* data, uint32_t size,
WebPData* const image, WebPData* const alpha) { WebPData* const image, WebPData* const alpha) {
if ((size < TAG_SIZE) || (memcmp(data, "RIFF", TAG_SIZE))) { if (size < TAG_SIZE || memcmp(data, "RIFF", TAG_SIZE)) {
// It is NOT webp file data. Return input data as is. // It is NOT webp file data. Return input data as is.
image->bytes_ = data; image->bytes_ = data;
image->size_ = size; image->size_ = size;
return WEBP_MUX_OK; return WEBP_MUX_OK;
} else { } else {
// It is webp file data. Extract image data from it. // It is webp file data. Extract image data from it.
WebPMux* mux;
WebPMuxError err; WebPMuxError err;
WebPMuxState mux_state; WebPMuxState mux_state;
mux = WebPMuxCreate(data, size, 0, &mux_state); WebPMux* const mux = WebPMuxCreate(data, size, 0, &mux_state);
if (mux == NULL || mux_state != WEBP_MUX_STATE_COMPLETE) { if (mux == NULL || mux_state != WEBP_MUX_STATE_COMPLETE) {
return WEBP_MUX_BAD_DATA; return WEBP_MUX_BAD_DATA;
} }
@ -209,7 +208,7 @@ static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux,
TAG_ID id; TAG_ID id;
WebPChunk** chunk_list; WebPChunk** chunk_list;
if ((mux == NULL) || (tag == NULL)) return WEBP_MUX_INVALID_ARGUMENT; if (mux == NULL || tag == NULL) return WEBP_MUX_INVALID_ARGUMENT;
id = ChunkGetIdFromName(tag); id = ChunkGetIdFromName(tag);
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
@ -237,7 +236,7 @@ WebPMuxError WebPMuxSetImage(WebPMux* const mux,
WebPData image; WebPData image;
const int has_alpha = (alpha_data != NULL && alpha_size != 0); const int has_alpha = (alpha_data != NULL && alpha_size != 0);
if ((mux == NULL) || (data == NULL) || (size > MAX_CHUNK_PAYLOAD)) { if (mux == NULL || data == NULL || size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -275,7 +274,7 @@ WebPMuxError WebPMuxSetMetadata(WebPMux* const mux, const uint8_t* data,
uint32_t size, int copy_data) { uint32_t size, int copy_data) {
WebPMuxError err; WebPMuxError err;
if ((mux == NULL) || (data == NULL) || (size > MAX_CHUNK_PAYLOAD)) { if (mux == NULL || data == NULL || size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -291,7 +290,7 @@ WebPMuxError WebPMuxSetColorProfile(WebPMux* const mux, const uint8_t* data,
uint32_t size, int copy_data) { uint32_t size, int copy_data) {
WebPMuxError err; WebPMuxError err;
if ((mux == NULL) || (data == NULL) || (size > MAX_CHUNK_PAYLOAD)) { if (mux == NULL || data == NULL || size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
@ -314,7 +313,7 @@ WebPMuxError WebPMuxSetLoopCount(WebPMux* const mux, uint32_t loop_count) {
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Add the given loop count. // Add the given loop count.
data = (uint8_t *)malloc(kChunks[LOOP_ID].chunkSize); data = (uint8_t*)malloc(kChunks[LOOP_ID].chunkSize);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
PutLE32(data, loop_count); PutLE32(data, loop_count);
@ -364,8 +363,8 @@ static WebPMuxError MuxAddFrameTileInternal(WebPMux* const mux, uint32_t nth,
} }
// Create image_info object. // Create image_info object.
image_info = CreateImageInfo(x_offset, y_offset, duration, image.bytes_, image_info = CreateImageInfo(x_offset, y_offset, duration,
image.size_); image.bytes_, image.size_);
if (image_info == NULL) { if (image_info == NULL) {
MuxImageRelease(&wpi); MuxImageRelease(&wpi);
return WEBP_MUX_MEMORY_ERROR; return WEBP_MUX_MEMORY_ERROR;
@ -492,13 +491,12 @@ static WebPMuxError GetImageCanvasHeightWidth(const WebPMux* const mux,
wpi = mux->images_; wpi = mux->images_;
assert(wpi != NULL); assert(wpi != NULL);
assert(wpi->vp8_ != NULL);
if (wpi->next_) { if (wpi->next_) {
// Aggregate the bounding box for Animation frames & Tiled images. // Aggregate the bounding box for animation frames & tiled images.
for (; wpi != NULL; wpi = wpi->next_) { for (; wpi != NULL; wpi = wpi->next_) {
const WebPImageInfo* image_info; const WebPImageInfo* image_info = wpi->vp8_->image_info_;
assert(wpi->vp8_ != NULL);
image_info = wpi->vp8_->image_info_;
if (image_info != NULL) { if (image_info != NULL) {
const uint32_t max_x_pos = image_info->x_offset_ + image_info->width_; const uint32_t max_x_pos = image_info->x_offset_ + image_info->width_;
@ -509,22 +507,18 @@ static WebPMuxError GetImageCanvasHeightWidth(const WebPMux* const mux,
if (max_y_pos < image_info->y_offset_) { // Overflow occurred. if (max_y_pos < image_info->y_offset_) { // Overflow occurred.
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
} }
if (max_x_pos > max_x) { if (max_x_pos > max_x) max_x = max_x_pos;
max_x = max_x_pos; if (max_y_pos > max_y) max_y = max_y_pos;
}
if (max_y_pos > max_y) {
max_y = max_y_pos;
}
image_area += (image_info->width_ * image_info->height_); image_area += (image_info->width_ * image_info->height_);
} }
} }
*width = max_x; *width = max_x;
*height = max_y; *height = max_y;
// Crude check to validate that there are no image overlaps/holes for Tile // Crude check to validate that there are no image overlaps/holes for tile
// images. Check that the aggregated image area for individual tiles exactly // images. Check that the aggregated image area for individual tiles exactly
// matches the image area of the constructed Canvas. However, the area-match // matches the image area of the constructed canvas. However, the area-match
// is necessary but not sufficient condition. // is necessary but not sufficient condition.
if (!!(flags & TILE_FLAG) && (image_area != (max_x * max_y))) { if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) {
*width = 0; *width = 0;
*height = 0; *height = 0;
return WEBP_MUX_INVALID_ARGUMENT; return WEBP_MUX_INVALID_ARGUMENT;
@ -543,9 +537,9 @@ static WebPMuxError GetImageCanvasHeightWidth(const WebPMux* const mux,
return WEBP_MUX_OK; return WEBP_MUX_OK;
} }
// Following VP8X format followed: // VP8X format:
// Total Size : 12, // Total Size : 12,
// Flags : 4 bytes, // Flags : 4 bytes,
// Width : 4 bytes, // Width : 4 bytes,
// Height : 4 bytes. // Height : 4 bytes.
static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
@ -610,8 +604,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
return err; return err;
} }
WebPMuxError WebPMuxAssemble(WebPMux* const mux, uint8_t** output_data, WebPMuxError WebPMuxAssemble(WebPMux* const mux,
uint32_t* output_size) { uint8_t** output_data, uint32_t* output_size) {
uint32_t size = 0; uint32_t size = 0;
uint8_t* data = NULL; uint8_t* data = NULL;
uint8_t* dst = NULL; uint8_t* dst = NULL;
@ -649,9 +643,9 @@ WebPMuxError WebPMuxAssemble(WebPMux* const mux, uint8_t** output_data,
// Allocate data. // Allocate data.
size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_)
+ ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
+ ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_)
+ RIFF_HEADER_SIZE; + RIFF_HEADER_SIZE;
data = (uint8_t*)malloc(size); data = (uint8_t*)malloc(size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;

View File

@ -143,8 +143,8 @@ TAG_ID ChunkGetIdFromTag(uint32_t tag);
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag); WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
// Fill the chunk with the given data & image_info. // Fill the chunk with the given data & image_info.
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk, const uint8_t* data, WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk,
uint32_t data_size, const uint8_t* data, uint32_t data_size,
WebPImageInfo* image_info, WebPImageInfo* image_info,
int copy_data, uint32_t tag); int copy_data, uint32_t tag);

View File

@ -127,8 +127,8 @@ static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Chunk writer methods. // Chunk writer methods.
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk, const uint8_t* data, WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk,
uint32_t data_size, const uint8_t* data, uint32_t data_size,
WebPImageInfo* image_info, WebPImageInfo* image_info,
int copy_data, uint32_t tag) { int copy_data, uint32_t tag) {
// For internally allocated chunks, always copy data & make it owner of data. // For internally allocated chunks, always copy data & make it owner of data.
@ -231,11 +231,7 @@ uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) {
void MuxImageInit(WebPMuxImage* const wpi) { void MuxImageInit(WebPMuxImage* const wpi) {
assert(wpi); assert(wpi);
wpi->header_ = NULL; memset(wpi, 0, sizeof(*wpi));
wpi->alpha_ = NULL;
wpi->vp8_ = NULL;
wpi->is_partial_ = 0;
wpi->next_ = NULL;
} }
WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) { WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
@ -260,8 +256,8 @@ int MuxImageCount(WebPMuxImage* const wpi_list, TAG_ID id) {
WebPChunk** const wpi_chunk_ptr = MuxImageGetListFromId(current, id); WebPChunk** const wpi_chunk_ptr = MuxImageGetListFromId(current, id);
assert(wpi_chunk_ptr != NULL); assert(wpi_chunk_ptr != NULL);
if ((*wpi_chunk_ptr != NULL) && if (*wpi_chunk_ptr != NULL &&
((*wpi_chunk_ptr)->tag_ == kChunks[id].chunkTag)) { (*wpi_chunk_ptr)->tag_ == kChunks[id].chunkTag) {
++count; ++count;
} }
} }
@ -374,7 +370,7 @@ WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
assert(wpi_list); assert(wpi_list);
assert(wpi); assert(wpi);
if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id, if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id,
(WebPMuxImage*** const)&wpi_list)) { (WebPMuxImage***)&wpi_list)) {
return WEBP_MUX_NOT_FOUND; return WEBP_MUX_NOT_FOUND;
} }
*wpi = (WebPMuxImage*)*wpi_list; *wpi = (WebPMuxImage*)*wpi_list;
@ -438,12 +434,9 @@ WebPChunk** GetChunkListFromId(const WebPMux* mux, TAG_ID id) {
} }
WebPMuxError ValidateForImage(const WebPMux* const mux) { WebPMuxError ValidateForImage(const WebPMux* const mux) {
int num_vp8; const int num_vp8 = MuxImageCount(mux->images_, IMAGE_ID);
int num_frames; const int num_frames = MuxImageCount(mux->images_, FRAME_ID);
int num_tiles; const int num_tiles = MuxImageCount(mux->images_, TILE_ID);
num_vp8 = MuxImageCount(mux->images_, IMAGE_ID);
num_frames = MuxImageCount(mux->images_, FRAME_ID);
num_tiles = MuxImageCount(mux->images_, TILE_ID);
if (num_vp8 == 0) { if (num_vp8 == 0) {
// No images in mux. // No images in mux.

View File

@ -226,8 +226,7 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
} }
WebPMuxError WebPMuxGetImage(const WebPMux* const mux, WebPMuxError WebPMuxGetImage(const WebPMux* const mux,
WebPData* const image, WebPData* const image, WebPData* const alpha) {
WebPData* const alpha) {
WebPMuxError err; WebPMuxError err;
WebPMuxImage* wpi = NULL; WebPMuxImage* wpi = NULL;
@ -324,7 +323,7 @@ static WebPMuxError MuxGetFrameTileInternal(const WebPMux* const mux,
frame_tile_size = wpi->header_->payload_size_; frame_tile_size = wpi->header_->payload_size_;
if (frame_tile_size < kChunks[id].chunkSize) return WEBP_MUX_BAD_DATA; if (frame_tile_size < kChunks[id].chunkSize) return WEBP_MUX_BAD_DATA;
*x_offset = GetLE32(frame_tile_data); *x_offset = GetLE32(frame_tile_data + 0);
*y_offset = GetLE32(frame_tile_data + 4); *y_offset = GetLE32(frame_tile_data + 4);
if (is_frame) *duration = GetLE32(frame_tile_data + 16); if (is_frame) *duration = GetLE32(frame_tile_data + 16);
@ -370,7 +369,7 @@ static int CountChunks(WebPChunk* const chunk_list, uint32_t tag) {
int count = 0; int count = 0;
WebPChunk* current; WebPChunk* current;
for (current = chunk_list; current != NULL; current = current->next_) { for (current = chunk_list; current != NULL; current = current->next_) {
if ((tag == NIL_TAG) || (current->tag_ == tag)) { if (tag == NIL_TAG || current->tag_ == tag) {
count++; // Count chunks whose tags match. count++; // Count chunks whose tags match.
} }
} }

View File

@ -210,17 +210,17 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = { const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
NULL, // WEBP_FILTER_NONE NULL, // WEBP_FILTER_NONE
HorizontalFilter, // WEBP_FILTER_HORIZONTAL HorizontalFilter, // WEBP_FILTER_HORIZONTAL
VerticalFilter, // WEBP_FILTER_VERTICAL VerticalFilter, // WEBP_FILTER_VERTICAL
GradientFilter // WEBP_FILTER_GRADIENT GradientFilter // WEBP_FILTER_GRADIENT
}; };
const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = { const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
NULL, // WEBP_FILTER_NONE NULL, // WEBP_FILTER_NONE
HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
VerticalUnfilter, // WEBP_FILTER_VERTICAL VerticalUnfilter, // WEBP_FILTER_VERTICAL
GradientUnfilter // WEBP_FILTER_GRADIENT GradientUnfilter // WEBP_FILTER_GRADIENT
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -115,7 +115,8 @@ WEBP_EXTERN(void) WebPMuxDelete(WebPMux* const mux);
// A pointer to the mux object created from given data - on success. // A pointer to the mux object created from given data - on success.
// NULL - In case of invalid data or memory error. // NULL - In case of invalid data or memory error.
WEBP_EXTERN(WebPMux*) WebPMuxCreate(const uint8_t* data, uint32_t size, WEBP_EXTERN(WebPMux*) WebPMuxCreate(const uint8_t* data, uint32_t size,
int copy_data, WebPMuxState* mux_state); int copy_data,
WebPMuxState* const mux_state);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Single Image. // Single Image.