diff --git a/examples/cwebp.c b/examples/cwebp.c index e2a8a539..df14b83f 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -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) { diff --git a/examples/webpmux.c b/examples/webpmux.c index dd8630a6..7357fd54 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -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; diff --git a/src/dec/frame.c b/src/dec/frame.c index 264145f4..1ad45f06 100644 --- a/src/dec/frame.c +++ b/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. diff --git a/src/dec/vp8.c b/src/dec/vp8.c index e59d4115..4e9be0ea 100644 --- a/src/dec/vp8.c +++ b/src/dec/vp8.c @@ -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_); diff --git a/src/dec/vp8i.h b/src/dec/vp8i.h index 5201b219..ba2b84fd 100644 --- a/src/dec/vp8i.h +++ b/src/dec/vp8i.h @@ -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. diff --git a/src/dsp/cpu.c b/src/dsp/cpu.c index 5a5d1559..05bd6424 100644 --- a/src/dsp/cpu.c +++ b/src/dsp/cpu.c @@ -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; diff --git a/src/dsp/dec.c b/src/dsp/dec.c index 251a4b52..4b4ce5fd 100644 --- a/src/dsp/dec.c +++ b/src/dsp/dec.c @@ -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 }; diff --git a/src/dsp/dsp.h b/src/dsp/dsp.h index 3c980180..63514c7a 100644 --- a/src/dsp/dsp.h +++ b/src/dsp/dsp.h @@ -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 diff --git a/src/dsp/enc.c b/src/dsp/enc.c index 09081f45..f07aa691 100644 --- a/src/dsp/enc.c +++ b/src/dsp/enc.c @@ -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) { diff --git a/src/enc/analysis.c b/src/enc/analysis.c index 4d7ce8ae..9bb6e22e 100644 --- a/src/enc/analysis.c +++ b/src/enc/analysis.c @@ -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) { diff --git a/src/enc/picture.c b/src/enc/picture.c index 04d89592..10b896e2 100644 --- a/src/enc/picture.c +++ b/src/enc/picture.c @@ -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]); diff --git a/src/enc/vp8enci.h b/src/enc/vp8enci.h index 326f7b19..f5e68877 100644 --- a/src/enc/vp8enci.h +++ b/src/enc/vp8enci.h @@ -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, diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index 3fd6c464..4befc292 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -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; diff --git a/src/mux/muxi.h b/src/mux/muxi.h index 9118b36c..0891132d 100644 --- a/src/mux/muxi.h +++ b/src/mux/muxi.h @@ -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); diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c index ec13e934..f8a04cb6 100644 --- a/src/mux/muxinternal.c +++ b/src/mux/muxinternal.c @@ -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. diff --git a/src/mux/muxread.c b/src/mux/muxread.c index e920a8c7..b231f878 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -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. } } diff --git a/src/utils/filters.c b/src/utils/filters.c index 02302880..4844cc7a 100644 --- a/src/utils/filters.c +++ b/src/utils/filters.c @@ -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 }; //------------------------------------------------------------------------------ diff --git a/src/webp/mux.h b/src/webp/mux.h index 7d2b1a11..e74c1479 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -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.