mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 05:38:22 +01:00
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:
parent
b9600308e8
commit
a0b2736d79
@ -443,7 +443,7 @@ static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
|
||||
typedef enum {
|
||||
PNG = 0,
|
||||
JPEG,
|
||||
UNSUPPORTED,
|
||||
UNSUPPORTED
|
||||
} InputFileFormat;
|
||||
|
||||
static InputFileFormat GetImageType(FILE* in_file) {
|
||||
|
@ -140,38 +140,38 @@ static void WebPDataFree(WebPData* const webpdata) {
|
||||
memset(webpdata, 0, sizeof(*webpdata));
|
||||
}
|
||||
|
||||
#define RETURN_IF_ERROR(ERR_MSG) \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
return err; \
|
||||
}
|
||||
#define RETURN_IF_ERROR(ERR_MSG) \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
return err; \
|
||||
}
|
||||
|
||||
#define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR); \
|
||||
return err; \
|
||||
}
|
||||
#define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \
|
||||
if (err != WEBP_MUX_OK) { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR); \
|
||||
return err; \
|
||||
}
|
||||
|
||||
#define ERROR_GOTO1(ERR_MSG, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
#define ERROR_GOTO1(ERR_MSG, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
|
||||
#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
|
||||
#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
|
||||
do { \
|
||||
fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
|
||||
ok = 0; \
|
||||
goto LABEL; \
|
||||
} while (0)
|
||||
|
||||
static WebPMuxError DisplayInfo(const WebPMux* mux) {
|
||||
uint32_t flag;
|
||||
|
339
src/dec/frame.c
339
src/dec/frame.c
@ -19,54 +19,7 @@ extern "C" {
|
||||
#define ALIGN_MASK (32 - 1)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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)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
|
||||
// Filtering
|
||||
|
||||
// kFilterExtraRows[] = How many extra lines are needed on the MB boundary
|
||||
// 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).
|
||||
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) {
|
||||
if (keyframe) {
|
||||
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
|
||||
|
||||
// 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;
|
||||
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
|
||||
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->mb_y_ = dec->mb_y_;
|
||||
ctx->filter_row_ = dec->filter_row_;
|
||||
ok = VP8FinishRow(dec, io);
|
||||
ok = FinishRow(dec, io);
|
||||
} else {
|
||||
WebPWorker* const worker = &dec->worker_;
|
||||
// Finish previous job *before* updating context
|
||||
@ -513,6 +348,174 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
|
||||
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.
|
||||
|
||||
|
@ -42,7 +42,7 @@ int VP8InitIoInternal(VP8Io* const io, int version) {
|
||||
}
|
||||
|
||||
VP8Decoder* VP8New(void) {
|
||||
VP8Decoder* dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
|
||||
VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(VP8Decoder));
|
||||
if (dec) {
|
||||
SetOk(dec);
|
||||
WebPWorkerInit(&dec->worker_);
|
||||
|
@ -316,14 +316,10 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
|
||||
// Must always be called in pair with VP8EnterCritical().
|
||||
// Returns false in case of error.
|
||||
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)
|
||||
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
|
||||
// Store a block, along with filtering params
|
||||
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.
|
||||
void VP8InitScanline(VP8Decoder* const dec);
|
||||
// Decode one macroblock. Returns false if there is not enough data.
|
||||
|
@ -59,6 +59,7 @@ VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
|
||||
// define a dummy function to enable turning off NEON at runtime by setting
|
||||
// VP8DecGetCPUInfo = NULL
|
||||
static int armCPUInfo(CPUFeature feature) {
|
||||
(void)feature;
|
||||
return 1;
|
||||
}
|
||||
VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
|
||||
|
@ -467,16 +467,16 @@ static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
|
||||
//------------------------------------------------------------------------------
|
||||
// default C implementations
|
||||
|
||||
VP8PredFunc VP8PredLuma4[/* NUM_BMODES */] = {
|
||||
const VP8PredFunc VP8PredLuma4[NUM_BMODES] = {
|
||||
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,
|
||||
DC16NoTop, DC16NoLeft, DC16NoTopLeft
|
||||
};
|
||||
|
||||
VP8PredFunc VP8PredChroma8[/*NUM_B_DC_MODES */] = {
|
||||
const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
|
||||
DC8uv, TM8uv, VE8uv, HE8uv,
|
||||
DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
|
||||
};
|
||||
|
@ -71,8 +71,6 @@ extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16;
|
||||
|
||||
typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
|
||||
extern VP8BlockCopy VP8Copy4x4;
|
||||
extern VP8BlockCopy VP8Copy8x8;
|
||||
extern VP8BlockCopy VP8Copy16x16;
|
||||
// Quantization
|
||||
struct VP8Matrix; // forward declaration
|
||||
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
|
||||
// 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 const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
|
||||
extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
|
||||
extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
|
||||
|
||||
// simple filter (only for luma)
|
||||
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;
|
||||
|
||||
// must be called before anything using the above
|
||||
extern void VP8DspInit(void);
|
||||
void VP8DspInit(void);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// WebP I/O
|
||||
|
@ -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 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
|
||||
@ -705,8 +703,6 @@ VP8WMetric VP8TDisto4x4;
|
||||
VP8WMetric VP8TDisto16x16;
|
||||
VP8QuantizeBlock VP8EncQuantizeBlock;
|
||||
VP8BlockCopy VP8Copy4x4;
|
||||
VP8BlockCopy VP8Copy8x8;
|
||||
VP8BlockCopy VP8Copy16x16;
|
||||
|
||||
extern void VP8EncDspInitSSE2(void);
|
||||
|
||||
@ -730,8 +726,6 @@ void VP8EncDspInit(void) {
|
||||
VP8TDisto16x16 = Disto16x16;
|
||||
VP8EncQuantizeBlock = QuantizeBlock;
|
||||
VP8Copy4x4 = Copy4x4;
|
||||
VP8Copy8x8 = Copy8x8;
|
||||
VP8Copy16x16 = Copy16x16;
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo) {
|
||||
|
@ -35,7 +35,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
|
||||
const int w = enc->mb_w_;
|
||||
const int h = enc->mb_h_;
|
||||
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;
|
||||
for (y = 1; y < h - 1; ++y) {
|
||||
|
@ -332,7 +332,7 @@ int WebPPictureRescale(WebPPicture* const pic, int width, int height) {
|
||||
tmp.height = height;
|
||||
if (!WebPPictureAlloc(&tmp)) return 0;
|
||||
|
||||
work = malloc(2 * width * sizeof(int32_t));
|
||||
work = (int32_t*)malloc(2 * width * sizeof(int32_t));
|
||||
if (work == NULL) {
|
||||
WebPPictureFree(&tmp);
|
||||
return 0;
|
||||
@ -697,12 +697,12 @@ int WebPPictureDistortion(const WebPPicture* const pic1,
|
||||
for (c = 0; c <= 4; ++c) {
|
||||
if (type == 1) {
|
||||
const double v = VP8SSIMGet(&stats[c]);
|
||||
result[c] = (v < 1.) ? -10.0 * log10(1. - v)
|
||||
: kMinDistortion_dB;
|
||||
result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v)
|
||||
: kMinDistortion_dB);
|
||||
} else {
|
||||
const double v = VP8SSIMGetSquaredError(&stats[c]);
|
||||
result[c] = (v > 0.) ? -4.3429448 * log(v / (255 * 255.))
|
||||
: kMinDistortion_dB;
|
||||
result[c] = (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.))
|
||||
: kMinDistortion_dB);
|
||||
}
|
||||
// Accumulate forward
|
||||
if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]);
|
||||
|
@ -323,7 +323,7 @@ void VP8IteratorResetCosts(VP8EncIterator* const it);
|
||||
|
||||
typedef struct VP8Tokens 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_;
|
||||
VP8Tokens* next_;
|
||||
};
|
||||
@ -346,13 +346,13 @@ int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw,
|
||||
static WEBP_INLINE int VP8AddToken(VP8TBuffer* const b,
|
||||
int bit, int proba_idx) {
|
||||
if (b->left_ > 0 || VP8TBufferNewPage(b)) {
|
||||
const int slot = --b->left_;
|
||||
const int slot = --b->left_;
|
||||
b->tokens_[slot] = (bit << 15) | proba_idx;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // USE_TOKEN_BUFFER
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VP8Encoder
|
||||
@ -501,7 +501,9 @@ void VP8EncDeleteLayer(VP8Encoder* enc); // reclaim memory
|
||||
// in filter.c
|
||||
|
||||
// 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 VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1,
|
||||
const uint8_t* src2, int stride2,
|
||||
|
@ -62,15 +62,15 @@ void WebPMuxDelete(WebPMux* const mux) {
|
||||
|
||||
// Handy MACRO, makes MuxSet() very symmetric to MuxGet().
|
||||
#define SWITCH_ID_LIST(ID, LIST) \
|
||||
if (id == (ID)) { \
|
||||
err = ChunkAssignDataImageInfo(&chunk, data, size, \
|
||||
image_info, \
|
||||
copy_data, kChunks[(ID)].chunkTag); \
|
||||
if (err == WEBP_MUX_OK) { \
|
||||
err = ChunkSetNth(&chunk, (LIST), nth); \
|
||||
} \
|
||||
return err; \
|
||||
}
|
||||
if (id == (ID)) { \
|
||||
err = ChunkAssignDataImageInfo(&chunk, data, size, \
|
||||
image_info, \
|
||||
copy_data, kChunks[(ID)].chunkTag); \
|
||||
if (err == WEBP_MUX_OK) { \
|
||||
err = ChunkSetNth(&chunk, (LIST), nth); \
|
||||
} \
|
||||
return err; \
|
||||
}
|
||||
|
||||
static WebPMuxError MuxSet(WebPMux* const mux, TAG_ID id, uint32_t nth,
|
||||
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.
|
||||
static WebPMuxError CreateDataFromImageInfo(WebPImageInfo* image_info,
|
||||
static WebPMuxError CreateDataFromImageInfo(const WebPImageInfo* image_info,
|
||||
int is_frame,
|
||||
uint8_t** data, uint32_t* size) {
|
||||
assert(data);
|
||||
@ -154,7 +154,7 @@ static WebPMuxError CreateDataFromImageInfo(WebPImageInfo* image_info,
|
||||
if (*data == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
|
||||
// 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_);
|
||||
|
||||
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).
|
||||
static WebPMuxError GetImageData(const uint8_t* data, uint32_t size,
|
||||
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.
|
||||
image->bytes_ = data;
|
||||
image->size_ = size;
|
||||
return WEBP_MUX_OK;
|
||||
} else {
|
||||
// It is webp file data. Extract image data from it.
|
||||
WebPMux* mux;
|
||||
WebPMuxError err;
|
||||
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) {
|
||||
return WEBP_MUX_BAD_DATA;
|
||||
}
|
||||
@ -209,7 +208,7 @@ static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux,
|
||||
TAG_ID id;
|
||||
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);
|
||||
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
|
||||
@ -237,7 +236,7 @@ WebPMuxError WebPMuxSetImage(WebPMux* const mux,
|
||||
WebPData image;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -275,7 +274,7 @@ WebPMuxError WebPMuxSetMetadata(WebPMux* const mux, const uint8_t* data,
|
||||
uint32_t size, int copy_data) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -291,7 +290,7 @@ WebPMuxError WebPMuxSetColorProfile(WebPMux* const mux, const uint8_t* data,
|
||||
uint32_t size, int copy_data) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
// 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;
|
||||
|
||||
PutLE32(data, loop_count);
|
||||
@ -364,8 +363,8 @@ static WebPMuxError MuxAddFrameTileInternal(WebPMux* const mux, uint32_t nth,
|
||||
}
|
||||
|
||||
// Create image_info object.
|
||||
image_info = CreateImageInfo(x_offset, y_offset, duration, image.bytes_,
|
||||
image.size_);
|
||||
image_info = CreateImageInfo(x_offset, y_offset, duration,
|
||||
image.bytes_, image.size_);
|
||||
if (image_info == NULL) {
|
||||
MuxImageRelease(&wpi);
|
||||
return WEBP_MUX_MEMORY_ERROR;
|
||||
@ -492,13 +491,12 @@ static WebPMuxError GetImageCanvasHeightWidth(const WebPMux* const mux,
|
||||
|
||||
wpi = mux->images_;
|
||||
assert(wpi != NULL);
|
||||
assert(wpi->vp8_ != NULL);
|
||||
|
||||
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_) {
|
||||
const WebPImageInfo* image_info;
|
||||
assert(wpi->vp8_ != NULL);
|
||||
image_info = wpi->vp8_->image_info_;
|
||||
const WebPImageInfo* image_info = wpi->vp8_->image_info_;
|
||||
|
||||
if (image_info != NULL) {
|
||||
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.
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
}
|
||||
if (max_x_pos > max_x) {
|
||||
max_x = max_x_pos;
|
||||
}
|
||||
if (max_y_pos > max_y) {
|
||||
max_y = max_y_pos;
|
||||
}
|
||||
if (max_x_pos > max_x) max_x = max_x_pos;
|
||||
if (max_y_pos > max_y) max_y = max_y_pos;
|
||||
image_area += (image_info->width_ * image_info->height_);
|
||||
}
|
||||
}
|
||||
*width = max_x;
|
||||
*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
|
||||
// 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.
|
||||
if (!!(flags & TILE_FLAG) && (image_area != (max_x * max_y))) {
|
||||
if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) {
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
return WEBP_MUX_INVALID_ARGUMENT;
|
||||
@ -543,9 +537,9 @@ static WebPMuxError GetImageCanvasHeightWidth(const WebPMux* const mux,
|
||||
return WEBP_MUX_OK;
|
||||
}
|
||||
|
||||
// Following VP8X format followed:
|
||||
// VP8X format:
|
||||
// Total Size : 12,
|
||||
// Flags : 4 bytes,
|
||||
// Flags : 4 bytes,
|
||||
// Width : 4 bytes,
|
||||
// Height : 4 bytes.
|
||||
static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
||||
@ -610,8 +604,8 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
||||
return err;
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxAssemble(WebPMux* const mux, uint8_t** output_data,
|
||||
uint32_t* output_size) {
|
||||
WebPMuxError WebPMuxAssemble(WebPMux* const mux,
|
||||
uint8_t** output_data, uint32_t* output_size) {
|
||||
uint32_t size = 0;
|
||||
uint8_t* data = NULL;
|
||||
uint8_t* dst = NULL;
|
||||
@ -649,9 +643,9 @@ WebPMuxError WebPMuxAssemble(WebPMux* const mux, uint8_t** output_data,
|
||||
|
||||
// Allocate data.
|
||||
size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_)
|
||||
+ ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
|
||||
+ ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_)
|
||||
+ RIFF_HEADER_SIZE;
|
||||
+ ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
|
||||
+ ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_)
|
||||
+ RIFF_HEADER_SIZE;
|
||||
|
||||
data = (uint8_t*)malloc(size);
|
||||
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
|
||||
|
@ -143,8 +143,8 @@ TAG_ID ChunkGetIdFromTag(uint32_t tag);
|
||||
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
|
||||
|
||||
// Fill the chunk with the given data & image_info.
|
||||
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk, const uint8_t* data,
|
||||
uint32_t data_size,
|
||||
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk,
|
||||
const uint8_t* data, uint32_t data_size,
|
||||
WebPImageInfo* image_info,
|
||||
int copy_data, uint32_t tag);
|
||||
|
||||
|
@ -127,8 +127,8 @@ static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
|
||||
//------------------------------------------------------------------------------
|
||||
// Chunk writer methods.
|
||||
|
||||
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk, const uint8_t* data,
|
||||
uint32_t data_size,
|
||||
WebPMuxError ChunkAssignDataImageInfo(WebPChunk* chunk,
|
||||
const uint8_t* data, uint32_t data_size,
|
||||
WebPImageInfo* image_info,
|
||||
int copy_data, uint32_t tag) {
|
||||
// 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) {
|
||||
assert(wpi);
|
||||
wpi->header_ = NULL;
|
||||
wpi->alpha_ = NULL;
|
||||
wpi->vp8_ = NULL;
|
||||
wpi->is_partial_ = 0;
|
||||
wpi->next_ = NULL;
|
||||
memset(wpi, 0, sizeof(*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);
|
||||
assert(wpi_chunk_ptr != NULL);
|
||||
|
||||
if ((*wpi_chunk_ptr != NULL) &&
|
||||
((*wpi_chunk_ptr)->tag_ == kChunks[id].chunkTag)) {
|
||||
if (*wpi_chunk_ptr != NULL &&
|
||||
(*wpi_chunk_ptr)->tag_ == kChunks[id].chunkTag) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
@ -374,7 +370,7 @@ WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
|
||||
assert(wpi_list);
|
||||
assert(wpi);
|
||||
if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id,
|
||||
(WebPMuxImage*** const)&wpi_list)) {
|
||||
(WebPMuxImage***)&wpi_list)) {
|
||||
return WEBP_MUX_NOT_FOUND;
|
||||
}
|
||||
*wpi = (WebPMuxImage*)*wpi_list;
|
||||
@ -438,12 +434,9 @@ WebPChunk** GetChunkListFromId(const WebPMux* mux, TAG_ID id) {
|
||||
}
|
||||
|
||||
WebPMuxError ValidateForImage(const WebPMux* const mux) {
|
||||
int num_vp8;
|
||||
int num_frames;
|
||||
int num_tiles;
|
||||
num_vp8 = MuxImageCount(mux->images_, IMAGE_ID);
|
||||
num_frames = MuxImageCount(mux->images_, FRAME_ID);
|
||||
num_tiles = MuxImageCount(mux->images_, TILE_ID);
|
||||
const int num_vp8 = MuxImageCount(mux->images_, IMAGE_ID);
|
||||
const int num_frames = MuxImageCount(mux->images_, FRAME_ID);
|
||||
const int num_tiles = MuxImageCount(mux->images_, TILE_ID);
|
||||
|
||||
if (num_vp8 == 0) {
|
||||
// No images in mux.
|
||||
|
@ -226,8 +226,7 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* const mux, uint32_t* flags) {
|
||||
}
|
||||
|
||||
WebPMuxError WebPMuxGetImage(const WebPMux* const mux,
|
||||
WebPData* const image,
|
||||
WebPData* const alpha) {
|
||||
WebPData* const image, WebPData* const alpha) {
|
||||
WebPMuxError err;
|
||||
WebPMuxImage* wpi = NULL;
|
||||
|
||||
@ -324,7 +323,7 @@ static WebPMuxError MuxGetFrameTileInternal(const WebPMux* const mux,
|
||||
frame_tile_size = wpi->header_->payload_size_;
|
||||
|
||||
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);
|
||||
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;
|
||||
WebPChunk* current;
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
@ -210,17 +210,17 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
|
||||
NULL, // WEBP_FILTER_NONE
|
||||
HorizontalFilter, // WEBP_FILTER_HORIZONTAL
|
||||
VerticalFilter, // WEBP_FILTER_VERTICAL
|
||||
GradientFilter // WEBP_FILTER_GRADIENT
|
||||
NULL, // WEBP_FILTER_NONE
|
||||
HorizontalFilter, // WEBP_FILTER_HORIZONTAL
|
||||
VerticalFilter, // WEBP_FILTER_VERTICAL
|
||||
GradientFilter // WEBP_FILTER_GRADIENT
|
||||
};
|
||||
|
||||
const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
|
||||
NULL, // WEBP_FILTER_NONE
|
||||
HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
|
||||
VerticalUnfilter, // WEBP_FILTER_VERTICAL
|
||||
GradientUnfilter // WEBP_FILTER_GRADIENT
|
||||
NULL, // WEBP_FILTER_NONE
|
||||
HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
|
||||
VerticalUnfilter, // WEBP_FILTER_VERTICAL
|
||||
GradientUnfilter // WEBP_FILTER_GRADIENT
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -115,7 +115,8 @@ WEBP_EXTERN(void) WebPMuxDelete(WebPMux* const mux);
|
||||
// A pointer to the mux object created from given data - on success.
|
||||
// NULL - In case of invalid data or memory error.
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user